vmtk-1.0.1/0000775000175000017500000000000011757446472011147 5ustar lucalucavmtk-1.0.1/vtkVmtk/0000775000175000017500000000000011757446472012615 5ustar lucalucavmtk-1.0.1/vtkVmtk/Misc/0000775000175000017500000000000011757446472013510 5ustar lucalucavmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataSizingFunction.cxx0000664000175000017500000000734411757446472022302 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataSizingFunction.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataSizingFunction.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkTriangle.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataSizingFunction, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkPolyDataSizingFunction); vtkvmtkPolyDataSizingFunction::vtkvmtkPolyDataSizingFunction() { this->SizingFunctionArrayName = NULL; this->ScaleFactor = 1.0; } vtkvmtkPolyDataSizingFunction::~vtkvmtkPolyDataSizingFunction() { if (this->SizingFunctionArrayName) { delete[] this->SizingFunctionArrayName; this->SizingFunctionArrayName = NULL; } } int vtkvmtkPolyDataSizingFunction::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 (input->GetNumberOfPoints() < 1) { return 1; } if (!this->SizingFunctionArrayName) { vtkErrorMacro(<<"No SizingFunctionArrayName specified"); return 1; } input->BuildCells(); input->BuildLinks(); int numberOfPoints = input->GetNumberOfPoints(); vtkDoubleArray* sizingFunctionArray = vtkDoubleArray::New(); sizingFunctionArray->SetName(this->SizingFunctionArrayName); sizingFunctionArray->SetNumberOfTuples(numberOfPoints); sizingFunctionArray->FillComponent(0,0.0); vtkIdList* pointCells = vtkIdList::New(); int i, j; for (i=0; iGetPointCells(i,pointCells); int numberOfPointCells = pointCells->GetNumberOfIds(); double averageArea = 0.0; if (numberOfPointCells == 0) { continue; } for (j=0; jGetCell(pointCells->GetId(j))); if (!triangle) { vtkErrorMacro(<<"Cell not triangle: skipping cell for sizing function computation"); } double point0[3], point1[3], point2[3]; triangle->GetPoints()->GetPoint(0,point0); triangle->GetPoints()->GetPoint(1,point1); triangle->GetPoints()->GetPoint(2,point2); averageArea += vtkTriangle::TriangleArea(point0,point1,point2); } averageArea /= numberOfPointCells; double sizingFunction = sqrt(averageArea) * this->ScaleFactor; sizingFunctionArray->SetValue(i,sizingFunction); } output->DeepCopy(input); output->GetPointData()->AddArray(sizingFunctionArray); sizingFunctionArray->Delete(); pointCells->Delete(); return 1; } void vtkvmtkPolyDataSizingFunction::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkBoundaryLayerGenerator.cxx0000664000175000017500000003621011757446472022314 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryLayerGenerator.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkPoints.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkBoundaryLayerGenerator, "$Revision: 1.7 $"); 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->IncludeSurfaceCells = 0; this->NegateWarpVectors = 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; } } 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 (!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); } vtkPoints* outputPoints = vtkPoints::New(); vtkPoints* warpedPoints = vtkPoints::New(); vtkCellArray* boundaryLayerCellArray = vtkCellArray::New(); vtkIdList* boundaryLayerCellTypes = vtkIdList::New(); 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; } outputPoints->SetNumberOfPoints(numberOfInputPoints + numberOfLayerPoints * this->NumberOfSubLayers); double point[3]; int i; for (i=0; iGetPoint(i,point); outputPoints->SetPoint(i,point); } vtkIdType npts, *pts; vtkIdType *surfacePts; if (this->IncludeSurfaceCells) { for (i=0; iGetCellPoints(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); delete[] surfacePts; } } if (this->InnerSurface) { this->InnerSurface->Delete(); this->InnerSurface = NULL; } this->InnerSurface = vtkUnstructuredGrid::New(); this->InnerSurface->DeepCopy(input); vtkPoints* innerSurfacePoints = vtkPoints::New(); this->WarpPoints(inputPoints,innerSurfacePoints,this->NumberOfSubLayers-1,warpQuadratic); this->InnerSurface->GetPoints()->DeepCopy(innerSurfacePoints); int k; for (k=0; kNumberOfSubLayers; k++) { warpedPoints->Initialize(); this->WarpPoints(inputPoints,warpedPoints,k,warpQuadratic); for (i=0; iGetPoint(i,point); outputPoints->SetPoint(i + numberOfInputPoints + k*numberOfLayerPoints,point); } vtkIdType prismNPts, *prismPts; for (i=0; iGetCellPoints(i,npts,pts); cellType = input->GetCellType(i); if (cellType == VTK_TRIANGLE || cellType == VTK_QUAD) { prismNPts = npts * 2; prismPts = new vtkIdType[prismNPts]; int j; for (j=0; jInsertNextCell(prismNPts,prismPts); delete[] prismPts; if (cellType == VTK_TRIANGLE) { boundaryLayerCellTypes->InsertNextId(VTK_WEDGE); } else if (cellType == VTK_QUAD) { boundaryLayerCellTypes->InsertNextId(VTK_HEXAHEDRON); } } else if (cellType == VTK_QUADRATIC_TRIANGLE) { prismNPts = npts * 3 - 3; // prismNPts = npts * 3; prismPts = new vtkIdType[prismNPts]; 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; // TODO: this creates a 18-noded wedge, which is not supported by VTK, but it works as a 15-node (the last 3 points are ignored). Better solutions? Could put it in as a vtkGenericCell, but harder to identify it afterwards // prismPts[15] = pts[3] + k*numberOfLayerPoints + numberOfLayerPoints/2; // prismPts[16] = pts[4] + k*numberOfLayerPoints + numberOfLayerPoints/2; // prismPts[17] = pts[5] + k*numberOfLayerPoints + numberOfLayerPoints/2; boundaryLayerCellArray->InsertNextCell(prismNPts,prismPts); delete[] prismPts; } else { vtkErrorMacro(<<"Unsupported surface element."); return 1; } } if (this->IncludeSurfaceCells) { if (k==this->NumberOfSubLayers-1) { for (i=0; iGetCellPoints(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); delete[] surfacePts; } } } } output->SetPoints(outputPoints); int* boundaryLayerCellTypesInt = new int[boundaryLayerCellTypes->GetNumberOfIds()]; for (i=0; iGetNumberOfIds(); i++) { boundaryLayerCellTypesInt[i] = boundaryLayerCellTypes->GetId(i); } output->SetCells(boundaryLayerCellTypesInt,boundaryLayerCellArray); delete[] boundaryLayerCellTypesInt; outputPoints->Delete(); warpedPoints->Delete(); boundaryLayerCellArray->Delete(); boundaryLayerCellTypes->Delete(); innerSurfacePoints->Delete(); return 1; } 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; iNumberOfSubLayers; i++) { totalLayerZeroSubLayerRatio += pow(this->SubLayerRatio,this->NumberOfSubLayers-i-1); } subLayerOffsetRatio = 0.0; for (i=0; iSubLayerRatio,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; iGetPoint(i,point); 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); 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::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLinearToQuadraticMeshFilter.h0000664000175000017500000000571411757446472022655 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearToQuadraticMeshFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkLinearToQuadraticMeshFilter - Converts linear elements to quadratic. // .SECTION Description // ... #ifndef __vtkvmtkLinearToQuadraticMeshFilter_h #define __vtkvmtkLinearToQuadraticMeshFilter_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkPolyData.h" #include "vtkCell.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkLinearToQuadraticMeshFilter : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkLinearToQuadraticMeshFilter,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkLinearToQuadraticMeshFilter *New(); vtkSetMacro(UseBiquadraticWedge,int); vtkGetMacro(UseBiquadraticWedge,int); vtkBooleanMacro(UseBiquadraticWedge,int); vtkSetObjectMacro(ReferenceSurface,vtkPolyData); vtkGetObjectMacro(ReferenceSurface,vtkPolyData); vtkSetStringMacro(CellEntityIdsArrayName); vtkGetStringMacro(CellEntityIdsArrayName); vtkSetMacro(ProjectedCellEntityId,int); vtkGetMacro(ProjectedCellEntityId,int); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); vtkSetMacro(NegativeJacobianTolerance,double); vtkGetMacro(NegativeJacobianTolerance,double); vtkSetMacro(JacobianRelaxation,int); vtkGetMacro(JacobianRelaxation,int); vtkBooleanMacro(JacobianRelaxation,int); vtkSetMacro(TestFinalJacobians,int); vtkGetMacro(TestFinalJacobians,int); vtkBooleanMacro(TestFinalJacobians,int); protected: vtkvmtkLinearToQuadraticMeshFilter(); ~vtkvmtkLinearToQuadraticMeshFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); bool HasJacobianChangedSign(vtkCell* linearVolumeCell, vtkCell* quadraticVolumeCell); double ComputeJacobian(vtkCell* cell, double pcoords[3]); int UseBiquadraticWedge; vtkPolyData* ReferenceSurface; char* CellEntityIdsArrayName; int ProjectedCellEntityId; int QuadratureOrder; double NegativeJacobianTolerance; int JacobianRelaxation; int TestFinalJacobians; private: vtkvmtkLinearToQuadraticMeshFilter(const vtkvmtkLinearToQuadraticMeshFilter&); // Not implemented. void operator=(const vtkvmtkLinearToQuadraticMeshFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStreamlineClusteringFilter.h0000664000175000017500000000356711757446472022634 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStreamlineClusteringFilter.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkStreamlineClusteringFilter - Cluster streamlines based on Mahalanobis distance metric and K-Means clustering. // .SECTION Description // This class clusters streamlines. #ifndef __vtkvmtkStreamlineClusteringFilter_h #define __vtkvmtkStreamlineClusteringFilter_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkStreamlineClusteringFilter : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkStreamlineClusteringFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkStreamlineClusteringFilter *New(); vtkGetObjectMacro(ClusterCenters,vtkPolyData); protected: vtkvmtkStreamlineClusteringFilter(); ~vtkvmtkStreamlineClusteringFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkPolyData* ClusterCenters; private: vtkvmtkStreamlineClusteringFilter(const vtkvmtkStreamlineClusteringFilter&); // Not implemented. void operator=(const vtkvmtkStreamlineClusteringFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLevelSetSigmoidFilter.cxx0000664000175000017500000000600211757446472022066 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLevelSetSigmoidFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkLevelSetSigmoidFilter.h" #include "vtkPointData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkLevelSetSigmoidFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkLevelSetSigmoidFilter); vtkvmtkLevelSetSigmoidFilter::vtkvmtkLevelSetSigmoidFilter() { this->LevelSetsImage = NULL; this->Sigma = 1.0; this->ScaleValue = 0.02; this->ComputeScaleValueFromInput = 1; } vtkvmtkLevelSetSigmoidFilter::~vtkvmtkLevelSetSigmoidFilter() { if (this->LevelSetsImage) { this->LevelSetsImage->Delete(); this->LevelSetsImage = NULL; } } void vtkvmtkLevelSetSigmoidFilter::SimpleExecute(vtkImageData* input, vtkImageData* output) { if (!this->LevelSetsImage) { vtkErrorMacro(<<"Error: no LevelSetsImage has been set!"); return; } vtkDataArray* inputScalars = input->GetPointData()->GetScalars(); vtkDataArray* levelSetsScalars = this->LevelSetsImage->GetPointData()->GetScalars(); vtkDataArray* outputScalars = output->GetPointData()->GetScalars(); double spacing[3]; input->GetSpacing(spacing); double minSpacing = spacing[0]; if (spacing[1] < minSpacing) { minSpacing = spacing[1]; } if (spacing[2] < minSpacing) { minSpacing = spacing[2]; } double windowValue = 4.0; double windowValueReal = windowValue * minSpacing; double sigmaReal = this->Sigma * minSpacing; double scaleValue = this->ScaleValue; int numberOfPoints = input->GetNumberOfPoints(); int i; if (this->ComputeScaleValueFromInput) { scaleValue = 0.0; for (i=0; iGetComponent(i,0); } scaleValue /= numberOfPoints; } for (i=0; iGetComponent(i,0); double levelSetsValue = levelSetsScalars->GetComponent(i,0); if (levelSetsValue < windowValueReal) { double sigmoidValue = scaleValue * 1.0 / (1.0 + exp((levelSetsValue-sigmaReal)/(0.5*sigmaReal))); featureValue += sigmoidValue; } outputScalars->SetComponent(i,0,featureValue); } } void vtkvmtkLevelSetSigmoidFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshLambda2.cxx0000664000175000017500000001231411757446472017743 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshLambda2.cxx,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMeshLambda2.h" #include "vtkvmtkUnstructuredGridGradientFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMeshLambda2, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkMeshLambda2); vtkvmtkMeshLambda2::vtkvmtkMeshLambda2() { this->VelocityArrayName = NULL; this->Lambda2ArrayName = NULL; this->ComputeIndividualPartialDerivatives = 0; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; this->ForceBoundaryToNegative = 0; } vtkvmtkMeshLambda2::~vtkvmtkMeshLambda2() { if (this->VelocityArrayName) { delete[] this->VelocityArrayName; this->VelocityArrayName = NULL; } if (this->Lambda2ArrayName) { delete[] this->Lambda2ArrayName; this->Lambda2ArrayName = NULL; } } int vtkvmtkMeshLambda2::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())); if (this->VelocityArrayName == NULL) { vtkErrorMacro("VelocityArrayName not specified"); return 1; } vtkDataArray* velocityArray = input->GetPointData()->GetArray(this->VelocityArrayName); if (velocityArray == NULL) { vtkErrorMacro("VelocityArray with name specified does not exist"); return 1; } char gradientArrayName[] = "VelocityGradient"; vtkvmtkUnstructuredGridGradientFilter* gradientFilter = vtkvmtkUnstructuredGridGradientFilter::New(); gradientFilter->SetInput(input); gradientFilter->SetInputArrayName(this->VelocityArrayName); gradientFilter->SetGradientArrayName(gradientArrayName); gradientFilter->SetQuadratureOrder(this->QuadratureOrder); gradientFilter->SetConvergenceTolerance(this->ConvergenceTolerance); gradientFilter->SetComputeIndividualPartialDerivatives(this->ComputeIndividualPartialDerivatives); gradientFilter->Update(); vtkDataArray* velocityGradientArray = gradientFilter->GetOutput()->GetPointData()->GetArray(gradientArrayName); int numberOfPoints = input->GetNumberOfPoints(); vtkDoubleArray* lambda2Array = vtkDoubleArray::New(); if (this->Lambda2ArrayName) { lambda2Array->SetName(this->Lambda2ArrayName); } else { lambda2Array->SetName("Lambda2"); } lambda2Array->SetNumberOfComponents(1); lambda2Array->SetNumberOfTuples(numberOfPoints); double velocityGradient[9]; double symmetricVelocityGradient[3][3]; double antiSymmetricVelocityGradient[3][3]; double A[3][3]; int i, j, k, l; for (i=0; iGetTuple(i,velocityGradient); for (j=0; j<3; j++) { for (k=0; k<3; k++) { int index0 = k + j*3; int index1 = j + k*3; symmetricVelocityGradient[j][k] = 0.5 * (velocityGradient[index0] + velocityGradient[index1]); antiSymmetricVelocityGradient[j][k] = 0.5 * (velocityGradient[index0] - velocityGradient[index1]); } } for (j=0; j<3; j++) { for (k=0; k<3; k++) { A[j][k] = 0.0; for (l=0; l<3; l++) { A[j][k] += symmetricVelocityGradient[j][l]*symmetricVelocityGradient[l][k] + antiSymmetricVelocityGradient[j][l]*antiSymmetricVelocityGradient[l][k]; } } } double eigenVectors[3][3]; double eigenValues[3]; vtkMath::Diagonalize3x3(A,eigenValues,eigenVectors); bool done = false; while (!done) { done = true; for (j=0; j<2; j++) { if (eigenValues[j] > eigenValues[j+1]) { done = false; double tmp = eigenValues[j+1]; eigenValues[j+1] = eigenValues[j]; eigenValues[j] = tmp; } } } double lambda2 = eigenValues[1]; lambda2Array->SetTuple1(i,lambda2); } output->DeepCopy(input); output->GetPointData()->AddArray(lambda2Array); lambda2Array->Delete(); return 1; } void vtkvmtkMeshLambda2::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSurfaceDistance.cxx0000664000175000017500000001525411757446472020735 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfaceDistance.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:49:05 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSurfaceDistance.h" #include "vtkCellLocator.h" #include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSurfaceDistance, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkSurfaceDistance); vtkvmtkSurfaceDistance::vtkvmtkSurfaceDistance() { this->DistanceArrayName = NULL; this->DistanceVectorsArrayName = NULL; this->SignedDistanceArrayName = NULL; this->ReferenceSurface = NULL; } vtkvmtkSurfaceDistance::~vtkvmtkSurfaceDistance() { if (this->ReferenceSurface) { this->ReferenceSurface->Delete(); this->ReferenceSurface = NULL; } if (this->DistanceArrayName) { delete[] this->DistanceArrayName; this->DistanceArrayName = NULL; } if (this->DistanceVectorsArrayName) { delete[] this->DistanceVectorsArrayName; this->DistanceVectorsArrayName = NULL; } if (this->SignedDistanceArrayName) { delete[] this->SignedDistanceArrayName; this->SignedDistanceArrayName = NULL; } } int vtkvmtkSurfaceDistance::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; vtkIdType numberOfPoints, numberOfCellPoints; vtkIdType cellId, pointId; int subId; double point[3], closestPoint[3]; double distance2, distance, signedDistance; double pcoords[3]; double pointNormal[3], *normal; double distanceVector[3]; double *weights; double dot; bool computeDistance, computeDistanceVectors, computeSignedDistance; vtkDoubleArray *distanceArray, *distanceVectorsArray, *signedDistanceArray; vtkDataArray *normals; vtkCellLocator *locator; vtkGenericCell *genericCell; vtkCell *cell; if (!this->ReferenceSurface) { vtkErrorMacro(<<"No reference surface!"); return 1; } if ((!this->DistanceArrayName)&&(!this->DistanceVectorsArrayName)&&(!this->SignedDistanceArrayName)) { vtkErrorMacro(<<"No array names set!"); return 1; } distanceArray = vtkDoubleArray::New(); distanceVectorsArray = vtkDoubleArray::New(); signedDistanceArray = vtkDoubleArray::New(); normals = NULL; locator = vtkCellLocator::New(); genericCell = vtkGenericCell::New(); numberOfPoints = input->GetNumberOfPoints(); computeDistance = false; computeDistanceVectors = false; computeSignedDistance = false; if (this->DistanceArrayName) { computeDistance = true; distanceArray->SetName(this->DistanceArrayName); distanceArray->SetNumberOfComponents(1); distanceArray->SetNumberOfTuples(numberOfPoints); } if (this->DistanceVectorsArrayName) { computeDistanceVectors = true; distanceVectorsArray->SetName(this->DistanceVectorsArrayName); distanceVectorsArray->SetNumberOfComponents(3); distanceVectorsArray->SetNumberOfTuples(numberOfPoints); } if (this->SignedDistanceArrayName) { computeSignedDistance = true; signedDistanceArray->SetName(this->SignedDistanceArrayName); signedDistanceArray->SetNumberOfComponents(1); signedDistanceArray->SetNumberOfTuples(numberOfPoints); normals = this->ReferenceSurface->GetPointData()->GetNormals(); if (!normals) { vtkErrorMacro(<<"Signed distance requires point normals to be defined over ReferenceSurface!"); return 1; } } locator->SetDataSet(this->ReferenceSurface); locator->BuildLocator(); for (i=0; iGetPoint(i,point); locator->FindClosestPoint(point,closestPoint,genericCell,cellId,subId,distance2); distanceVector[0] = point[0] - closestPoint[0]; distanceVector[1] = point[1] - closestPoint[1]; distanceVector[2] = point[2] - closestPoint[2]; distance = sqrt(distance2); if (computeDistance) { distanceArray->SetTuple1(i,distance); } if (computeDistanceVectors) { distanceVectorsArray->SetTuple3(i,-distanceVector[0],-distanceVector[1],-distanceVector[2]); } if (computeSignedDistance) { cell = this->ReferenceSurface->GetCell(cellId); numberOfCellPoints = cell->GetNumberOfPoints(); weights = new double[numberOfCellPoints]; cell->EvaluatePosition(point,NULL,subId,pcoords,distance2,weights); pointNormal[0] = 0.0; pointNormal[1] = 0.0; pointNormal[2] = 0.0; for (j=0; jGetPointId(j); normal = normals->GetTuple3(pointId); pointNormal[0] += weights[j] * normal[0]; pointNormal[1] += weights[j] * normal[1]; pointNormal[2] += weights[j] * normal[2]; } dot = vtkMath::Dot(distanceVector,pointNormal); signedDistance = distance; // distance is positive if distanceVector and normal have negative dot if (dot>0.0) { signedDistance *= -1.0; } signedDistanceArray->SetTuple1(i,signedDistance); delete[] weights; } } output->DeepCopy(input); if (computeDistance) { output->GetPointData()->AddArray(distanceArray); } if (computeDistanceVectors) { output->GetPointData()->AddArray(distanceVectorsArray); } if (computeSignedDistance) { output->GetPointData()->AddArray(signedDistanceArray); } distanceArray->Delete(); distanceVectorsArray->Delete(); signedDistanceArray->Delete(); locator->Delete(); genericCell->Delete(); return 1; } void vtkvmtkSurfaceDistance::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataKiteRemovalFilter.h0000664000175000017500000000347511757446472022347 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataKiteRemovalFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataKiteRemovalFilter - Add caps to boundaries. // .SECTION Description // This class closes the boundaries of a surface with a cap. #ifndef __vtkvmtkPolyDataKiteRemovalFilter_h #define __vtkvmtkPolyDataKiteRemovalFilter_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkPolyDataKiteRemovalFilter : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataKiteRemovalFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataKiteRemovalFilter *New(); vtkGetMacro(SizeFactor,double); vtkSetMacro(SizeFactor,double); protected: vtkvmtkPolyDataKiteRemovalFilter(); ~vtkvmtkPolyDataKiteRemovalFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); double SizeFactor; private: vtkvmtkPolyDataKiteRemovalFilter(const vtkvmtkPolyDataKiteRemovalFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataKiteRemovalFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkAnnularCapPolyData.cxx0000664000175000017500000002511211757446472021346 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkAnnularCapPolyData.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkAnnularCapPolyData.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkvmtkBoundaryReferenceSystems.h" #include "vtkPolyData.h" #include "vtkCellArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyLine.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkAnnularCapPolyData, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkAnnularCapPolyData); vtkvmtkAnnularCapPolyData::vtkvmtkAnnularCapPolyData() { this->CellEntityIdsArrayName = NULL; this->CellEntityIdOffset = 1; } vtkvmtkAnnularCapPolyData::~vtkvmtkAnnularCapPolyData() { if (this->CellEntityIdsArrayName) { delete[] this->CellEntityIdsArrayName; this->CellEntityIdsArrayName = NULL; } } int vtkvmtkAnnularCapPolyData::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 ( input->GetNumberOfPoints() < 1 ) { return 1; } bool markCells = true; if (!this->CellEntityIdsArrayName) { markCells = false; } if (strcmp(this->CellEntityIdsArrayName,"") == 0) { markCells = false; } input->BuildLinks(); vtkPoints* newPoints = vtkPoints::New(); newPoints->DeepCopy(input->GetPoints()); vtkCellArray* newPolys = vtkCellArray::New(); newPolys->DeepCopy(input->GetPolys()); vtkIntArray* cellEntityIdsArray = NULL; if (markCells) { cellEntityIdsArray = vtkIntArray::New(); cellEntityIdsArray->SetName(this->CellEntityIdsArrayName); cellEntityIdsArray->SetNumberOfTuples(newPolys->GetNumberOfCells()); cellEntityIdsArray->FillComponent(0,static_cast(this->CellEntityIdOffset)); } vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(input); boundaryExtractor->Update(); vtkPolyData* boundaries = boundaryExtractor->GetOutput(); int numberOfBoundaries = boundaries->GetNumberOfCells(); if (numberOfBoundaries % 2 != 0) { vtkErrorMacro(<< "Error: the number of boundaries must be even."); newPoints->Delete(); newPolys->Delete(); if (markCells) { cellEntityIdsArray->Delete(); } boundaryExtractor->Delete(); } vtkPoints* barycenters = vtkPoints::New(); barycenters->SetNumberOfPoints(numberOfBoundaries); vtkIdList* boundaryPairings = vtkIdList::New(); boundaryPairings->SetNumberOfIds(numberOfBoundaries); vtkIdList* visitedBoundaries = vtkIdList::New(); visitedBoundaries->SetNumberOfIds(numberOfBoundaries); double barycenter[3]; for (int i=0; iGetCell(i); vtkvmtkBoundaryReferenceSystems::ComputeBoundaryBarycenter(boundary->GetPoints(),barycenter); barycenters->SetPoint(i,barycenter); boundaryPairings->SetId(i,-1); visitedBoundaries->SetId(i,-1); } double currentBarycenter[3]; double distance2, minDistance2 = 0.0; vtkIdType closestBoundaryId; for (int i=0; iGetId(i) != -1 || boundaryPairings->IsId(i) != -1) { continue; } barycenters->GetPoint(i,barycenter); closestBoundaryId = -1; for (int j=i+1; jGetId(j) != -1 || boundaryPairings->IsId(j) != -1) { continue; } barycenters->GetPoint(j,currentBarycenter); distance2 = vtkMath::Distance2BetweenPoints(barycenter,currentBarycenter); if (closestBoundaryId == -1 || distance2 < minDistance2) { minDistance2 = distance2; closestBoundaryId = j; } } boundaryPairings->SetId(i,closestBoundaryId); boundaryPairings->SetId(closestBoundaryId,i); } for (int i=0; iGetId(i) == -1) { continue; } if (visitedBoundaries->GetId(i) != -1) { continue; } visitedBoundaries->SetId(i,i); visitedBoundaries->SetId(boundaryPairings->GetId(i),i); vtkIdTypeArray* boundaryPointIdsArray = vtkIdTypeArray::New(); boundaryPointIdsArray->DeepCopy(boundaries->GetPointData()->GetScalars()); vtkPolyLine* boundary0 = vtkPolyLine::SafeDownCast(boundaries->GetCell(i)); vtkIdType numberOfBoundaryPoints0 = boundary0->GetNumberOfPoints(); vtkIdList* boundaryPointIds0 = vtkIdList::New(); boundaryPointIds0->SetNumberOfIds(numberOfBoundaryPoints0); for (int j=0; jSetId(j,boundaryPointIdsArray->GetValue(boundary0->GetPointId(j))); } vtkPolyLine* boundary1 = vtkPolyLine::SafeDownCast(boundaries->GetCell(boundaryPairings->GetId(i))); vtkIdType numberOfBoundaryPoints1 = boundary1->GetNumberOfPoints(); vtkIdList* boundaryPointIds1 = vtkIdList::New(); boundaryPointIds1->SetNumberOfIds(numberOfBoundaryPoints1); for (int j=0; jSetId(j,boundaryPointIdsArray->GetValue(boundary1->GetPointId(j))); } double startingPoint[3], currentPoint[3]; input->GetPoint(boundaryPointIds0->GetId(0),startingPoint); vtkIdType offset = -1; for (int j=0; jGetPoint(boundaryPointIds1->GetId(j),currentPoint); distance2 = vtkMath::Distance2BetweenPoints(startingPoint,currentPoint); if (offset == -1 || distance2 < minDistance2) { offset = j; minDistance2 = distance2; } } double vectorToStart[3], vectorToForward[3], cross0[3], cross1[3]; double pointForward[3]; barycenters->GetPoint(i,barycenter); input->GetPoint(boundaryPointIds0->GetId(0),startingPoint); input->GetPoint(boundaryPointIds0->GetId(numberOfBoundaryPoints0/8),pointForward); vectorToStart[0] = startingPoint[0] - barycenter[0]; vectorToStart[1] = startingPoint[1] - barycenter[1]; vectorToStart[2] = startingPoint[2] - barycenter[2]; vectorToForward[0] = pointForward[0] - barycenter[0]; vectorToForward[1] = pointForward[1] - barycenter[1]; vectorToForward[2] = pointForward[2] - barycenter[2]; vtkMath::Cross(vectorToStart,vectorToForward,cross0); barycenters->GetPoint(boundaryPairings->GetId(i),barycenter); input->GetPoint(boundaryPointIds1->GetId(0),startingPoint); input->GetPoint(boundaryPointIds1->GetId(numberOfBoundaryPoints1/8),pointForward); vectorToStart[0] = startingPoint[0] - barycenter[0]; vectorToStart[1] = startingPoint[1] - barycenter[1]; vectorToStart[2] = startingPoint[2] - barycenter[2]; vectorToForward[0] = pointForward[0] - barycenter[0]; vectorToForward[1] = pointForward[1] - barycenter[1]; vectorToForward[2] = pointForward[2] - barycenter[2]; vtkMath::Cross(vectorToStart,vectorToForward,cross1); bool backward = false; if (vtkMath::Dot(cross0,cross1) < 0.0) { backward = true; } double point0[3], nextPoint0[3]; double point1[3], nextPoint1[3]; vtkIdType pointId0, nextPointId0; vtkIdType pointId1, nextPointId1; int j = 0; int k = 0; while (true) { if (j == numberOfBoundaryPoints0 && k == numberOfBoundaryPoints1) { break; } pointId0 = j % numberOfBoundaryPoints0; nextPointId0 = (pointId0 + 1) % numberOfBoundaryPoints0; pointId1 = (k + offset) % numberOfBoundaryPoints1; nextPointId1 = (pointId1 + 1) % numberOfBoundaryPoints1; if (backward) { pointId1 = (numberOfBoundaryPoints1 - k + offset + numberOfBoundaryPoints1) % numberOfBoundaryPoints1; nextPointId1 = (pointId1 - 1 + numberOfBoundaryPoints1) % numberOfBoundaryPoints1; } input->GetPoint(boundaryPointIds0->GetId(pointId0),point0); input->GetPoint(boundaryPointIds0->GetId(nextPointId0),nextPoint0); input->GetPoint(boundaryPointIds1->GetId(pointId1),point1); input->GetPoint(boundaryPointIds1->GetId(nextPointId1),nextPoint1); newPolys->InsertNextCell(3); newPolys->InsertCellPoint(boundaryPointIds0->GetId(pointId0)); newPolys->InsertCellPoint(boundaryPointIds1->GetId(pointId1)); bool next1 = false; if (vtkMath::Distance2BetweenPoints(point0,nextPoint1) < vtkMath::Distance2BetweenPoints(point1,nextPoint0)) { next1 = true; } if (k == numberOfBoundaryPoints1) { next1 = false; } else if (j == numberOfBoundaryPoints0) { next1 = true; } if (next1) { newPolys->InsertCellPoint(boundaryPointIds1->GetId(nextPointId1)); k++; } else { newPolys->InsertCellPoint(boundaryPointIds0->GetId(nextPointId0)); j++; } if (markCells) { cellEntityIdsArray->InsertNextValue(i+1+this->CellEntityIdOffset); } } boundaryPointIdsArray->Delete(); boundaryPointIds0->Delete(); boundaryPointIds1->Delete(); } output->SetPoints(newPoints); output->SetPolys(newPolys); output->GetPointData()->PassData(input->GetPointData()); if (markCells) { output->GetCellData()->AddArray(cellEntityIdsArray); cellEntityIdsArray->Delete(); } newPoints->Delete(); newPolys->Delete(); boundaryExtractor->Delete(); barycenters->Delete(); visitedBoundaries->Delete(); return 1; } void vtkvmtkAnnularCapPolyData::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataSizingFunction.h0000664000175000017500000000373311757446472021725 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataSizingFunction.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataSizingFunction - Add caps to boundaries. // .SECTION Description // This class constructs a sizing function for volume meshing on the basis // on the input surface. #ifndef __vtkvmtkPolyDataSizingFunction_h #define __vtkvmtkPolyDataSizingFunction_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkPolyDataSizingFunction : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataSizingFunction,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataSizingFunction *New(); vtkSetStringMacro(SizingFunctionArrayName); vtkGetStringMacro(SizingFunctionArrayName); vtkSetMacro(ScaleFactor,double); vtkGetMacro(ScaleFactor,double); protected: vtkvmtkPolyDataSizingFunction(); ~vtkvmtkPolyDataSizingFunction(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* SizingFunctionArrayName; double ScaleFactor; private: vtkvmtkPolyDataSizingFunction(const vtkvmtkPolyDataSizingFunction&); // Not implemented. void operator=(const vtkvmtkPolyDataSizingFunction&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStreamlineOsculatingCentersFilter.cxx0000664000175000017500000001651311757446472024517 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStreamlineOsculatingCentersFilter.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkStreamlineOsculatingCentersFilter.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkMath.h" #include "vtkSplineFilter.h" #include "vtkCellLocator.h" #include "vtkCellArray.h" #include "vtkCell.h" vtkCxxRevisionMacro(vtkvmtkStreamlineOsculatingCentersFilter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkStreamlineOsculatingCentersFilter); vtkvmtkStreamlineOsculatingCentersFilter::vtkvmtkStreamlineOsculatingCentersFilter() { this->VoronoiDiagram = NULL; this->VoronoiSheetIdsArrayName = NULL; this->OsculatingCenters = NULL; } vtkvmtkStreamlineOsculatingCentersFilter::~vtkvmtkStreamlineOsculatingCentersFilter() { if (this->VoronoiDiagram) { this->VoronoiDiagram->Delete(); this->VoronoiDiagram = NULL; } if (this->OsculatingCenters) { this->OsculatingCenters->Delete(); this->OsculatingCenters = NULL; } if (this->VoronoiSheetIdsArrayName) { delete[] this->VoronoiSheetIdsArrayName; this->VoronoiSheetIdsArrayName = NULL; } } int vtkvmtkStreamlineOsculatingCentersFilter::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 (input->GetNumberOfPoints() < 1) { return 1; } if (this->OsculatingCenters) { this->OsculatingCenters->Delete(); this->OsculatingCenters = NULL; } this->OsculatingCenters = vtkPolyData::New(); double resampleLength = 0.1; vtkSplineFilter* splineFilter = vtkSplineFilter::New(); splineFilter->SetInput(input); splineFilter->SetSubdivideToLength(); splineFilter->SetLength(resampleLength); splineFilter->Update(); vtkPolyData* streamlines = splineFilter->GetOutput(); vtkIntArray* voronoiSheetIdsArray = NULL; vtkIntArray* sheetIdsArray = NULL; vtkIntArray* streamlineSheetIdsArray = NULL; vtkCellLocator* cellLocator = NULL; if (this->VoronoiDiagram) { if (!this->VoronoiDiagram->GetCellData()->GetArray(this->VoronoiSheetIdsArrayName)) { vtkErrorMacro(<< "VoronoiSheetIdsArray with name specified does not exist!"); return 1; } voronoiSheetIdsArray = vtkIntArray::New(); voronoiSheetIdsArray->DeepCopy(this->VoronoiDiagram->GetCellData()->GetArray(this->VoronoiSheetIdsArrayName)); sheetIdsArray = vtkIntArray::New(); sheetIdsArray->SetName(this->VoronoiSheetIdsArrayName); cellLocator = vtkCellLocator::New(); cellLocator->SetDataSet(this->VoronoiDiagram); cellLocator->BuildLocator(); streamlineSheetIdsArray = vtkIntArray::New(); streamlineSheetIdsArray->SetName(this->VoronoiSheetIdsArrayName); streamlineSheetIdsArray->SetNumberOfTuples(streamlines->GetNumberOfPoints()); } int numberOfCells = streamlines->GetNumberOfCells(); vtkIntArray* labelArray = vtkIntArray::New(); labelArray->SetName("Label"); vtkDoubleArray* radiusArray = vtkDoubleArray::New(); radiusArray->SetName("Radius"); vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputVertices = vtkCellArray::New(); for (int i=0; iGetCell(i); int numberOfStreamlinePoints = streamline->GetNumberOfPoints(); for (int ip=1; ipGetPoint(streamline->GetPointId(ip-1),x0); streamlines->GetPoint(streamline->GetPointId(ip),x1); streamlines->GetPoint(streamline->GetPointId(ip+1),x2); double u[3], a[3]; for (int j=0; j<3; j++) { a[j] = 0.5 * (x1[j] + x0[j]); } double x2_x1[3], x1_x0[3]; double x2_a[3]; for (int j=0; j<3; j++) { x2_x1[j] = x2[j] - x1[j]; x1_x0[j] = x1[j] - x0[j]; x2_a[j] = x2[j] - a[j]; } double a_x2_sq = vtkMath::Distance2BetweenPoints(a,x2); double a_x1_sq = vtkMath::Distance2BetweenPoints(a,x1); double x2_x1_dot_x1_x0 = vtkMath::Dot(x2_x1,x1_x0); double x2_x1_sq = vtkMath::Distance2BetweenPoints(x2,x1); for (int j=0; j<3; j++) { u[j] = (x2[j] - x1[j]) - (x1[j] - x0[j]) * (x2_x1_dot_x1_x0 / x2_x1_sq); } vtkMath::Normalize(u); double u_dot_x2_a = vtkMath::Dot(u, x2_a); if (fabs(u_dot_x2_a) < VTK_VMTK_DOUBLE_TOL) { continue; } double t = (a_x2_sq - a_x1_sq) / (2.0 * u_dot_x2_a); double osculatingCenter[3]; for (int j=0; j<3; j++) { osculatingCenter[j] = a[j] + t * u[j]; } double radius = sqrt(vtkMath::Distance2BetweenPoints(osculatingCenter,x1)); vtkIdType id = outputPoints->InsertNextPoint(osculatingCenter); outputVertices->InsertNextCell(1); outputVertices->InsertCellPoint(id); labelArray->InsertNextValue(i); radiusArray->InsertNextValue(radius); if (this->VoronoiDiagram) { double closestPoint[3], dist2; vtkIdType sheetId, cellId; int subId; cellLocator->FindClosestPoint(osculatingCenter,closestPoint,cellId,subId,dist2); sheetId = voronoiSheetIdsArray->GetValue(cellId); sheetIdsArray->InsertNextValue(sheetId); streamlineSheetIdsArray->InsertValue(streamline->GetPointId(ip),sheetId); } } } this->OsculatingCenters->SetPoints(outputPoints); this->OsculatingCenters->SetVerts(outputVertices); this->OsculatingCenters->GetPointData()->AddArray(labelArray); this->OsculatingCenters->GetPointData()->AddArray(radiusArray); if (sheetIdsArray) { this->OsculatingCenters->GetPointData()->AddArray(sheetIdsArray); } output->DeepCopy(streamlines); if (sheetIdsArray) { output->GetPointData()->AddArray(streamlineSheetIdsArray); } splineFilter->Delete(); outputPoints->Delete(); outputVertices->Delete(); labelArray->Delete(); radiusArray->Delete(); if (voronoiSheetIdsArray) { voronoiSheetIdsArray->Delete(); sheetIdsArray->Delete(); streamlineSheetIdsArray->Delete(); cellLocator->Delete(); } return 1; } void vtkvmtkStreamlineOsculatingCentersFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkImageBoxPainter.h0000664000175000017500000000417711757446472020337 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkImageBoxPainter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkImageBoxPainter // .SECTION Description // #ifndef __vtkvmtkImageBoxPainter_h #define __vtkvmtkImageBoxPainter_h #include "vtkSimpleImageToImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkImageBoxPainter : public vtkSimpleImageToImageFilter { public: static vtkvmtkImageBoxPainter *New(); vtkTypeRevisionMacro(vtkvmtkImageBoxPainter,vtkSimpleImageToImageFilter); vtkGetMacro(PaintValue,double); vtkSetMacro(PaintValue,double); vtkGetVectorMacro(BoxBounds,double,6); vtkSetVectorMacro(BoxBounds,double,6); vtkGetVectorMacro(BoxExtent,int,6); vtkSetVectorMacro(BoxExtent,int,6); vtkGetMacro(BoxDefinition,int); vtkSetMacro(BoxDefinition,int); void SetBoxDefinitionToUseExtent() { this->BoxDefinition = vtkvmtkImageBoxPainter::USE_EXTENT; } void SetBoxDefinitionToUseBounds() { this->BoxDefinition = vtkvmtkImageBoxPainter::USE_BOUNDS; } protected: vtkvmtkImageBoxPainter(); ~vtkvmtkImageBoxPainter() {}; virtual void SimpleExecute(vtkImageData* input, vtkImageData* output); double PaintValue; double BoxBounds[6]; int BoxExtent[6]; int BoxDefinition; //BTX enum { USE_BOUNDS, USE_EXTENT }; //ETX private: vtkvmtkImageBoxPainter(const vtkvmtkImageBoxPainter&); // Not implemented. void operator=(const vtkvmtkImageBoxPainter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLinearToQuadraticSurfaceMeshFilter.cxx0000664000175000017500000001155511757446472024541 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearToQuadraticSurfaceMeshFilter.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:49:05 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkLinearToQuadraticSurfaceMeshFilter.h" #include "vtkGeometryFilter.h" #include "vtkInterpolatingSubdivisionFilter.h" #include "vtkLinearSubdivisionFilter.h" #include "vtkButterflySubdivisionFilter.h" #include "vtkPolyData.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkLinearToQuadraticSurfaceMeshFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkLinearToQuadraticSurfaceMeshFilter); vtkvmtkLinearToQuadraticSurfaceMeshFilter::vtkvmtkLinearToQuadraticSurfaceMeshFilter() { } vtkvmtkLinearToQuadraticSurfaceMeshFilter::~vtkvmtkLinearToQuadraticSurfaceMeshFilter() { } int vtkvmtkLinearToQuadraticSurfaceMeshFilter::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())); vtkIdType nqpts, *qpts, npts0, *pts0, npts1, *pts1; vtkIdType numberOfInputCells; vtkPolyData* subdividedSurface; vtkCellArray* quadraticTriangles; vtkIdList* quadraticTriangleCellTypes; vtkGeometryFilter* geometryFilter; vtkInterpolatingSubdivisionFilter* subdivisionFilter; geometryFilter = vtkGeometryFilter::New(); geometryFilter->SetInput(input); geometryFilter->MergingOff(); switch (this->SubdivisionMethod) { case LINEAR_SUBDIVISION: subdivisionFilter = vtkLinearSubdivisionFilter::New(); break; case BUTTERFLY_SUBDIVISION: subdivisionFilter = vtkButterflySubdivisionFilter::New(); break; default: vtkErrorMacro(<<"Unsupported subdivision method."); return 1; } subdivisionFilter->SetInput(geometryFilter->GetOutput()); subdivisionFilter->SetNumberOfSubdivisions(1); subdivisionFilter->Update(); subdividedSurface = subdivisionFilter->GetOutput(); output->SetPoints(subdividedSurface->GetPoints()); output->GetPointData()->PassData(subdividedSurface->GetPointData()); output->GetCellData()->PassData(subdividedSurface->GetCellData()); // input->BuildCells(); subdividedSurface->BuildCells(); numberOfInputCells = input->GetNumberOfCells(); quadraticTriangles = vtkCellArray::New(); quadraticTriangleCellTypes = vtkIdList::New(); nqpts = 6; qpts = new vtkIdType[nqpts]; // strongly based on the way output cells are built in vtkInterpolatingSubdivisionFilter !!! for (int i=0; iGetCellPoints(i,npts0,pts0); subdividedSurface->GetCellPoints(4*i+3,npts1,pts1); qpts[0] = pts0[0]; qpts[1] = pts0[1]; qpts[2] = pts0[2]; qpts[3] = pts1[0]; qpts[4] = pts1[1]; qpts[5] = pts1[2]; // old PolyDataToPolyData version // qpts[0] = pts0[0]; // qpts[1] = pts1[0]; // qpts[2] = pts0[1]; // qpts[3] = pts1[1]; // qpts[4] = pts0[2]; // qpts[5] = pts1[2]; quadraticTriangles->InsertNextCell(nqpts,qpts); quadraticTriangleCellTypes->InsertNextId(VTK_QUADRATIC_TRIANGLE); } delete[] qpts; int* quadraticTriangleCellTypesInt = new int[quadraticTriangleCellTypes->GetNumberOfIds()]; for (int i=0; iGetNumberOfIds(); i++) { quadraticTriangleCellTypesInt[i] = quadraticTriangleCellTypes->GetId(i); } output->SetCells(quadraticTriangleCellTypesInt,quadraticTriangles); delete[] quadraticTriangleCellTypesInt; geometryFilter->Delete(); subdivisionFilter->Delete(); quadraticTriangles->Delete(); quadraticTriangleCellTypes->Delete(); return 1; } void vtkvmtkLinearToQuadraticSurfaceMeshFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshProjection.h0000664000175000017500000000347011757446472020245 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshProjection.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkMeshProjection - ... // .SECTION Description // . #ifndef __vtkvmtkMeshProjection_h #define __vtkvmtkMeshProjection_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkUnstructuredGrid.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkMeshProjection : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkMeshProjection,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkMeshProjection *New(); vtkSetObjectMacro(ReferenceMesh,vtkUnstructuredGrid); vtkGetObjectMacro(ReferenceMesh,vtkUnstructuredGrid); vtkSetMacro(Tolerance,double); vtkGetMacro(Tolerance,double); protected: vtkvmtkMeshProjection(); ~vtkvmtkMeshProjection(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkUnstructuredGrid *ReferenceMesh; double Tolerance; private: vtkvmtkMeshProjection(const vtkvmtkMeshProjection&); // Not implemented. void operator=(const vtkvmtkMeshProjection&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStaticTemporalStreamTracer.h0000664000175000017500000001032011757446472022554 0ustar lucaluca/*========================================================================= Program: Visualization Toolkit Module: vtkvmtkStaticTemporalStreamTracer.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 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) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkStaticTemporalStreamTracer - Streamline generator // .SECTION Description // vtkvmtkStaticTemporalStreamTracer is a filter that integrates a vector field to generate // streamlines. The integration is performed using a specified integrator, // by default Runge-Kutta2. // #ifndef __vtkvmtkStaticTemporalStreamTracer_h #define __vtkvmtkStaticTemporalStreamTracer_h #include "vtkStreamTracer.h" #include "vtkvmtkWin32Header.h" class vtkTable; class VTK_VMTK_MISC_EXPORT vtkvmtkStaticTemporalStreamTracer : public vtkStreamTracer { public: vtkTypeMacro(vtkvmtkStaticTemporalStreamTracer,vtkStreamTracer); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkStaticTemporalStreamTracer *New(); vtkSetMacro(SeedTime, double); vtkGetMacro(SeedTime, double); vtkSetStringMacro(SeedTimesArrayName); vtkGetStringMacro(SeedTimesArrayName); vtkSetMacro(Periodic, int); vtkGetMacro(Periodic, int); vtkBooleanMacro(Periodic, int); vtkSetMacro(VelocityScale, double); vtkGetMacro(VelocityScale, double); vtkGetObjectMacro(TimeStepsTable,vtkTable); virtual void SetTimeStepsTable(vtkTable*); 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); protected: vtkvmtkStaticTemporalStreamTracer(); ~vtkvmtkStaticTemporalStreamTracer(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void InitializeDefaultInterpolatorPrototype(); int CheckInputs(vtkAbstractInterpolatedVelocityField*& func, int* maxCellSize); void InitializeSeeds(vtkDataArray*& seeds, vtkIdList*& seedIds, vtkDoubleArray*& startTimes, vtkIntArray*& integrationDirections, vtkDataSet *source); void Integrate(vtkDataSet *input, vtkPolyData* output, vtkDataArray* seedSource, vtkIdList* seedIds, vtkDoubleArray* startTimes, vtkIntArray* integrationDirections, double lastPoint[3], vtkAbstractInterpolatedVelocityField* func, int maxCellSize, double& propagation, vtkIdType& numSteps); double SeedTime; char* SeedTimesArrayName; int Periodic; int UseVectorComponents; char* VectorPrefix; char* Component0Prefix; char* Component1Prefix; char* Component2Prefix; vtkTable* TimeStepsTable; double VelocityScale; private: vtkvmtkStaticTemporalStreamTracer(const vtkvmtkStaticTemporalStreamTracer&); // Not implemented. void operator=(const vtkvmtkStaticTemporalStreamTracer&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStreamlineToParticlesFilter.h0000664000175000017500000000532211757446472022735 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStreamlineToParticlesFilter.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkStreamlineToParticlesFilter - Cluster streamlines based on Mahalanobis distance metric and K-Means clustering. // .SECTION Description // This class clusters streamlines. #ifndef __vtkvmtkStreamlineToParticlesFilter_h #define __vtkvmtkStreamlineToParticlesFilter_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkStreamlineToParticlesFilter : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkStreamlineToParticlesFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkStreamlineToParticlesFilter *New(); vtkSetMacro(NumberOfInjections,int); vtkGetMacro(NumberOfInjections,int); vtkSetMacro(NumberOfParticlesPerInjection,int); vtkGetMacro(NumberOfParticlesPerInjection,int); vtkSetMacro(InjectionStart,double); vtkGetMacro(InjectionStart,double); vtkSetMacro(InjectionEnd,double); vtkGetMacro(InjectionEnd,double); vtkSetMacro(TracingEnd,double); vtkGetMacro(TracingEnd,double); vtkSetMacro(DeltaT,double); vtkGetMacro(DeltaT,double); vtkSetStringMacro(IntegrationTimeArrayName); vtkGetStringMacro(IntegrationTimeArrayName); vtkSetStringMacro(TimeArrayName); vtkGetStringMacro(TimeArrayName); vtkSetStringMacro(VelocityArrayName); vtkGetStringMacro(VelocityArrayName); protected: vtkvmtkStreamlineToParticlesFilter(); ~vtkvmtkStreamlineToParticlesFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int NumberOfInjections; int NumberOfParticlesPerInjection; double InjectionStart; double InjectionEnd; double TracingEnd; double DeltaT; char* IntegrationTimeArrayName; char* TimeArrayName; char* VelocityArrayName; private: vtkvmtkStreamlineToParticlesFilter(const vtkvmtkStreamlineToParticlesFilter&); // Not implemented. void operator=(const vtkvmtkStreamlineToParticlesFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkTetGenWrapper.cxx0000664000175000017500000003735711757446472020431 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkTetGenWrapper.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.8 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkTetGenWrapper.h" #include "vtkvmtkConstants.h" #include "vtkUnstructuredGrid.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkIntArray.h" #include "vtkStdString.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "tetgen.h" vtkCxxRevisionMacro(vtkvmtkTetGenWrapper, "$Revision: 1.8 $"); vtkStandardNewMacro(vtkvmtkTetGenWrapper); vtkvmtkTetGenWrapper::vtkvmtkTetGenWrapper() { this->PLC = 0; // -p switch, 0 this->Refine = 0; // -r switch, 0 this->Coarsen = 0; // -R switch, 0 this->Quality = 0; // -q switch, 0 this->NoBoundarySplit = 0; // -Y switch, 0 this->VarVolume = 0; // -a switch without number, 0 this->FixedVolume = 0; // -a switch with number, 0 this->MaxVolume = -1.0; // number after -a, -1.0 this->RemoveSliver = 0; // -s switch, 0 this->MinRatio = 2.0; // number after -q, 2.0 this->MinDihedral = 5.0; // number after -qq, 5.0 this->MaxDihedral = 165.0; // number after -qqq, 165.0 this->RegionAttrib = 0; // -A switch, 0 this->Epsilon = 1.0e-8; // number after -T switch, 1.0e-8 this->NoMerge = 0; // -M switch, 0 this->DetectInter = 0; // -d switch, 0 this->CheckClosure = 0; // -c switch, 0 this->Order = 1; // number after -o switch, 1 (e.g. -o2 for quadratic elements) this->DoCheck = 0; // -C switch, 0 this->UseSizingFunction = 0; // -m switch, 0 this->Verbose = 0; this->CellEntityIdsArrayName = NULL; this->TetrahedronVolumeArrayName = NULL; this->SizingFunctionArrayName = NULL; this->OutputSurfaceElements = 1; this->OutputVolumeElements = 1; this->LastRunExitStatus = -1; } vtkvmtkTetGenWrapper::~vtkvmtkTetGenWrapper() { if (this->CellEntityIdsArrayName) { delete[] this->CellEntityIdsArrayName; this->CellEntityIdsArrayName = NULL; } if (this->TetrahedronVolumeArrayName) { delete[] this->TetrahedronVolumeArrayName; this->TetrahedronVolumeArrayName = NULL; } if (this->SizingFunctionArrayName) { delete[] this->SizingFunctionArrayName; this->SizingFunctionArrayName = NULL; } } int vtkvmtkTetGenWrapper::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())); if (this->VarVolume && !this->TetrahedronVolumeArrayName) { vtkErrorMacro(<<"VarVolumeOn but TetrahedronVolumeArrayName not specified"); return 1; } vtkStdString tetgenOptionString; char buffer[64]; if (this->PLC) { tetgenOptionString += "p"; } if (this->Refine) { tetgenOptionString += "r"; } if (this->Coarsen) { tetgenOptionString += "R"; } if (this->Quality) { tetgenOptionString += "q"; sprintf(buffer,"%f",this->MinRatio); tetgenOptionString += buffer; tetgenOptionString += "q"; sprintf(buffer,"%f",this->MinDihedral); tetgenOptionString += buffer; tetgenOptionString += "q"; sprintf(buffer,"%f",this->MaxDihedral); tetgenOptionString += buffer; } if (this->NoBoundarySplit) { tetgenOptionString += "Y"; } if (this->RemoveSliver) { tetgenOptionString += "s"; } if (this->Order == 2) { tetgenOptionString += "o2"; } tetgenOptionString += "T"; sprintf(buffer,"%e",this->Epsilon); tetgenOptionString += buffer; if (this->VarVolume) { tetgenOptionString += "a"; } if (this->FixedVolume) { tetgenOptionString += "a"; sprintf(buffer,"%f",this->MaxVolume); tetgenOptionString += buffer; } if (this->RegionAttrib) { tetgenOptionString += "A"; } if (this->NoMerge) { tetgenOptionString += "M"; } if (this->DetectInter) { tetgenOptionString += "d"; } if (this->DoCheck) { tetgenOptionString += "C"; } if (this->CheckClosure) { tetgenOptionString += "c"; } tetgenOptionString += "z"; // tetgenOptionString += "Y"; if (this->Verbose) { tetgenOptionString += "V"; } else { tetgenOptionString += "Q"; } vtkDataArray* sizingFunctionArray = NULL; if (this->SizingFunctionArrayName) { sizingFunctionArray = input->GetPointData()->GetArray(this->SizingFunctionArrayName); } if (this->UseSizingFunction && sizingFunctionArray) { tetgenOptionString += "m"; } tetgenio in_tetgenio; tetgenio out_tetgenio; in_tetgenio.firstnumber = 0; const int meshDimensionality = 3; //TODO: set this in_tetgenio.mesh_dim = meshDimensionality; //TODO - all point arrays except marker array in_tetgenio.pointattributelist = NULL; //REAL* in_tetgenio.numberofpointattributes = 0; //TODO in_tetgenio.pointmtrlist = NULL; in_tetgenio.numberofpointmtrs = 0; int numberOfPoints = input->GetNumberOfPoints(); in_tetgenio.numberofpoints = numberOfPoints; in_tetgenio.pointlist = new REAL[meshDimensionality * numberOfPoints]; #if 0 if (pointMarkerArray) { in_tetgenio.pointmarkerlist = new int[numberOfPoints]; } #endif if (sizingFunctionArray) { in_tetgenio.numberofpointmtrs = 1; in_tetgenio.pointmtrlist = new REAL[numberOfPoints]; } double point[3]; int i; for (i=0; iGetPoint(i,point); in_tetgenio.pointlist[meshDimensionality * i + 0] = point[0]; in_tetgenio.pointlist[meshDimensionality * i + 1] = point[1]; in_tetgenio.pointlist[meshDimensionality * i + 2] = point[2]; #if 0 if (pointMarkerArray) { in_tetgenio.pointmarkerlist[i] = static_cast(pointMarkerArray->GetComponent(i,0)); } else { in_tetgenio.pointmarkerlist[i] = 0; } #endif if (sizingFunctionArray) { in_tetgenio.pointmtrlist[i] = sizingFunctionArray->GetComponent(i,0); if (in_tetgenio.pointmtrlist[i] == 0.0) { in_tetgenio.pointmtrlist[i] = VTK_VMTK_FLOAT_TOL; } } } vtkIdList* facetCellIds = vtkIdList::New(); vtkIdList* tetraCellIds = vtkIdList::New(); int numberOfCells = input->GetNumberOfCells(); for (i=0; iGetCell(i); int cellType = cell->GetCellType(); switch (cellType) { case VTK_TRIANGLE: case VTK_QUADRATIC_TRIANGLE: case VTK_POLYGON: facetCellIds->InsertNextId(i); break; case VTK_TETRA: if (this->Order != 1) { vtkErrorMacro(<<"Element of incorrect order found."); break; } tetraCellIds->InsertNextId(i); break; case VTK_QUADRATIC_TETRA: if (this->Order != 2) { vtkErrorMacro(<<"Element of incorrect order found."); break; } tetraCellIds->InsertNextId(i); break; default: vtkErrorMacro(<<"Invalid element found, cellId "<GetNumberOfIds(); int numberOfTetras = tetraCellIds->GetNumberOfIds(); //TODO - input as vtkPointSet (point inside hole ([0],[1],[2])) in_tetgenio.holelist = NULL; //REAL* in_tetgenio.numberofholes = 0; //TODO if (numberOfFacets > 0) { in_tetgenio.numberoffacets = numberOfFacets; in_tetgenio.facetlist = new tetgenio::facet[numberOfFacets]; in_tetgenio.facetmarkerlist = new int[numberOfFacets]; vtkDataArray* facetMarkerArray = input->GetCellData()->GetArray(this->CellEntityIdsArrayName); for (i=0; iGetCellPoints(facetCellIds->GetId(i),npts,pts); in_tetgenio.facetlist[i].numberofpolygons = 1; in_tetgenio.facetlist[i].polygonlist = new tetgenio::polygon[in_tetgenio.facetlist[i].numberofpolygons]; in_tetgenio.facetlist[i].numberofholes = 0; in_tetgenio.facetlist[i].holelist = NULL; in_tetgenio.facetlist[i].polygonlist[0].numberofvertices = npts; in_tetgenio.facetlist[i].polygonlist[0].vertexlist = new int[npts]; for (int j=0; j(facetMarkerArray->GetComponent(facetCellIds->GetId(i),0)); } else { in_tetgenio.facetmarkerlist[i] = 0; } } } //TODO - all cell arrays except volume array in_tetgenio.tetrahedronattributelist = NULL; //REAL* in_tetgenio.numberoftetrahedronattributes = 0; //TODO if (numberOfTetras > 0) { vtkDataArray* tetrahedronVolumeArray = NULL; if (this->VarVolume) { tetrahedronVolumeArray = input->GetCellData()->GetArray(this->TetrahedronVolumeArrayName); } in_tetgenio.numberoftetrahedra = numberOfTetras; switch (this->Order) { case 1: in_tetgenio.numberofcorners = 4; break; case 2: in_tetgenio.numberofcorners = 10; break; default: in_tetgenio.numberofcorners = 0; break; } in_tetgenio.tetrahedronlist = new int[in_tetgenio.numberofcorners * numberOfTetras]; if (tetrahedronVolumeArray) { in_tetgenio.tetrahedronvolumelist = new REAL[numberOfTetras]; } for (i=0; iGetCellPoints(tetraCellIds->GetId(i),npts,pts); for (int j=0; jGetComponent(i,0); } } } facetCellIds->Delete(); tetraCellIds->Delete(); //TODO - input as vtkPointSet + arrays for attributes (point inside region ([0],[1],[2]), regional attribute [3], volume constraint [4]) in_tetgenio.regionlist = NULL; //REAL* in_tetgenio.numberofregions = 0; //TODO char tetgenOptions[512]; strcpy(tetgenOptions,tetgenOptionString.c_str()); cout<<"TetGen command line options: "<LastRunExitStatus = 1; return 1; } this->LastRunExitStatus = 0; //TODO // out_tetgenio.edgelist; //int* // out_tetgenio.edgemarkerlist; //int* // out_tetgenio.numberofedges; // out_tetgenio.neighborlist; //int* //TODO vtkPoints* outputPoints = vtkPoints::New(); outputPoints->SetNumberOfPoints(out_tetgenio.numberofpoints); for (i=0; iSetPoint(i,point); } output->SetPoints(outputPoints); vtkCellArray* outputCellArray = vtkCellArray::New(); int numberOfOutputCells = 0; if (this->OutputVolumeElements) { numberOfOutputCells += out_tetgenio.numberoftetrahedra; } if (this->OutputSurfaceElements) { numberOfOutputCells += out_tetgenio.numberoftrifaces; } int* outputCellTypes = new int[numberOfOutputCells]; vtkIntArray* outputCellMarkerArray = vtkIntArray::New(); outputCellMarkerArray->SetNumberOfTuples(numberOfOutputCells); outputCellMarkerArray->SetName(this->CellEntityIdsArrayName); outputCellMarkerArray->FillComponent(0,0.0); int cellIdOffset = 0; #if 1 if (this->OutputVolumeElements) { int outputCellType; switch (this->Order) { case 1: outputCellType = VTK_TETRA; break; case 2: outputCellType = VTK_QUADRATIC_TETRA; break; default: outputCellType = VTK_TETRA; } for (i=0; iInsertNextCell(out_tetgenio.numberofcorners); for (int j=0; jInsertCellPoint(out_tetgenio.tetrahedronlist[i*out_tetgenio.numberofcorners + j]); } outputCellTypes[cellIdOffset+i] = outputCellType; } cellIdOffset = out_tetgenio.numberoftetrahedra; } if (this->OutputSurfaceElements) { int outputCellType = VTK_TRIANGLE; int numberOfTrifaceCorners = 3; for (i=0; iInsertNextCell(numberOfTrifaceCorners); for (int j=0; jInsertCellPoint(out_tetgenio.trifacelist[i*numberOfTrifaceCorners + j]); } outputCellTypes[cellIdOffset+i] = outputCellType; outputCellMarkerArray->SetValue(cellIdOffset+i,out_tetgenio.trifacemarkerlist[i]); } cellIdOffset = out_tetgenio.numberoftrifaces; } #else if (this->OutputSurfaceElements) { int outputCellType = VTK_TRIANGLE; int numberOfTrifaceCorners = 3; for (i=0; iInsertNextCell(numberOfTrifaceCorners); for (int j=0; jInsertCellPoint(out_tetgenio.trifacelist[i*numberOfTrifaceCorners + j]); } outputCellTypes[cellIdOffset+i] = outputCellType; outputCellMarkerArray->SetValue(cellIdOffset+i,out_tetgenio.trifacemarkerlist[i]+1); } cellIdOffset = out_tetgenio.numberoftrifaces; } if (this->OutputVolumeElements) { int outputCellType; switch (this->Order) { case 1: outputCellType = VTK_TETRA; break; case 2: outputCellType = VTK_QUADRATIC_TETRA; break; default: outputCellType = VTK_TETRA; } for (i=0; iInsertNextCell(out_tetgenio.numberofcorners); for (int j=0; jInsertCellPoint(out_tetgenio.tetrahedronlist[i*out_tetgenio.numberofcorners + j]); } outputCellTypes[cellIdOffset+i] = outputCellType; } cellIdOffset = out_tetgenio.numberoftetrahedra; } #endif output->SetCells(outputCellTypes,outputCellArray); output->GetCellData()->AddArray(outputCellMarkerArray); outputPoints->Delete(); outputCellArray->Delete(); delete[] outputCellTypes; outputCellMarkerArray->Delete(); return 1; } void vtkvmtkTetGenWrapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSmoothCapPolyData.cxx0000664000175000017500000002112011757446472021212 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSmoothCapPolyData.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSmoothCapPolyData.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkPolyData.h" #include "vtkCellArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyLine.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkThinPlateSplineTransform.h" #include "vtkPoints.h" #include "vtkIdList.h" #include "vtkMath.h" #include "vtkTriangle.h" vtkCxxRevisionMacro(vtkvmtkSmoothCapPolyData, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkSmoothCapPolyData); vtkvmtkSmoothCapPolyData::vtkvmtkSmoothCapPolyData() { this->BoundaryIds = NULL; this->ConstraintFactor = 1.0; this->NumberOfRings = 8; } vtkvmtkSmoothCapPolyData::~vtkvmtkSmoothCapPolyData() { if (this->BoundaryIds) { this->BoundaryIds->Delete(); this->BoundaryIds = NULL; } } int vtkvmtkSmoothCapPolyData::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 ( input->GetNumberOfPoints() < 1 ) { return 1; } input->BuildCells(); input->BuildLinks(); vtkPoints* newPoints = vtkPoints::New(); newPoints->DeepCopy(input->GetPoints()); vtkCellArray* newPolys = vtkCellArray::New(); newPolys->DeepCopy(input->GetPolys()); vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(input); boundaryExtractor->Update(); vtkPolyData* boundaries = boundaryExtractor->GetOutput(); int boundaryId; for (boundaryId=0; boundaryIdGetNumberOfCells(); boundaryId++) { if (this->BoundaryIds) { if (this->BoundaryIds->IsId(boundaryId) == -1) { continue; } } vtkPolyLine* boundaryCell = vtkPolyLine::SafeDownCast(boundaries->GetCell(boundaryId)); int numberOfBoundaryPoints = boundaryCell->GetNumberOfPoints(); double boundaryDiagonal = sqrt(boundaryCell->GetLength2()); vtkIdList* boundaryPointIds = vtkIdList::New(); int i; for (i=0; i(boundaries->GetPointData()->GetScalars()->GetComponent(boundaryCell->GetPointId(i),0)); boundaryPointIds->InsertNextId(boundaryPointId); } vtkPoints* outerRingPoints = vtkPoints::New(); vtkIdList* pointCells = vtkIdList::New(); vtkIdList* cellPoints = vtkIdList::New(); for (i=0; iGetId(i); pointCells->Initialize(); input->GetPointCells(boundaryPointId,pointCells); double outerRingPoint[3]; outerRingPoint[0] = outerRingPoint[1] = outerRingPoint[2] = 0.0; double areaSum = 0.0; int j; for (j=0; jGetNumberOfIds(); j++) { vtkIdType cellId = pointCells->GetId(j); input->GetCellPoints(cellId,cellPoints); //TODO: assert cell is vtkTriangle double point0[3], point1[3], point2[3]; input->GetPoint(cellPoints->GetId(0),point0); input->GetPoint(cellPoints->GetId(1),point1); input->GetPoint(cellPoints->GetId(2),point2); double triangleCenter[3]; vtkTriangle::TriangleCenter(point0,point1,point2,triangleCenter); double triangleArea = vtkTriangle::TriangleArea(point0,point1,point2); outerRingPoint[0] += triangleArea * triangleCenter[0]; outerRingPoint[1] += triangleArea * triangleCenter[1]; outerRingPoint[2] += triangleArea * triangleCenter[2]; areaSum += triangleArea; } outerRingPoint[0] /= areaSum; outerRingPoint[1] /= areaSum; outerRingPoint[2] /= areaSum; double boundaryPoint[3]; input->GetPoint(boundaryPointId,boundaryPoint); double boundaryVector[3]; boundaryVector[0] = outerRingPoint[0] - boundaryPoint[0]; boundaryVector[1] = outerRingPoint[1] - boundaryPoint[1]; boundaryVector[2] = outerRingPoint[2] - boundaryPoint[2]; vtkMath::Normalize(boundaryVector); double distance = this->ConstraintFactor * 0.125 * boundaryDiagonal; outerRingPoint[0] = distance * boundaryVector[0] + boundaryPoint[0]; outerRingPoint[1] = distance * boundaryVector[1] + boundaryPoint[1]; outerRingPoint[2] = distance * boundaryVector[2] + boundaryPoint[2]; outerRingPoints->InsertNextPoint(outerRingPoint); } pointCells->Delete(); cellPoints->Delete(); vtkThinPlateSplineTransform* thinPlateSplineTransform = vtkThinPlateSplineTransform::New(); thinPlateSplineTransform->SetBasisToR2LogR(); thinPlateSplineTransform->SetSigma(1.0); vtkPoints* sourceLandmarks = vtkPoints::New(); vtkPoints* targetLandmarks = vtkPoints::New(); for (i=0; iInsertNextPoint(sourcePoint); targetLandmarks->InsertNextPoint(boundaryCell->GetPoints()->GetPoint(i)); double outerRingRadius = 1.25; sourcePoint[0] = outerRingRadius * cos(angle); sourcePoint[1] = outerRingRadius * sin(angle); sourcePoint[2] = 0.0; sourceLandmarks->InsertNextPoint(sourcePoint); targetLandmarks->InsertNextPoint(outerRingPoints->GetPoint(i)); } thinPlateSplineTransform->SetSourceLandmarks(sourceLandmarks); thinPlateSplineTransform->SetTargetLandmarks(targetLandmarks); outerRingPoints->Delete(); vtkIdList* circlePointIds = vtkIdList::New(); vtkIdList* previousCirclePointIds = vtkIdList::New(); circlePointIds->DeepCopy(boundaryPointIds); int k; for (k=1; kNumberOfRings; k++) { previousCirclePointIds->DeepCopy(circlePointIds); circlePointIds->Initialize(); for (i=0; iNumberOfRings; double sourcePoint[3]; sourcePoint[0] = radius * cos(angle); sourcePoint[1] = radius * sin(angle); sourcePoint[2] = 0.0; double transformedPoint[3]; thinPlateSplineTransform->TransformPoint(sourcePoint,transformedPoint); vtkIdType circlePointId = newPoints->InsertNextPoint(transformedPoint); circlePointIds->InsertNextId(circlePointId); } for (i=0; iInsertNextId(previousCirclePointIds->GetId(i)); newPolyIds->InsertNextId(previousCirclePointIds->GetId((i+1)%numberOfBoundaryPoints)); newPolyIds->InsertNextId(circlePointIds->GetId((i+1)%numberOfBoundaryPoints)); newPolyIds->InsertNextId(circlePointIds->GetId(i)); newPolys->InsertNextCell(newPolyIds); newPolyIds->Delete(); } } newPolys->InsertNextCell(circlePointIds); boundaryPointIds->Delete(); circlePointIds->Delete(); previousCirclePointIds->Delete(); thinPlateSplineTransform->Delete(); sourceLandmarks->Delete(); targetLandmarks->Delete(); } output->SetPoints(newPoints); output->SetPolys(newPolys); boundaryExtractor->Delete(); newPoints->Delete(); newPolys->Delete(); return 1; } void vtkvmtkSmoothCapPolyData::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkIterativeClosestPointTransform.cxx0000664000175000017500000002033111757446472024061 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkIterativeClosestPointTransform.cxx,v $ Language: C++ Date: $Date: 2010/05/30 11:32:56 $ Version: $Revision: 1.0 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkIterativeClosestPointTransform.h" #include "vtkDataSet.h" #include "vtkCellLocator.h" #include "vtkPoints.h" #include "vtkTransform.h" #include "vtkLandmarkTransform.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkIterativeClosestPointTransform, "$Revision: 1.0 $"); vtkStandardNewMacro(vtkvmtkIterativeClosestPointTransform); vtkvmtkIterativeClosestPointTransform::vtkvmtkIterativeClosestPointTransform() { this->FarThreshold = 1.0; this->UseFarThreshold = 0; } vtkvmtkIterativeClosestPointTransform::~vtkvmtkIterativeClosestPointTransform() { } void vtkvmtkIterativeClosestPointTransform::InternalUpdate() { // Check source, target if (this->Source == NULL || !this->Source->GetNumberOfPoints()) { vtkErrorMacro(<<"Can't execute with NULL or empty input"); return; } if (this->Target == NULL || !this->Target->GetNumberOfPoints()) { vtkErrorMacro(<<"Can't execute with NULL or empty target"); return; } // Create locator this->CreateDefaultLocator(); this->Locator->SetDataSet(this->Target); this->Locator->SetNumberOfCellsPerBucket(1); this->Locator->BuildLocator(); // Create two sets of points to handle iteration int step = 1; if (this->Source->GetNumberOfPoints() > this->MaximumNumberOfLandmarks) { step = this->Source->GetNumberOfPoints() / this->MaximumNumberOfLandmarks; vtkDebugMacro(<< "Landmarks step is now : " << step); } vtkIdType nb_points = this->Source->GetNumberOfPoints() / step; // Allocate some points. // - closestp is used so that the internal state of LandmarkTransform remains // correct whenever the iteration process is stopped (hence its source // and landmark points might be used in a vtkThinPlateSplineTransform). // - points2 could have been avoided, but do not ask me why // InternalTransformPoint is not working correctly on my computer when // in and out are the same pointer. vtkPoints *points1 = vtkPoints::New(); points1->SetNumberOfPoints(nb_points); vtkPoints *closestp = vtkPoints::New(); closestp->SetNumberOfPoints(nb_points); vtkPoints *points2 = vtkPoints::New(); points2->SetNumberOfPoints(nb_points); // Fill with initial positions (sample dataset using step) vtkTransform *accumulate = vtkTransform::New(); accumulate->PostMultiply(); vtkIdType i; int j; double p1[3], p2[3]; if (StartByMatchingCentroids) { double source_centroid[3] = {0,0,0}; for (i = 0; i < this->Source->GetNumberOfPoints(); i++) { this->Source->GetPoint(i, p1); source_centroid[0] += p1[0]; source_centroid[1] += p1[1]; source_centroid[2] += p1[2]; } source_centroid[0] /= this->Source->GetNumberOfPoints(); source_centroid[1] /= this->Source->GetNumberOfPoints(); source_centroid[2] /= this->Source->GetNumberOfPoints(); double target_centroid[3] = {0,0,0}; for (i = 0; i < this->Target->GetNumberOfPoints(); i++) { this->Target->GetPoint(i, p2); target_centroid[0] += p2[0]; target_centroid[1] += p2[1]; target_centroid[2] += p2[2]; } target_centroid[0] /= this->Target->GetNumberOfPoints(); target_centroid[1] /= this->Target->GetNumberOfPoints(); target_centroid[2] /= this->Target->GetNumberOfPoints(); accumulate->Translate(target_centroid[0] - source_centroid[0], target_centroid[1] - source_centroid[1], target_centroid[2] - source_centroid[2]); accumulate->Update(); for (i = 0, j = 0; i < nb_points; i++, j += step) { double outPoint[3]; accumulate->InternalTransformPoint(this->Source->GetPoint(j), outPoint); points1->SetPoint(i, outPoint); } } else { for (i = 0, j = 0; i < nb_points; i++, j += step) { points1->SetPoint(i, this->Source->GetPoint(j)); } } // Go vtkIdType cell_id; int sub_id; double dist2, totaldist = 0; double outPoint[3]; vtkPoints *temp, *a = points1, *b = points2; this->NumberOfIterations = 0; double tooFarThreshold2 = this->FarThreshold * this->FarThreshold; do { // Fill points with the closest points to each vertex in input if (!this->UseFarThreshold) { closestp->SetNumberOfPoints(nb_points); // It was set above, but at this point it should be removed from there for(i = 0; i < nb_points; i++) { this->Locator->FindClosestPoint(a->GetPoint(i), outPoint, cell_id, sub_id, dist2); closestp->SetPoint(i, outPoint); } this->LandmarkTransform->SetSourceLandmarks(a); } else //use a FarThreshold { vtkPoints* sourceLandmarks = vtkPoints::New(); closestp->Initialize(); for(i = 0; i < nb_points; i++) { this->Locator->FindClosestPoint(a->GetPoint(i), outPoint, cell_id, sub_id, dist2); if(dist2 < tooFarThreshold2) { closestp->InsertNextPoint(outPoint); sourceLandmarks->InsertNextPoint(a->GetPoint(i)); } } this->LandmarkTransform->SetSourceLandmarks(sourceLandmarks); sourceLandmarks->Delete(); } // Build the landmark transform this->LandmarkTransform->SetTargetLandmarks(closestp); this->LandmarkTransform->Update(); // Concatenate (can't use this->Concatenate directly) accumulate->Concatenate(this->LandmarkTransform->GetMatrix()); this->NumberOfIterations++; vtkDebugMacro(<< "Iteration: " << this->NumberOfIterations); if (this->NumberOfIterations >= this->MaximumNumberOfIterations) { break; } // Move mesh and compute mean distance if needed if (this->CheckMeanDistance) { totaldist = 0.0; } for(i = 0; i < nb_points; i++) { a->GetPoint(i, p1); this->LandmarkTransform->InternalTransformPoint(p1, p2); b->SetPoint(i, p2); if (this->CheckMeanDistance) { if (this->MeanDistanceMode == VTK_ICP_MODE_RMS) { totaldist += vtkMath::Distance2BetweenPoints(p1, p2); } else { totaldist += sqrt(vtkMath::Distance2BetweenPoints(p1, p2)); } } } if (this->CheckMeanDistance) { if (this->MeanDistanceMode == VTK_ICP_MODE_RMS) { this->MeanDistance = sqrt(totaldist / (double)nb_points); } else { this->MeanDistance = totaldist / (double)nb_points; } vtkDebugMacro("Mean distance: " << this->MeanDistance); if (this->MeanDistance <= this->MaximumMeanDistance) { break; } } temp = a; a = b; b = temp; } while (1); // Now recover accumulated result this->Matrix->DeepCopy(accumulate->GetMatrix()); accumulate->Delete(); points1->Delete(); closestp->Delete(); points2->Delete(); } void vtkvmtkIterativeClosestPointTransform::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "FarThreshold: " << this->FarThreshold << "\n"; os << indent << "UseFarThreshold: " << this->UseFarThreshold << "\n"; } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSurfaceProjection.cxx0000664000175000017500000000753511757446472021322 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfaceProjection.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSurfaceProjection.h" #include "vtkCellLocator.h" #include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSurfaceProjection, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkSurfaceProjection); vtkvmtkSurfaceProjection::vtkvmtkSurfaceProjection() { this->ReferenceSurface = NULL; } vtkvmtkSurfaceProjection::~vtkvmtkSurfaceProjection() { if (this->ReferenceSurface) { this->ReferenceSurface->Delete(); this->ReferenceSurface = NULL; } } int vtkvmtkSurfaceProjection::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; vtkIdType cellId; int subId; double point[3], closestPoint[3]; double pcoords[3]; double distance2; vtkCellLocator *locator; vtkGenericCell *genericCell; if (!this->ReferenceSurface) { vtkErrorMacro(<<"No reference surface!"); return 1; } int numberOfPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkPointData* outputPointData = output->GetPointData(); vtkPointData* referencePointData = this->ReferenceSurface->GetPointData(); outputPointData->InterpolateAllocate(referencePointData,numberOfPoints); this->ReferenceSurface->BuildCells(); locator = vtkCellLocator::New(); genericCell = vtkGenericCell::New(); locator->SetDataSet(this->ReferenceSurface); locator->BuildLocator(); for (i=0; iGetPoint(i,point); locator->FindClosestPoint(point,closestPoint,genericCell,cellId,subId,distance2); if (this->ReferenceSurface->GetCellType(cellId) != VTK_POLY_LINE) { double* weights = new double[genericCell->GetNumberOfPoints()]; genericCell->EvaluatePosition(closestPoint,NULL,subId,pcoords,distance2,weights); outputPointData->InterpolatePoint(referencePointData,i,genericCell->GetPointIds(),weights); delete[] weights; } else { double testPoint0[3], testPoint1[3]; vtkIdType pointId = genericCell->GetPointId(subId); input->GetPoint(genericCell->GetPointId(subId),testPoint0); input->GetPoint(genericCell->GetPointId(subId+1),testPoint1); if (vtkMath::Distance2BetweenPoints(closestPoint,testPoint1) < vtkMath::Distance2BetweenPoints(closestPoint,testPoint0)) { pointId = genericCell->GetPointId(subId+1); } outputPointData->CopyData(referencePointData,pointId,i); } } locator->Delete(); genericCell->Delete(); return 1; } void vtkvmtkSurfaceProjection::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSurfMeshWrapper.h0000664000175000017500000000323411757446472020407 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfMeshWrapper.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSurfMeshWrapper - Converts linear elements to quadratic. // .SECTION Description // ... #ifndef __vtkvmtkSurfMeshWrapper_h #define __vtkvmtkSurfMeshWrapper_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkSurfMeshWrapper : public vtkPolyDataAlgorithm { public: static vtkvmtkSurfMeshWrapper *New(); vtkTypeRevisionMacro(vtkvmtkSurfMeshWrapper,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); vtkSetMacro(NodeSpacing,double); vtkGetMacro(NodeSpacing,double); protected: vtkvmtkSurfMeshWrapper(); ~vtkvmtkSurfMeshWrapper(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); double NodeSpacing; private: vtkvmtkSurfMeshWrapper(const vtkvmtkSurfMeshWrapper&); // Not implemented. void operator=(const vtkvmtkSurfMeshWrapper&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkIterativeClosestPointTransform.h0000664000175000017500000000467511757446472023523 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkIterativeClosestPointTransform.h,v $ Language: C++ Date: $Date: 2010/05/30 11:29:48 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkIterativeClosestPointTransform - Implementation of the ICP algorithm with FarThreshold variant. // .SECTION Description // #ifndef __vtkvmtkIterativeClosestPointTransform_h #define __vtkvmtkIterativeClosestPointTransform_h #include "vtkIterativeClosestPointTransform.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkIterativeClosestPointTransform : public vtkIterativeClosestPointTransform { public: static vtkvmtkIterativeClosestPointTransform *New(); vtkTypeRevisionMacro(vtkvmtkIterativeClosestPointTransform,vtkIterativeClosestPointTransform); void PrintSelf(ostream& os, vtkIndent indent); // Description: // Set/Get the threshold to declare a point to not have a corresponding // point in the other point set. This value is only used if // UseFarThreshold is True (not the default). // This is useful to align partially overlapping surfaces. // If this value is negative, all points are considered to have a // corresponding point in the other point set. // The default is 1.0. vtkSetMacro(FarThreshold,double); vtkGetMacro(FarThreshold,double); // Description: // Determine whether or not to use the FarThreshold. // The default is 0. vtkSetMacro(UseFarThreshold,int); vtkGetMacro(UseFarThreshold,int); vtkBooleanMacro(UseFarThreshold,int); protected: vtkvmtkIterativeClosestPointTransform(); ~vtkvmtkIterativeClosestPointTransform(); void InternalUpdate(); double FarThreshold; int UseFarThreshold; private: vtkvmtkIterativeClosestPointTransform(const vtkvmtkIterativeClosestPointTransform&); // Not implemented. void operator=(const vtkvmtkIterativeClosestPointTransform&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSurfaceDistance.h0000664000175000017500000000467611757446472020370 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfaceDistance.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSurfaceDistance - ... // .SECTION Description // . #ifndef __vtkvmtkSurfaceDistance_h #define __vtkvmtkSurfaceDistance_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class VTK_VMTK_MISC_EXPORT vtkvmtkSurfaceDistance : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkSurfaceDistance,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSurfaceDistance *New(); // Description: // Set/Get the name of the array where the computed distance has to be stored. vtkSetStringMacro(DistanceArrayName); vtkGetStringMacro(DistanceArrayName); // Description: // Set/Get the name of the array where the computed distance has to be stored. vtkSetStringMacro(SignedDistanceArrayName); vtkGetStringMacro(SignedDistanceArrayName); // Description: // Set/Get the name of the array where the computed distance vectors have to be stored. vtkSetStringMacro(DistanceVectorsArrayName); vtkGetStringMacro(DistanceVectorsArrayName); // Description: // Set/Get the reference surface to compute distance from. vtkSetObjectMacro(ReferenceSurface,vtkPolyData); vtkGetObjectMacro(ReferenceSurface,vtkPolyData); protected: vtkvmtkSurfaceDistance(); ~vtkvmtkSurfaceDistance(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char *DistanceArrayName; char *DistanceVectorsArrayName; char *SignedDistanceArrayName; vtkPolyData *ReferenceSurface; private: vtkvmtkSurfaceDistance(const vtkvmtkSurfaceDistance&); // Not implemented. void operator=(const vtkvmtkSurfaceDistance&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLevelSetSigmoidFilter.h0000664000175000017500000000413611757446472021521 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLevelSetSigmoidFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // . #ifndef __vtkvmtkLevelSetSigmoidFilter_h #define __vtkvmtkLevelSetSigmoidFilter_h #include "vtkSimpleImageToImageFilter.h" #include "vtkImageData.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkLevelSetSigmoidFilter : public vtkSimpleImageToImageFilter { public: vtkTypeRevisionMacro(vtkvmtkLevelSetSigmoidFilter,vtkSimpleImageToImageFilter); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkLevelSetSigmoidFilter *New(); vtkSetObjectMacro(LevelSetsImage,vtkImageData); vtkGetObjectMacro(LevelSetsImage,vtkImageData); vtkSetMacro(Sigma,double); vtkGetMacro(Sigma,double); vtkSetMacro(ScaleValue,double); vtkGetMacro(ScaleValue,double); vtkSetMacro(ComputeScaleValueFromInput,int); vtkGetMacro(ComputeScaleValueFromInput,int); vtkBooleanMacro(ComputeScaleValueFromInput,int); protected: vtkvmtkLevelSetSigmoidFilter(); ~vtkvmtkLevelSetSigmoidFilter(); virtual void SimpleExecute(vtkImageData* input, vtkImageData* output); vtkImageData *LevelSetsImage; double Sigma; double ScaleValue; int ComputeScaleValueFromInput; private: vtkvmtkLevelSetSigmoidFilter(const vtkvmtkLevelSetSigmoidFilter&); // Not implemented. void operator=(const vtkvmtkLevelSetSigmoidFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshVelocityStatistics.cxx0000664000175000017500000001234711757446472022360 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshVelocityStatistics.cxx,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMeshVelocityStatistics.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMeshVelocityStatistics, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkMeshVelocityStatistics); vtkvmtkMeshVelocityStatistics::vtkvmtkMeshVelocityStatistics() { this->VelocityArrayIds = NULL; } vtkvmtkMeshVelocityStatistics::~vtkvmtkMeshVelocityStatistics() { if (this->VelocityArrayIds) { this->VelocityArrayIds->Delete(); this->VelocityArrayIds = NULL; } } int vtkvmtkMeshVelocityStatistics::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())); output->CopyStructure(input); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); vtkPointData* inputPointData = input->GetPointData(); if (this->VelocityArrayIds == NULL) { vtkErrorMacro("No VelocityArrayIds specified"); return 1; } int numberOfArrayIds = this->VelocityArrayIds->GetNumberOfIds(); if (numberOfArrayIds < 2) { vtkWarningMacro("Only 1 VelocityArrayIds specified. No point in computing statistics."); return 1; } int i; for (i=0; iGetArray(this->VelocityArrayIds->GetId(i)) == NULL) { vtkErrorMacro("Id in VelocityArrayIds is not a PointData array."); return 1; } } int numberOfPoints = input->GetNumberOfPoints(); vtkDoubleArray* avgVelocityArray = vtkDoubleArray::New(); avgVelocityArray->SetName("AVGVelocity"); avgVelocityArray->SetNumberOfComponents(3); avgVelocityArray->SetNumberOfTuples(numberOfPoints); avgVelocityArray->FillComponent(0,0.0); avgVelocityArray->FillComponent(1,0.0); avgVelocityArray->FillComponent(2,0.0); vtkDoubleArray* rmsVelocityArray = vtkDoubleArray::New(); rmsVelocityArray->SetName("RMSVelocity"); rmsVelocityArray->SetNumberOfComponents(3); rmsVelocityArray->SetNumberOfTuples(numberOfPoints); rmsVelocityArray->FillComponent(0,0.0); rmsVelocityArray->FillComponent(1,0.0); rmsVelocityArray->FillComponent(2,0.0); double avgVelocity[3], rmsVelocity[3], velocity[3]; double weight = 1.0 / double(numberOfArrayIds); int j; for (i=0; iGetArray(this->VelocityArrayIds->GetId(j)); avgVelocityArray->GetTuple(i,avgVelocity); velocityArray->GetTuple(i,velocity); avgVelocity[0] += weight * velocity[0]; avgVelocity[1] += weight * velocity[1]; avgVelocity[2] += weight * velocity[2]; avgVelocityArray->SetTuple(i,avgVelocity); } } for (i=0; iGetArray(this->VelocityArrayIds->GetId(j)); rmsVelocityArray->GetTuple(i,rmsVelocity); avgVelocityArray->GetTuple(i,avgVelocity); velocityArray->GetTuple(i,velocity); rmsVelocity[0] += weight * (velocity[0] - avgVelocity[0]) * (velocity[0] - avgVelocity[0]); rmsVelocity[1] += weight * (velocity[1] - avgVelocity[1]) * (velocity[1] - avgVelocity[1]); rmsVelocity[2] += weight * (velocity[2] - avgVelocity[2]) * (velocity[2] - avgVelocity[2]); rmsVelocityArray->SetTuple(i,rmsVelocity); } } for (i=0; iGetTuple(i,rmsVelocity); rmsVelocity[0] = sqrt(rmsVelocity[0]); rmsVelocity[1] = sqrt(rmsVelocity[1]); rmsVelocity[2] = sqrt(rmsVelocity[2]); rmsVelocityArray->SetTuple(i,rmsVelocity); } output->GetPointData()->AddArray(avgVelocityArray); output->GetPointData()->AddArray(rmsVelocityArray); avgVelocityArray->Delete(); rmsVelocityArray->Delete(); return 1; } void vtkvmtkMeshVelocityStatistics::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStreamlineToParticlesFilter.cxx0000664000175000017500000001520211757446472023306 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStreamlineToParticlesFilter.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkStreamlineToParticlesFilter.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkMaskPolyData.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkIdList.h" #include "vtkPolyLine.h" #include "vtkDoubleArray.h" #include "vtkCellArray.h" vtkCxxRevisionMacro(vtkvmtkStreamlineToParticlesFilter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkStreamlineToParticlesFilter); vtkvmtkStreamlineToParticlesFilter::vtkvmtkStreamlineToParticlesFilter() { this->NumberOfInjections = 10; this->NumberOfParticlesPerInjection = 10; this->InjectionStart = 0.0; this->InjectionEnd = 1.0; this->TracingEnd = 1.0; this->DeltaT = 1E-2; this->IntegrationTimeArrayName = NULL; this->TimeArrayName = NULL; this->VelocityArrayName = NULL; } vtkvmtkStreamlineToParticlesFilter::~vtkvmtkStreamlineToParticlesFilter() { if (this->IntegrationTimeArrayName) { delete[] this->IntegrationTimeArrayName; this->IntegrationTimeArrayName = NULL; } if (this->TimeArrayName) { delete[] this->TimeArrayName; this->TimeArrayName = NULL; } if (this->VelocityArrayName) { delete[] this->VelocityArrayName; this->VelocityArrayName = NULL; } } int vtkvmtkStreamlineToParticlesFilter::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 (input->GetNumberOfPoints() < 1) { return 1; } if (!this->IntegrationTimeArrayName) { vtkErrorMacro("Error: IntegrationTimeArrayName not specified"); return 1; } vtkDataArray* integrationTimeArray = input->GetPointData()->GetArray(this->IntegrationTimeArrayName); if (!integrationTimeArray) { vtkErrorMacro("Error: IntegrationTimeArray with name specified does not exist"); return 1; } vtkDataArray* velocityArray = NULL; if (this->VelocityArrayName) { velocityArray = input->GetPointData()->GetArray(this->VelocityArrayName); if (!velocityArray) { vtkErrorMacro("Error: VelocityArray with name specified does not exist"); return 1; } } int numberOfCells = input->GetNumberOfCells(); vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputVerts = vtkCellArray::New(); vtkDoubleArray* outputTimeArray = vtkDoubleArray::New(); outputTimeArray->SetName(this->TimeArrayName); vtkDoubleArray* outputVelocityArray = vtkDoubleArray::New(); outputVelocityArray->SetName(this->VelocityArrayName); outputVelocityArray->SetNumberOfComponents(3); int i; for (i=0; iNumberOfInjections; i++) { double injectionOffset = this->InjectionStart + i * (this->InjectionEnd - this->InjectionStart) / this->NumberOfInjections; vtkMaskPolyData* mask = vtkMaskPolyData::New(); mask->SetInput(input); mask->SetOnRatio(numberOfCells/this->NumberOfParticlesPerInjection); mask->SetOffset(i); mask->Update(); mask->GetOutput()->GetPointData()->SetActiveScalars(this->IntegrationTimeArrayName); vtkPolyData* subset = mask->GetOutput(); int numberOfSubsetCells = subset->GetNumberOfCells(); int j; for (j=0; jGetCell(j)); if (!polyLine) { continue; } vtkIdList* pointIds = polyLine->GetPointIds(); int numberOfPointIds = pointIds->GetNumberOfIds(); double integrationTime = injectionOffset; int k; for (k=0; kGetTuple1(pointIds->GetId(k)); double time1 = integrationTimeArray->GetTuple1(pointIds->GetId(k+1)); if (time0 < integrationTime && time1 < integrationTime) { continue; } if (time0 > integrationTime && time1 > integrationTime) { break; } bool valid = true; while (valid) { double pcoord = (integrationTime - time0) / (time1 - time0); double interpolatedPoint[3]; vtkvmtkCenterlineUtilities::InterpolatePoint(subset,j,k,pcoord,interpolatedPoint); vtkIdType pointId = outputPoints->InsertNextPoint(interpolatedPoint); outputVerts->InsertNextCell(1); outputVerts->InsertCellPoint(pointId); outputTimeArray->InsertNextValue(integrationTime + injectionOffset); if (velocityArray) { double velocity[3]; vtkvmtkCenterlineUtilities::InterpolateTuple3(subset,this->VelocityArrayName,j,k,pcoord,velocity); outputVelocityArray->InsertNextTuple(velocity); } integrationTime += this->DeltaT; if (integrationTime > time1) { valid = false; } if (integrationTime + injectionOffset > this->TracingEnd) { break; } } if (integrationTime + injectionOffset > this->TracingEnd) { break; } } } } output->SetPoints(outputPoints); output->SetVerts(outputVerts); output->GetPointData()->AddArray(outputTimeArray); if (velocityArray) { output->GetPointData()->AddArray(outputVelocityArray); } outputPoints->Delete(); outputVerts->Delete(); outputTimeArray->Delete(); if (velocityArray) { outputVelocityArray->Delete(); } return 1; } void vtkvmtkStreamlineToParticlesFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataBoundaryExtractor.h0000664000175000017500000000366011757446472022432 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBoundaryExtractor.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataBoundaryExtractor - Extract boundary edges as poly lines. // .SECTION Description // This class identifies boundary edges and organizes them into poly lines based on connectivity. It also provides the output with a point data vtkIdTypeArray (set as active scalars) in which the ids of boundary points in the input dataset are stored. #ifndef __vtkvmtkPolyDataBoundaryExtractor_h #define __vtkvmtkPolyDataBoundaryExtractor_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkPolyDataBoundaryExtractor : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataBoundaryExtractor,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataBoundaryExtractor *New(); protected: vtkvmtkPolyDataBoundaryExtractor(); ~vtkvmtkPolyDataBoundaryExtractor() {} virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); private: vtkvmtkPolyDataBoundaryExtractor(const vtkvmtkPolyDataBoundaryExtractor&); // Not implemented. void operator=(const vtkvmtkPolyDataBoundaryExtractor&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSimpleCapPolyData.cxx0000664000175000017500000001057411757446472021205 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSimpleCapPolyData.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSimpleCapPolyData.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkPolyData.h" #include "vtkCellArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyLine.h" #include "vtkIntArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSimpleCapPolyData, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkSimpleCapPolyData); vtkvmtkSimpleCapPolyData::vtkvmtkSimpleCapPolyData() { this->CellEntityIdsArrayName = NULL; this->BoundaryIds = NULL; this->CellEntityIdOffset = 1; } vtkvmtkSimpleCapPolyData::~vtkvmtkSimpleCapPolyData() { if (this->CellEntityIdsArrayName) { delete[] this->CellEntityIdsArrayName; this->CellEntityIdsArrayName = NULL; } if (this->BoundaryIds) { this->BoundaryIds->Delete(); this->BoundaryIds = NULL; } } int vtkvmtkSimpleCapPolyData::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 ( input->GetNumberOfPoints() < 1 ) { return 1; } bool markCells = true; if (!this->CellEntityIdsArrayName) { markCells = false; } if (strcmp(this->CellEntityIdsArrayName,"") == 0) { markCells = false; } input->BuildLinks(); vtkPoints* newPoints = vtkPoints::New(); newPoints->DeepCopy(input->GetPoints()); vtkCellArray* newPolys = vtkCellArray::New(); newPolys->DeepCopy(input->GetPolys()); vtkIntArray* cellEntityIdsArray = NULL; if (markCells) { cellEntityIdsArray = vtkIntArray::New(); cellEntityIdsArray->SetName(this->CellEntityIdsArrayName); cellEntityIdsArray->SetNumberOfTuples(newPolys->GetNumberOfCells()); cellEntityIdsArray->FillComponent(0,static_cast(this->CellEntityIdOffset)); } vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(input); boundaryExtractor->Update(); vtkPolyData* boundaries = boundaryExtractor->GetOutput(); for (int i=0; iGetNumberOfCells(); i++) { if (this->BoundaryIds) { if (this->BoundaryIds->IsId(i) == -1) { continue; } } vtkPolyLine* boundary = vtkPolyLine::SafeDownCast(boundaries->GetCell(i)); vtkIdType numberOfBoundaryPoints = boundary->GetNumberOfPoints(); vtkIdList* boundaryPointIds = vtkIdList::New(); boundaryPointIds->SetNumberOfIds(numberOfBoundaryPoints); for (int j=0; jSetId(j,static_cast(boundaries->GetPointData()->GetScalars()->GetTuple1(boundary->GetPointId(j)))); } newPolys->InsertNextCell(boundaryPointIds); if (markCells) { cellEntityIdsArray->InsertNextValue(i+1+this->CellEntityIdOffset); } boundaryPointIds->Delete(); } output->SetPoints(newPoints); output->SetPolys(newPolys); output->GetPointData()->PassData(input->GetPointData()); if (markCells) { output->GetCellData()->AddArray(cellEntityIdsArray); cellEntityIdsArray->Delete(); } newPoints->Delete(); newPolys->Delete(); boundaryExtractor->Delete(); return 1; } void vtkvmtkSimpleCapPolyData::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkRBFInterpolation.h0000664000175000017500000000475611757446472020505 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkRBFInterpolation.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkRBFInterpolation - // .SECTION Description // .. #ifndef __vtkvmtkRBFInterpolation_h #define __vtkvmtkRBFInterpolation_h #include "vtkImplicitFunction.h" #include "vtkPolyData.h" #include "vtkDoubleArray.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkRBFInterpolation : public vtkImplicitFunction { public: vtkTypeRevisionMacro(vtkvmtkRBFInterpolation,vtkImplicitFunction); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkRBFInterpolation *New(); // Description // Evaluate polyball. double EvaluateFunction(double x[3]); double EvaluateFunction(double x, double y, double z) {return this->vtkImplicitFunction::EvaluateFunction(x, y, z); } ; // Description // Evaluate polyball gradient. void EvaluateGradient(double x[3], double n[3]); void ComputeCoefficients(); // Description: // Set / get source poly data. vtkSetObjectMacro(Source,vtkPolyData); vtkGetObjectMacro(Source,vtkPolyData); vtkSetMacro(RBFType,int); vtkGetMacro(RBFType,int); void SetRBFTypeToThinPlateSpline() { this->SetRBFType(THIN_PLATE_SPLINE); } void SetRBFTypeToBiharmonic() { this->SetRBFType(BIHARMONIC); } void SetRBFTypeToTriharmonic() { this->SetRBFType(TRIHARMONIC); } //BTX enum { THIN_PLATE_SPLINE, BIHARMONIC, TRIHARMONIC }; //ETX unsigned long GetMTime(); protected: vtkvmtkRBFInterpolation(); ~vtkvmtkRBFInterpolation(); double EvaluateRBF(double c[3], double x[3]); vtkPolyData* Source; int RBFType; vtkDoubleArray* Coefficients; double RBFInterpolationValue; private: vtkvmtkRBFInterpolation(const vtkvmtkRBFInterpolation&); // Not implemented. void operator=(const vtkvmtkRBFInterpolation&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkBoundaryLayerGenerator.h0000664000175000017500000000664111757446472021746 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryLayerGenerator.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkDataArray; class VTK_VMTK_MISC_EXPORT vtkvmtkBoundaryLayerGenerator : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkBoundaryLayerGenerator,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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(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); vtkGetObjectMacro(InnerSurface,vtkUnstructuredGrid); protected: vtkvmtkBoundaryLayerGenerator(); ~vtkvmtkBoundaryLayerGenerator(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void WarpPoints(vtkPoints* inputPoints, vtkPoints* warpedPoints, int subLayerId, bool quadratic); vtkDataArray* WarpVectorsArray; vtkDataArray* LayerThicknessArray; int UseWarpVectorMagnitudeAsThickness; int ConstantThickness; char* WarpVectorsArrayName; char* LayerThicknessArrayName; double LayerThickness; double LayerThicknessRatio; double MaximumLayerThickness; int NumberOfSubLayers; double SubLayerRatio; int IncludeSurfaceCells; int NegateWarpVectors; vtkUnstructuredGrid* InnerSurface; private: vtkvmtkBoundaryLayerGenerator(const vtkvmtkBoundaryLayerGenerator&); // Not implemented. void operator=(const vtkvmtkBoundaryLayerGenerator&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkCurvedMPRImageFilter.h0000664000175000017500000001024611757446472021233 0ustar lucaluca// Note: this class was contributed by // Hugo Gratama van Andel // Academic Medical Centre - University of Amsterdam // Dept. Biomedical Engineering & Physics #ifndef __vtkvmtkCurvedMPRImageFilter_h #define __vtkvmtkCurvedMPRImageFilter_h #include "vtkImageAlgorithm.h" #include "vtkvmtkWin32Header.h" #include "vtkImageData.h" #include "vtkImageChangeInformation.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkTransform.h" #include "vtkImageReslice.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkCell.h" #include "vtkMath.h" class VTK_VMTK_MISC_EXPORT vtkvmtkCurvedMPRImageFilter : public vtkImageAlgorithm { public: static vtkvmtkCurvedMPRImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkCurvedMPRImageFilter,vtkImageAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); // Description: // Set/Get the centerline along which the MPR should be made vtkSetObjectMacro(Centerline,vtkPolyData); vtkGetObjectMacro(Centerline,vtkPolyData); // Description: // Set/Get the Inplane Output Spacing vtkSetVector2Macro(InplaneOutputSpacing,double); vtkGetVector2Macro(InplaneOutputSpacing,double); // Description: // Set/Get the Inplane Output Size vtkSetVector2Macro(InplaneOutputSize,int); vtkGetVector2Macro(InplaneOutputSize,int); // Description: // Set/Get the Back Ground Level of the Resliced Data vtkSetMacro(ReslicingBackgroundLevel,double); vtkGetMacro(ReslicingBackgroundLevel,double); // Description: // Set/Get the name of the FrenetTangentArray vtkSetStringMacro(FrenetTangentArrayName); vtkGetStringMacro(FrenetTangentArrayName); // Description: // Set/Get the name of the TransportNormalsArray vtkSetStringMacro(ParallelTransportNormalsArrayName); vtkGetStringMacro(ParallelTransportNormalsArrayName); // Description: // Get the new OutputExtent, the inplane output extent is set by SetInplaneOutputSize, // the out-of-plane extent is defined by the number of centerline-points vtkGetVectorMacro(OutputExtent,int,6); // Description: // Get the output origin. The point (0,0,0) is situated in the middle of the first MPR image // (at the place of the centerline)The Output Origin is defined by // the InplaneOutputSpacing and the InplaneOutputSize vtkGetVectorMacro(OutputOrigin,double,3); // Description: // Get the output spacing, the inplane output spacing is set by SetInplaneOutputSpacing, // the out-of-plane spacing is defined by the distance between the first two centerline-points vtkGetVectorMacro(OutputSpacing,double,3); protected: vtkvmtkCurvedMPRImageFilter(); ~vtkvmtkCurvedMPRImageFilter(); //BTX template void FillSlice(T* outReslicePtr, T* outputImagePtr, int* resliceUpdateExtent, int* outExtent, vtkIdType* outputInc, int slice); //ETX // Description: // This method is called by the superclass and sets the update extent of the input image to the wholeextent virtual int RequestUpdateExtent (vtkInformation *, vtkInformationVector **, vtkInformationVector *); // Description: // This method is called by the superclass and performs the actual computation of the MPR image virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); // Description: // This method is called by the superclass and compute the output extent, origin and spacing virtual int RequestInformation (vtkInformation * vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector); vtkPolyData * Centerline; double InplaneOutputSpacing[2]; int InplaneOutputSize[2]; double ReslicingBackgroundLevel; int OutputExtent[6]; double OutputOrigin[3]; double OutputSpacing[3]; char * FrenetTangentArrayName; char * ParallelTransportNormalsArrayName; private: vtkvmtkCurvedMPRImageFilter(const vtkvmtkCurvedMPRImageFilter&); // Not implemented. void operator=(const vtkvmtkCurvedMPRImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshProjection.cxx0000664000175000017500000000640411757446472020620 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshProjection.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMeshProjection.h" #include "vtkCellLocator.h" #include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMeshProjection, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkMeshProjection); vtkvmtkMeshProjection::vtkvmtkMeshProjection() { this->ReferenceMesh = NULL; this->Tolerance = 1E-6; } vtkvmtkMeshProjection::~vtkvmtkMeshProjection() { if (this->ReferenceMesh) { this->ReferenceMesh->Delete(); this->ReferenceMesh = NULL; } } int vtkvmtkMeshProjection::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())); vtkIdType i; vtkIdType cellId; int subId; double point[3], closestPoint[3]; double pcoords[3]; double distance2; vtkCellLocator *locator; vtkGenericCell *genericCell; if (!this->ReferenceMesh) { vtkErrorMacro(<<"No reference mesh!"); return 1; } int numberOfPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkPointData* outputPointData = output->GetPointData(); vtkPointData* referencePointData = this->ReferenceMesh->GetPointData(); outputPointData->InterpolateAllocate(referencePointData,numberOfPoints); locator = vtkCellLocator::New(); genericCell = vtkGenericCell::New(); locator->SetDataSet(this->ReferenceMesh); locator->BuildLocator(); locator->SetTolerance(this->Tolerance); for (i=0; iGetPoint(i,point); locator->FindClosestPoint(point,closestPoint,genericCell,cellId,subId,distance2); double* weights = new double[genericCell->GetNumberOfPoints()]; genericCell->EvaluatePosition(closestPoint,NULL,subId,pcoords,distance2,weights); outputPointData->InterpolatePoint(referencePointData,i,genericCell->GetPointIds(),weights); delete[] weights; } locator->Delete(); genericCell->Delete(); return 1; } void vtkvmtkMeshProjection::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshWallShearRate.cxx0000664000175000017500000001221011757446472021172 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshWallShearRate.cxx,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMeshWallShearRate.h" #include "vtkvmtkUnstructuredGridGradientFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkGeometryFilter.h" #include "vtkPolyDataNormals.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMeshWallShearRate, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkMeshWallShearRate); vtkvmtkMeshWallShearRate::vtkvmtkMeshWallShearRate() { this->VelocityArrayName = NULL; this->WallShearRateArrayName = NULL; this->ComputeIndividualPartialDerivatives = 0; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; } vtkvmtkMeshWallShearRate::~vtkvmtkMeshWallShearRate() { if (this->VelocityArrayName) { delete[] this->VelocityArrayName; this->VelocityArrayName = NULL; } if (this->WallShearRateArrayName) { delete[] this->WallShearRateArrayName; this->WallShearRateArrayName = NULL; } } int vtkvmtkMeshWallShearRate::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkUnstructuredGrid"); return 1; } int vtkvmtkMeshWallShearRate::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())); vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); if (this->VelocityArrayName == NULL) { vtkErrorMacro("VelocityArrayName not specified"); return 1; } vtkDataArray* velocityArray = input->GetPointData()->GetArray(this->VelocityArrayName); if (velocityArray == NULL) { vtkErrorMacro("VelocityArray with name specified does not exist"); return 1; } char gradientArrayName[] = "VelocityGradient"; vtkvmtkUnstructuredGridGradientFilter* gradientFilter = vtkvmtkUnstructuredGridGradientFilter::New(); gradientFilter->SetInput(input); gradientFilter->SetInputArrayName(this->VelocityArrayName); gradientFilter->SetGradientArrayName(gradientArrayName); gradientFilter->SetQuadratureOrder(this->QuadratureOrder); gradientFilter->SetConvergenceTolerance(this->ConvergenceTolerance); gradientFilter->SetComputeIndividualPartialDerivatives(this->ComputeIndividualPartialDerivatives); gradientFilter->Update(); vtkGeometryFilter* geometryFilter = vtkGeometryFilter::New(); geometryFilter->SetInput(gradientFilter->GetOutput()); geometryFilter->Update(); vtkPolyDataNormals* normalsFilter = vtkPolyDataNormals::New(); normalsFilter->SetInput(geometryFilter->GetOutput()); normalsFilter->AutoOrientNormalsOn(); normalsFilter->ConsistencyOn(); normalsFilter->SplittingOff(); normalsFilter->Update(); vtkPolyData* outputSurface = normalsFilter->GetOutput(); vtkDataArray* velocityGradientArray = outputSurface->GetPointData()->GetArray(gradientArrayName); vtkDataArray* normalsArray = outputSurface->GetPointData()->GetNormals(); int numberOfPoints = outputSurface->GetNumberOfPoints(); vtkDoubleArray* wallShearRateArray = vtkDoubleArray::New(); if (this->WallShearRateArrayName) { wallShearRateArray->SetName(this->WallShearRateArrayName); } else { wallShearRateArray->SetName("WallShearRate"); } wallShearRateArray->SetNumberOfComponents(3); wallShearRateArray->SetNumberOfTuples(numberOfPoints); double velocityGradient[9]; double normal[3]; double wallShearRate[3]; int i, j; for (i=0; iGetTuple(i,velocityGradient); normalsArray->GetTuple(i,normal); for (j=0; j<3; j++) { wallShearRate[j] = -normal[0] * velocityGradient[3*j + 0] - normal[1] * velocityGradient[3*j + 1] - normal[2] * velocityGradient[3*j + 2]; } wallShearRateArray->SetTuple(i,wallShearRate); } output->DeepCopy(outputSurface); output->GetPointData()->AddArray(wallShearRateArray); wallShearRateArray->Delete(); geometryFilter->Delete(); normalsFilter->Delete(); return 1; } void vtkvmtkMeshWallShearRate::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshVorticity.cxx0000664000175000017500000001022011757446472020467 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshVorticity.cxx,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMeshVorticity.h" #include "vtkvmtkUnstructuredGridGradientFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMeshVorticity, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkMeshVorticity); vtkvmtkMeshVorticity::vtkvmtkMeshVorticity() { this->VelocityArrayName = NULL; this->VorticityArrayName = NULL; this->ComputeIndividualPartialDerivatives = 0; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; } vtkvmtkMeshVorticity::~vtkvmtkMeshVorticity() { if (this->VelocityArrayName) { delete[] this->VelocityArrayName; this->VelocityArrayName = NULL; } if (this->VorticityArrayName) { delete[] this->VorticityArrayName; this->VorticityArrayName = NULL; } } int vtkvmtkMeshVorticity::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())); if (this->VelocityArrayName == NULL) { vtkErrorMacro("VelocityArrayName not specified"); return 1; } vtkDataArray* velocityArray = input->GetPointData()->GetArray(this->VelocityArrayName); if (velocityArray == NULL) { vtkErrorMacro("VelocityArray with name specified does not exist"); return 1; } char gradientArrayName[] = "VelocityGradient"; vtkvmtkUnstructuredGridGradientFilter* gradientFilter = vtkvmtkUnstructuredGridGradientFilter::New(); gradientFilter->SetInput(input); gradientFilter->SetInputArrayName(this->VelocityArrayName); gradientFilter->SetGradientArrayName(gradientArrayName); gradientFilter->SetQuadratureOrder(this->QuadratureOrder); gradientFilter->SetConvergenceTolerance(this->ConvergenceTolerance); gradientFilter->SetComputeIndividualPartialDerivatives(this->ComputeIndividualPartialDerivatives); gradientFilter->Update(); vtkDataArray* velocityGradientArray = gradientFilter->GetOutput()->GetPointData()->GetArray(gradientArrayName); int numberOfPoints = input->GetNumberOfPoints(); vtkDoubleArray* vorticityArray = vtkDoubleArray::New(); if (this->VorticityArrayName) { vorticityArray->SetName(this->VorticityArrayName); } else { vorticityArray->SetName("Vorticity"); } vorticityArray->SetNumberOfComponents(3); vorticityArray->SetNumberOfTuples(numberOfPoints); double velocityGradient[9]; double vorticity[3]; int i; for (i=0; iGetTuple(i,velocityGradient); vorticity[0] = velocityGradient[7] - velocityGradient[5]; vorticity[1] = velocityGradient[2] - velocityGradient[6]; vorticity[2] = velocityGradient[3] - velocityGradient[1]; vorticityArray->SetTuple(i,vorticity); } output->DeepCopy(input); output->GetPointData()->AddArray(vorticityArray); vorticityArray->Delete(); return 1; } void vtkvmtkMeshVorticity::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLinearToQuadraticSurfaceMeshFilter.h0000664000175000017500000000426111757446472024162 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearToQuadraticSurfaceMeshFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkLinearToQuadraticSurfaceMeshFilter - Converts linear elements to quadratic. // .SECTION Description // ... #ifndef __vtkvmtkLinearToQuadraticSurfaceMeshFilter_h #define __vtkvmtkLinearToQuadraticSurfaceMeshFilter_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkLinearToQuadraticSurfaceMeshFilter : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkLinearToQuadraticSurfaceMeshFilter,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkLinearToQuadraticSurfaceMeshFilter *New(); vtkSetMacro(SubdivisionMethod,int); vtkGetMacro(SubdivisionMethod,int); void SetSubdivisionMethodToLinear() { this->SubdivisionMethod = LINEAR_SUBDIVISION; } void SetSubdivisionMethodToButterfly() { this->SubdivisionMethod = BUTTERFLY_SUBDIVISION; } protected: vtkvmtkLinearToQuadraticSurfaceMeshFilter(); ~vtkvmtkLinearToQuadraticSurfaceMeshFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int SubdivisionMethod; //BTX enum { LINEAR_SUBDIVISION, BUTTERFLY_SUBDIVISION }; //ETX private: vtkvmtkLinearToQuadraticSurfaceMeshFilter(const vtkvmtkLinearToQuadraticSurfaceMeshFilter&); // Not implemented. void operator=(const vtkvmtkLinearToQuadraticSurfaceMeshFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLinearizeMeshFilter.h0000664000175000017500000000340211757446472021214 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearizeMeshFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkLinearizeMeshFilter - Converts linear elements to quadratic. // .SECTION Description // ... #ifndef __vtkvmtkLinearizeMeshFilter_h #define __vtkvmtkLinearizeMeshFilter_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkLinearizeMeshFilter : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkLinearizeMeshFilter,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkLinearizeMeshFilter *New(); vtkSetMacro(CleanOutput,int); vtkGetMacro(CleanOutput,int); vtkBooleanMacro(CleanOutput,int); protected: vtkvmtkLinearizeMeshFilter(); ~vtkvmtkLinearizeMeshFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int CleanOutput; private: vtkvmtkLinearizeMeshFilter(const vtkvmtkLinearizeMeshFilter&); // Not implemented. void operator=(const vtkvmtkLinearizeMeshFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/CMakeLists.txt0000664000175000017500000001230111757446472016245 0ustar lucalucaSET (VTK_VMTK_MISC_SRCS vtkvmtkAnnularCapPolyData.cxx vtkvmtkBoundaryLayerGenerator.cxx vtkvmtkCurvedMPRImageFilter.cxx vtkvmtkImageBoxPainter.cxx vtkvmtkIterativeClosestPointTransform.cxx vtkvmtkLevelSetSigmoidFilter.cxx vtkvmtkLinearizeMeshFilter.cxx vtkvmtkLinearToQuadraticMeshFilter.cxx vtkvmtkLinearToQuadraticSurfaceMeshFilter.cxx vtkvmtkMeshLambda2.cxx vtkvmtkMeshProjection.cxx vtkvmtkMeshVelocityStatistics.cxx vtkvmtkMeshVorticity.cxx vtkvmtkMeshWallShearRate.cxx vtkvmtkPolyDataNetworkExtraction.cxx vtkvmtkPolyDataKiteRemovalFilter.cxx vtkvmtkPolyDataSizingFunction.cxx vtkvmtkPolyDataToUnstructuredGridFilter.cxx vtkvmtkRBFInterpolation.cxx vtkvmtkSimpleCapPolyData.cxx vtkvmtkSmoothCapPolyData.cxx vtkvmtkStaticTemporalInterpolatedVelocityField.cxx vtkvmtkStaticTemporalStreamTracer.cxx vtkvmtkStreamlineClusteringFilter.cxx vtkvmtkStreamlineOsculatingCentersFilter.cxx vtkvmtkStreamlineToParticlesFilter.cxx vtkvmtkSurfaceDistance.cxx vtkvmtkSurfaceProjection.cxx ) SET (VTK_VMTK_MISC_TARGET_LINK_LIBRARIES vtkvmtkMisc vtkvmtkComputationalGeometry vtkvmtkDifferentialGeometry vtkCommon vtkFiltering vtkGraphics vtkHybrid) IF (VTK_VMTK_BUILD_TETGEN) SET (VTK_VMTK_MISC_SRCS ${VTK_VMTK_MISC_SRCS} vtkvmtkTetGenWrapper.cxx) ADD_DEFINITIONS (-DTETLIBRARY) INCLUDE_DIRECTORIES(${TETGEN_SOURCE_DIR}) LINK_DIRECTORIES(${TETGEN_LIB_DIR}) SET (VTK_VMTK_MISC_TARGET_LINK_LIBRARIES ${VTK_VMTK_MISC_TARGET_LINK_LIBRARIES} tet) ENDIF (VTK_VMTK_BUILD_TETGEN) IF (VTK_VMTK_BUILD_STREAMTRACER) SET (VTK_VMTK_MISC_SRCS ${VTK_VMTK_MISC_SRCS} vtkvmtkStaticTemporalInterpolatedVelocityField.cxx vtkvmtkStaticTemporalStreamTracer.cxx) ENDIF (VTK_VMTK_BUILD_STREAMTRACER) ADD_LIBRARY (vtkvmtkMisc ${VTK_VMTK_MISC_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkMisc PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkMisc ${VTK_VMTK_MISC_TARGET_LINK_LIBRARIES}) INSTALL(TARGETS vtkvmtkMisc LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_MISC_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/Misc/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkMisc) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkMiscPython VTK_VMTK_MISC_PYTHON_SRCS "${VTK_VMTK_MISC_SRCS}") ADD_LIBRARY(vtkvmtkMiscPythonD ${VTK_VMTK_MISC_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkMiscPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkMiscPython MODULE vtkvmtkMiscPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkMiscPythonD vtkvmtkMisc vtkvmtkComputationalGeometry vtkvmtkComputationalGeometryPythonD vtkvmtkDifferentialGeometry vtkvmtkDifferentialGeometryPythonD vtkCommon vtkCommonPythonD vtkFiltering vtkFilteringPythonD vtkGraphics vtkGraphicsPythonD) TARGET_LINK_LIBRARIES (vtkvmtkMiscPython vtkvmtkMiscPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkMiscPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkMiscPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkMiscPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkMiscTCL VTK_VMTK_MISC_TCL_SRCS "${VTK_VMTK_MISC_SRCS}" "") ADD_LIBRARY(vtkvmtkMiscTCL ${VTK_VMTK_MISC_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkMiscTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkMiscTCL vtkvmtkMisc vtkvmtkComputationalGeometryTCL vtkvmtkComputationalGeometry vtkvmtkDifferentialGeometryTCL vtkvmtkDifferentialGeometry vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkGraphics vtkGraphicsTCL) INSTALL(TARGETS vtkvmtkMiscTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkMiscTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSmoothCapPolyData.h0000664000175000017500000000372311757446472020650 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSmoothCapPolyData.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSmoothCapPolyData - Add caps to boundaries. // .SECTION Description // This class closes the boundaries of a surface with a cap. #ifndef __vtkvmtkSmoothCapPolyData_h #define __vtkvmtkSmoothCapPolyData_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkSmoothCapPolyData : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkSmoothCapPolyData,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSmoothCapPolyData *New(); vtkSetObjectMacro(BoundaryIds,vtkIdList); vtkGetObjectMacro(BoundaryIds,vtkIdList); vtkSetMacro(ConstraintFactor,double); vtkGetMacro(ConstraintFactor,double); vtkSetMacro(NumberOfRings,int); vtkGetMacro(NumberOfRings,int); protected: vtkvmtkSmoothCapPolyData(); ~vtkvmtkSmoothCapPolyData(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdList* BoundaryIds; double ConstraintFactor; int NumberOfRings; private: vtkvmtkSmoothCapPolyData(const vtkvmtkSmoothCapPolyData&); // Not implemented. void operator=(const vtkvmtkSmoothCapPolyData&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataKiteRemovalFilter.cxx0000664000175000017500000001343011757446472022712 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataKiteRemovalFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataKiteRemovalFilter.h" #include "vtkvmtkConstants.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkIdList.h" #include "vtkTriangleFilter.h" #include "vtkCleanPolyData.h" #include "vtkTriangle.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataKiteRemovalFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkPolyDataKiteRemovalFilter); vtkvmtkPolyDataKiteRemovalFilter::vtkvmtkPolyDataKiteRemovalFilter() { this->SizeFactor = 0.1; } vtkvmtkPolyDataKiteRemovalFilter::~vtkvmtkPolyDataKiteRemovalFilter() { } int vtkvmtkPolyDataKiteRemovalFilter::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())); vtkTriangleFilter* triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(input); triangleFilter->PassLinesOff(); triangleFilter->PassVertsOff(); triangleFilter->Update(); vtkPolyData* surface = vtkPolyData::New(); surface->CopyStructure(triangleFilter->GetOutput()); surface->GetPointData()->PassData(triangleFilter->GetOutput()->GetPointData()); surface->GetCellData()->PassData(triangleFilter->GetOutput()->GetCellData()); surface->GetFieldData()->PassData(triangleFilter->GetOutput()->GetFieldData()); surface->BuildCells(); surface->BuildLinks(); double averageTriangleArea = 0.0; int numberOfCells = surface->GetNumberOfCells(); double point[3], point1[3], point2[3]; vtkIdList* cellPointIds = vtkIdList::New(); for (vtkIdType cellId=0; cellIdInitialize(); surface->GetCellPoints(cellId,cellPointIds); surface->GetPoint(cellPointIds->GetId(0),point); surface->GetPoint(cellPointIds->GetId(1),point1); surface->GetPoint(cellPointIds->GetId(2),point2); averageTriangleArea += vtkTriangle::TriangleArea(point,point1,point2); } averageTriangleArea /= numberOfCells; int numberOfPoints = surface->GetNumberOfPoints(); vtkIdList* cellIds = vtkIdList::New(); for (int pointId=0; pointIdGetPoint(pointId,point); cellIds->Initialize(); surface->GetPointCells(pointId,cellIds); if (cellIds->GetNumberOfIds() != 4) { continue; } double localAverageTriangleArea = 0.0; int numberOfCellIds = cellIds->GetNumberOfIds(); int i, j; for (i=0; iGetId(i); cellPointIds->Initialize(); surface->GetCellPoints(cellId,cellPointIds); surface->GetPoint(cellPointIds->GetId(0),point); surface->GetPoint(cellPointIds->GetId(1),point1); surface->GetPoint(cellPointIds->GetId(2),point2); localAverageTriangleArea += vtkTriangle::TriangleArea(point,point1,point2); } localAverageTriangleArea /= numberOfCellIds; if (localAverageTriangleArea < VTK_VMTK_DOUBLE_TOL) { continue; } if (localAverageTriangleArea > this->SizeFactor * averageTriangleArea) { continue; } for (i=0; iGetId(i); cellPointIds->Initialize(); surface->GetCellPoints(cellId,cellPointIds); surface->GetPoint(cellPointIds->GetId(0),point); surface->GetPoint(cellPointIds->GetId(1),point1); surface->GetPoint(cellPointIds->GetId(2),point2); double area = vtkTriangle::TriangleArea(point,point1,point2); if (area > this->SizeFactor * averageTriangleArea) { continue; } int numberOfCellPointIds = cellPointIds->GetNumberOfIds(); for (j=0; jGetId(j); surface->GetPoints()->SetPoint(cellPointId,point); } } } vtkCleanPolyData* cleaner = vtkCleanPolyData::New(); cleaner->SetInput(surface); vtkTriangleFilter* triangleFilter2 = vtkTriangleFilter::New(); triangleFilter2->SetInput(cleaner->GetOutput()); triangleFilter2->PassLinesOff(); triangleFilter2->PassVertsOff(); triangleFilter2->Update(); output->CopyStructure(triangleFilter2->GetOutput()); output->GetPointData()->PassData(triangleFilter2->GetOutput()->GetPointData()); output->GetCellData()->PassData(triangleFilter2->GetOutput()->GetCellData()); output->GetFieldData()->PassData(triangleFilter2->GetOutput()->GetFieldData()); triangleFilter->Delete(); triangleFilter2->Delete(); cleaner->Delete(); surface->Delete(); cellPointIds->Delete(); cellIds->Delete(); return 1; } void vtkvmtkPolyDataKiteRemovalFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshLambda2.h0000664000175000017500000000452611757446472017376 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshLambda2.h,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkMeshLambda2 - ... // .SECTION Description // . #ifndef __vtkvmtkMeshLambda2_h #define __vtkvmtkMeshLambda2_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkUnstructuredGrid.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkMeshLambda2 : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkMeshLambda2,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkMeshLambda2 *New(); vtkSetStringMacro(VelocityArrayName); vtkGetStringMacro(VelocityArrayName); vtkSetStringMacro(Lambda2ArrayName); vtkGetStringMacro(Lambda2ArrayName); vtkSetMacro(ComputeIndividualPartialDerivatives,int); vtkGetMacro(ComputeIndividualPartialDerivatives,int); vtkBooleanMacro(ComputeIndividualPartialDerivatives,int); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); vtkSetMacro(ForceBoundaryToNegative,int); vtkGetMacro(ForceBoundaryToNegative,int); vtkBooleanMacro(ForceBoundaryToNegative,int); protected: vtkvmtkMeshLambda2(); ~vtkvmtkMeshLambda2(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* VelocityArrayName; char* Lambda2ArrayName; int ComputeIndividualPartialDerivatives; double ConvergenceTolerance; int QuadratureOrder; int ForceBoundaryToNegative; private: vtkvmtkMeshLambda2(const vtkvmtkMeshLambda2&); // Not implemented. void operator=(const vtkvmtkMeshLambda2&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStreamlineClusteringFilter.cxx0000664000175000017500000002104711757446472023200 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStreamlineClusteringFilter.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkStreamlineClusteringFilter.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkMath.h" #include "vtkSplineFilter.h" //#include "vtkPointLocator.h" #include "vtkCellArray.h" #include "vtkCell.h" vtkCxxRevisionMacro(vtkvmtkStreamlineClusteringFilter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkStreamlineClusteringFilter); vtkvmtkStreamlineClusteringFilter::vtkvmtkStreamlineClusteringFilter() { this->ClusterCenters = NULL; } vtkvmtkStreamlineClusteringFilter::~vtkvmtkStreamlineClusteringFilter() { if (this->ClusterCenters) { this->ClusterCenters->Delete(); this->ClusterCenters = NULL; } } int vtkvmtkStreamlineClusteringFilter::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 (input->GetNumberOfPoints() < 1) { return 1; } double resampleLength = 0.01; int numberOfChunkPoints = 40; int numberOfClusters = 4; vtkSplineFilter* splineFilter = vtkSplineFilter::New(); splineFilter->SetInput(input); splineFilter->SetSubdivideToLength(); splineFilter->SetLength(resampleLength); splineFilter->Update(); vtkPolyData* resampledInput = splineFilter->GetOutput(); vtkPolyData* streamlines = vtkPolyData::New(); vtkPoints* streamlinesPoints = vtkPoints::New(); vtkCellArray* streamlinesLines = vtkCellArray::New(); streamlines->SetPoints(streamlinesPoints); streamlines->SetLines(streamlinesLines); streamlinesPoints->DeepCopy(splineFilter->GetOutput()->GetPoints()); int numberOfCells = resampledInput->GetNumberOfCells(); vtkIdList* inputCellIds = vtkIdList::New(); vtkIdList* inputLabelIds = vtkIdList::New(); int currentLabelId = -1; for (int i=0; iGetCell(i); int numberOfLinePoints = line->GetNumberOfPoints(); for (int j=0; jInsertNextCell(numberOfChunkLinePoints); if (isCluster) { inputCellIds->InsertNextId(id); inputLabelIds->InsertNextId(currentLabelId); } } int pointId = line->GetPointId(j); streamlinesLines->InsertCellPoint(pointId); } } numberOfCells = streamlines->GetNumberOfCells(); numberOfClusters = inputCellIds->GetNumberOfIds(); vtkPolyData* clusterCenters = vtkPolyData::New(); vtkPoints* clusterCenterPoints = vtkPoints::New(); vtkCellArray* clusterCenterLines = vtkCellArray::New(); clusterCenters->SetPoints(clusterCenterPoints); clusterCenters->SetLines(clusterCenterLines); vtkIntArray* centerLabelArray = vtkIntArray::New(); centerLabelArray->SetName("Label"); for (int i=0; iGetCell(inputCellIds->GetId(i)); int numberOfLinePoints = line->GetNumberOfPoints(); clusterCenterLines->InsertNextCell(numberOfLinePoints); centerLabelArray->InsertNextValue(inputLabelIds->GetId(i)); for (int j=0; jGetPoint(line->GetPointId(j),point); int pointId = clusterCenterPoints->InsertNextPoint(point); clusterCenterLines->InsertCellPoint(pointId); } } clusterCenters->GetCellData()->AddArray(centerLabelArray); // vtkDoubleArray* covariance = vtkDoubleArray::New(); // covariance->SetName("PointCovariance"); // covariance->SetNumberOfComponents(3); // covariance->SetNumberOfTuples(clusterCenterPoints->GetNumberOfPoints()); // clusterCenters->GetPointData()->AddArray(covariance); // vtkPointLocator* pointLocator = vtkPointLocator::New(); // pointLocator->SetDataSet(clusterCenters); // pointLocator->BuildLocator(); vtkIntArray* labelArray = vtkIntArray::New(); labelArray->SetName("Label"); labelArray->SetNumberOfValues(numberOfCells); vtkDoubleArray* distance = vtkDoubleArray::New(); distance->SetName("Distance"); distance->SetNumberOfTuples(numberOfCells); for (int i=0; iGetCell(i); double minClusterCenterDistance = VTK_VMTK_LARGE_DOUBLE; int minClusterCenterDistanceId = -1; for (int j=0; jGetCell(j); int numberOfClusterCenterLinePoints = clusterCenterLine->GetNumberOfPoints(); double squaredDistanceSum = 0.0; int numberOfRepeatedMatches = 0; int numberOfStreamlinePoints = streamline->GetNumberOfPoints(); vtkIdList* correspondenceIds = vtkIdList::New(); for (int ip=0; ipGetPoint(streamline->GetPointId(ip),point); double minPointDistanceSquared = VTK_VMTK_LARGE_DOUBLE; int minPointDistanceId = -1; for (int jp=0; jpGetPoint(clusterCenterLine->GetPointId(jp),clusterCenterPoint); double distanceSquared = vtkMath::Distance2BetweenPoints(point,clusterCenterPoint); if (distanceSquared < minPointDistanceSquared) { minPointDistanceSquared = distanceSquared; minPointDistanceId = jp; } } squaredDistanceSum += minPointDistanceSquared; if (correspondenceIds->IsId(minPointDistanceId) != -1) { numberOfRepeatedMatches++; } else { correspondenceIds->InsertNextId(minPointDistanceId); } } correspondenceIds->Delete(); double clusterCenterDistance = sqrt(squaredDistanceSum); double averageDistance = clusterCenterDistance / numberOfStreamlinePoints; double distancePenalty = (numberOfClusterCenterLinePoints - numberOfStreamlinePoints + numberOfRepeatedMatches) * averageDistance; double distance = (clusterCenterDistance + distancePenalty) / numberOfStreamlinePoints; if (distance < minClusterCenterDistance) { minClusterCenterDistance = distance; minClusterCenterDistanceId = inputLabelIds->GetId(j); } } labelArray->InsertValue(i,minClusterCenterDistanceId); distance->InsertValue(i,minClusterCenterDistance); } output->DeepCopy(streamlines); output->GetCellData()->AddArray(labelArray); output->GetCellData()->AddArray(distance); if (this->ClusterCenters) { this->ClusterCenters->Delete(); this->ClusterCenters = NULL; } this->ClusterCenters = vtkPolyData::New(); this->ClusterCenters->DeepCopy(clusterCenters); splineFilter->Delete(); inputCellIds->Delete(); clusterCenters->Delete(); clusterCenterPoints->Delete(); clusterCenterLines->Delete(); // covariance->Delete(); // pointLocator->Delete(); labelArray->Delete(); centerLabelArray->Delete(); return 1; } void vtkvmtkStreamlineClusteringFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataToUnstructuredGridFilter.cxx0000664000175000017500000000532211757446472024311 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataToUnstructuredGridFilter.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:49:05 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataToUnstructuredGridFilter.h" #include "vtkPolyData.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataToUnstructuredGridFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataToUnstructuredGridFilter); int vtkvmtkPolyDataToUnstructuredGridFilter::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData"); return 1; } int vtkvmtkPolyDataToUnstructuredGridFilter::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())); vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); output->SetPoints(input->GetPoints()); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); vtkCellArray* cellArray = vtkCellArray::New(); int numberOfCells = input->GetNumberOfCells(); input->BuildCells(); int* cellTypes = new int[numberOfCells]; vtkIdType npts, *pts; int cellType; for (int i=0; iGetCellPoints(i,npts,pts); cellType = input->GetCellType(i); cellArray->InsertNextCell(npts,pts); cellTypes[i] = cellType; } output->SetCells(cellTypes,cellArray); cellArray->Delete(); delete[] cellTypes; return 1; } void vtkvmtkPolyDataToUnstructuredGridFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSimpleCapPolyData.h0000664000175000017500000000376211757446472020633 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSimpleCapPolyData.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSimpleCapPolyData - Add caps to boundaries. // .SECTION Description // This class closes the boundaries of a surface with a cap. #ifndef __vtkvmtkSimpleCapPolyData_h #define __vtkvmtkSimpleCapPolyData_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkSimpleCapPolyData : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkSimpleCapPolyData,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSimpleCapPolyData *New(); vtkSetStringMacro(CellEntityIdsArrayName); vtkGetStringMacro(CellEntityIdsArrayName); vtkSetObjectMacro(BoundaryIds,vtkIdList); vtkGetObjectMacro(BoundaryIds,vtkIdList); vtkSetMacro(CellEntityIdOffset,int); vtkGetMacro(CellEntityIdOffset,int); protected: vtkvmtkSimpleCapPolyData(); ~vtkvmtkSimpleCapPolyData(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdList* BoundaryIds; char* CellEntityIdsArrayName; int CellEntityIdOffset; private: vtkvmtkSimpleCapPolyData(const vtkvmtkSimpleCapPolyData&); // Not implemented. void operator=(const vtkvmtkSimpleCapPolyData&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataNetworkExtraction.h0000664000175000017500000001670611757446472022452 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataNetworkExtraction.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataNetworkExtraction - Add caps to boundaries. // .SECTION Description // This class closes the boundaries of a surface with a cap. #ifndef __vtkvmtkPolyDataNetworkExtraction_h #define __vtkvmtkPolyDataNetworkExtraction_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class vtkPolyDataCollection; class vtkIdTypeArray; class vtkCollection; class vtkPoints; class VTK_VMTK_MISC_EXPORT vtkvmtkPolyDataNetworkExtraction : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataNetworkExtraction,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataNetworkExtraction *New(); vtkSetStringMacro(MarksArrayName); vtkGetStringMacro(MarksArrayName); vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); vtkSetStringMacro(TopologyArrayName); vtkGetStringMacro(TopologyArrayName); vtkSetMacro(AdvancementRatio,double); vtkGetMacro(AdvancementRatio,double); vtkGetMacro(TotalMarkedPoints,int); vtkGetMacro(MinimumStep,double); vtkGetObjectMacro(GraphLayout,vtkPolyData); //BTX enum { STEP_ITERATION_PROCEED, STEP_ITERATION_REDEFINE, STEP_ITERATION_STOP_END, STEP_ITERATION_STOP_BIFURCATION, STEP_ITERATION_STOP_CLOSED }; //ETX //BTX enum { NON_VISITED, VISITED, GLOBAL }; //ETX protected: vtkvmtkPolyDataNetworkExtraction(); ~vtkvmtkPolyDataNetworkExtraction(); void BoundaryExtractor (vtkPolyData* polyInput, vtkPolyData* boundary); void BoundarySeparator(vtkPolyData* appendedBoundaries, vtkPolyDataCollection* boundaries); void InsertInEdgeTable(vtkIdTypeArray* edgeTable, vtkIdType pointId0, vtkIdType pointId1); bool InsertUniqueInEdgeTable(vtkIdTypeArray* edgeTable, vtkIdType pointId0, vtkIdType pointId1); void GetFromEdgeTable(vtkIdTypeArray* edgeTable, vtkIdType position, vtkIdType edge[2]); void UpdateEdgeTableCollectionReal(vtkPolyData* model,vtkPolyDataCollection* profiles,vtkCollection* edgeTables); double Distance(double point1[3], double point2[3]); double GetFurthestDistance (vtkPolyDataCollection* polyDataCollection, double fromPoint[3]); void Barycenter (vtkPoints* points, double barycenter[3]); void ProfileBarycenter (vtkPoints* points, double barycenter[3]); void DefineVirtualSphere(vtkPolyDataCollection* baseProfiles, double center[3], double &radius, double ratio); vtkIdType CurrentPointId(vtkPolyData* model,vtkIdType currentEdge[2]); void InsertEdgeForNewProfiles(vtkPolyData* model, vtkIdType* edge, vtkIdTypeArray* edgeTable, vtkIdTypeArray* cellPairs, vtkIdList* pointIds); bool LookForNeighbors(vtkPolyData* model, vtkIdType pointId, vtkIdList* notVisitedIds, vtkIdTypeArray* edgeTableForIncludedGlobalProfiles); void PropagateFromBaseProfilePoint(vtkPolyData* model, vtkIdList* toVisitPointIds, double center[3], double radius, vtkIdTypeArray* edgeTableForNewProfiles, vtkIdTypeArray* cellPairsForNewProfiles, vtkIdList* pointIdsForNewProfiles, vtkPoints* markedPoints, vtkIdList* markedPointIds, vtkIdTypeArray* edgeTableForIncludedGlobalProfiles); void LocateVirtualPoint(vtkIdType edge[2], double center[3], double radius, vtkIdList* pointIdsForNewProfiles, vtkPoints* pointsForNewProfiles, vtkDoubleArray* pointDistancesForNewProfiles, double virtualPoint[3]); void ReconstructNewProfiles(vtkPoints* virtualPoints, vtkIdTypeArray* edgeTable, vtkIdTypeArray* cellPairs, vtkPolyDataCollection* newProfiles, vtkCollection* newProfilesEdgeTables); void GenerateNewProfiles(vtkPolyData* model, double center[3], double radius, vtkIdTypeArray* edgeTableForNewProfiles, vtkIdTypeArray* cellPairsForNewProfiles, vtkIdList* pointIdsForNewProfiles, vtkPolyDataCollection* newProfiles, vtkCollection* newProfilesEdgeTables); void UnmarkPoints(vtkPolyData* model, vtkIdList* markedPointIds); double ComputeStepRadius(vtkPoints* points, double point1[3], double point2[3]); double ComputeMeanRadius(vtkPoints* points, double point1[3]); void PointsForRadius(vtkPoints *markedPoints, vtkPolyDataCollection *baseProfiles, vtkPolyDataCollection *newProfiles, vtkPoints *pointsForRadius); void LookForIntersectingPoint(vtkPoints* segmentPoints, double center[3], double radius, vtkIdType &intersectingPointId); vtkIdType StepIteration(vtkPolyData* model, vtkPolyDataCollection* baseProfiles, vtkCollection* baseProfilesEdgeTables, vtkPolyDataCollection* globalProfiles, vtkCollection* globalProfilesEdgeTables, vtkPolyDataCollection* newProfiles, vtkCollection* newProfilesEdgeTables, vtkPoints* segmentPoints, vtkDoubleArray* segmentRadii, vtkPoints* bifurcationPoints, vtkDoubleArray* bifurcationRadii, double oldCenter[3], double &oldRadius, double advancementRatio); void MarkModelGlobalProfile(vtkPolyData* model, vtkIdTypeArray* newGlobalProfileEdgeTable); void SegmentTopology(vtkCollection* bifurcations, vtkCollection* bifurcationsRadii, double firstSegmentPoint[3], double lastSegmentPoint[3], double firstPoint[3], double &firstRadius, double lastPoint[3], double &lastRadius, vtkIdType segmentTopology[2]); void BuildSegment(vtkPoints* segmentPoints, vtkDoubleArray* segmentRadii, vtkIdType segmentTopology[2], double firstPoint[3], double firstRadius, double lastPoint[3], double lastRadius, const double* centralPoint, vtkPolyData* segment); void InsertNewBifurcation(vtkCollection* bifurcations, vtkCollection* bifurcationsRadii, vtkPoints* bifurcationPoints, vtkDoubleArray* bifurcationRadii, vtkPolyDataCollection* additionalSegments); void SegmentIteration(vtkPolyData* model, vtkPolyData* initialProfile, vtkIdTypeArray* initialProfileEdgeTable, vtkPolyDataCollection* globalProfiles, vtkCollection* globalProfilesEdgeTables, vtkCollection* bifurcations, vtkCollection* bifurcationsRadii, vtkPolyDataCollection* segments, double advancementRatio); void JoinSegments (vtkPolyData* segment0, vtkPolyData* segment1, bool first0, bool first1, vtkPolyData* segment); void RemoveDegenerateBifurcations(vtkPolyDataCollection* segments,vtkCollection* bifurcations); void GlobalIteration(vtkPolyData* model, vtkPolyDataCollection* globalProfiles, vtkPolyData* network, double advancementRatio); void MarkModelRealBoundary(vtkPolyData* model, vtkPolyData* modelBoundary); void Graph(vtkPolyData* network, vtkPolyData* graphLayout); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkPolyData* GraphLayout; char* MarksArrayName; char* RadiusArrayName; char* TopologyArrayName; double MinimumStep; double AdvancementRatio; vtkIdType TotalMarkedPoints; private: vtkvmtkPolyDataNetworkExtraction(const vtkvmtkPolyDataNetworkExtraction&); // Not implemented. void operator=(const vtkvmtkPolyDataNetworkExtraction&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStaticTemporalInterpolatedVelocityField.cxx0000664000175000017500000003134611757446472025663 0ustar lucaluca/*========================================================================= Program: Visualization Toolkit Module: vtkvmtkStaticTemporalInterpolatedVelocityField.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 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. =========================================================================*/ #include "vtkvmtkStaticTemporalInterpolatedVelocityField.h" #include "vtkTable.h" #include "vtkDataSet.h" #include "vtkGenericCell.h" #include "vtkPointData.h" #include "vtkDataArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkStandardNewMacro(vtkvmtkStaticTemporalInterpolatedVelocityField); vtkCxxSetObjectMacro(vtkvmtkStaticTemporalInterpolatedVelocityField, TimeStepsTable, vtkTable); vtkvmtkStaticTemporalInterpolatedVelocityField::vtkvmtkStaticTemporalInterpolatedVelocityField() { this->Periodic = 0; this->VelocityScale = 1.0; this->TimeStepsTable = NULL; this->UseVectorComponents = 0; this->VectorPrefix = NULL; this->Component0Prefix = NULL; this->Component1Prefix = NULL; this->Component2Prefix = NULL; } vtkvmtkStaticTemporalInterpolatedVelocityField::~vtkvmtkStaticTemporalInterpolatedVelocityField() { if (this->VectorPrefix) { delete[] this->VectorPrefix; this->VectorPrefix = NULL; } if (this->Component0Prefix) { delete[] this->Component0Prefix; this->Component0Prefix = NULL; } if (this->Component1Prefix) { delete[] this->Component1Prefix; this->Component1Prefix = NULL; } if (this->Component2Prefix) { delete[] this->Component2Prefix; this->Component2Prefix = NULL; } this->SetTimeStepsTable(NULL); } void vtkvmtkStaticTemporalInterpolatedVelocityField::AddDataSet( vtkDataSet * dataset ) { if ( !dataset ) { return; } // insert the dataset (do NOT register the dataset to 'this') this->DataSets->push_back( dataset ); int size = dataset->GetMaxCellSize(); if ( size > this->WeightsSize ) { this->WeightsSize = size; if ( this->Weights ) { delete[] this->Weights; this->Weights = NULL; } this->Weights = new double[size]; } } void vtkvmtkStaticTemporalInterpolatedVelocityField::SetLastCellId( vtkIdType c, int dataindex ) { this->LastCellId = c; this->LastDataSet = ( *this->DataSets )[dataindex]; // if the dataset changes, then the cached cell is invalidated // we might as well prefetch the cached cell either way if ( this->LastCellId != -1 ) { this->LastDataSet->GetCell( this->LastCellId, this->GenCell ); } this->LastDataSetIndex = dataindex; } void vtkvmtkStaticTemporalInterpolatedVelocityField::FindTimeRowId(double time, int& prevRowId, int& nextRowId, double& p) { //cout<<"Time "<TimeStepsTable == NULL) { return; } int numberOfRows = this->TimeStepsTable->GetNumberOfRows(); if (this->TimeStepsTable->GetNumberOfColumns() < 2 || numberOfRows == 1) { return; } int previousRowIndex = this->TimeStepsTable->GetValue(0,0).ToInt(); double previousRowTime = this->TimeStepsTable->GetValue(0,1).ToDouble(); if (numberOfRows < 2 || previousRowTime == time) { return; } double shiftedTime = time; double period = this->TimeStepsTable->GetValue(numberOfRows-1,1).ToDouble() - previousRowTime; if (this->Periodic) { double ratio = (time - previousRowTime) / period; shiftedTime = (ratio - floor(ratio)) * period + previousRowTime; } bool found = false; int pRowId = 0; for (int i=1; iTimeStepsTable->GetValue(rowId,0).ToInt(); double rowTime = this->TimeStepsTable->GetValue(rowId,1).ToDouble(); if (shiftedTime > previousRowTime && shiftedTime <= rowTime) { prevRowId = pRowId; nextRowId = rowId; p = (shiftedTime - previousRowTime) / (rowTime - previousRowTime); found = true; break; } pRowId = rowId; previousRowIndex = rowIndex; previousRowTime = rowTime; } //cout<<"Index "<LastDataSet && !this->DataSets->empty()) { ds = ( *this->DataSets )[0]; this->LastDataSet = ds; this->LastDataSetIndex = 0; } else { ds = this->LastDataSet; } int retVal = this->FunctionValues( ds, x, f ); if ( !retVal ) { for( this->LastDataSetIndex = 0; this->LastDataSetIndex < static_cast( this->DataSets->size() ); this->LastDataSetIndex ++ ) { ds = this->DataSets->operator[]( this->LastDataSetIndex ); if( ds && ds != this->LastDataSet ) { this->ClearLastCellId(); retVal = this->FunctionValues( ds, x, f ); if ( retVal ) { this->LastDataSet = ds; return retVal; } } } this->LastCellId = -1; this->LastDataSetIndex = 0; this->LastDataSet = (*this->DataSets)[0]; return 0; } return retVal; } int vtkvmtkStaticTemporalInterpolatedVelocityField::FunctionValues( vtkDataSet * dataset, double * x, double * f ) { int i, j, subId , numPts, id; vtkDataArray * vectorsPrev = NULL; vtkDataArray * vectorsNext = NULL; vtkDataArray * component0Prev = NULL; vtkDataArray * component0Next = NULL; vtkDataArray * component1Prev = NULL; vtkDataArray * component1Next = NULL; vtkDataArray * component2Prev = NULL; vtkDataArray * component2Next = NULL; double vecPrev[3], vecNext[3]; double dist2; int ret; char arrayName[1024]; f[0] = f[1] = f[2] = 0.0; // See if a dataset has been specified and if there are input vectors if ( !dataset ) { vtkErrorMacro( << "Can't evaluate dataset!" ); return 0; } double time = x[3]; int prevRowId, nextRowId; double timeP; this->FindTimeRowId(time,prevRowId,nextRowId,timeP); int prevTimeIndex = this->TimeStepsTable->GetValue(prevRowId,0).ToInt(); int nextTimeIndex = this->TimeStepsTable->GetValue(nextRowId,0).ToInt(); if (this->UseVectorComponents) { this->BuildArrayName(this->Component0Prefix,prevTimeIndex,arrayName); component0Prev = dataset->GetPointData()->GetArray(arrayName); this->BuildArrayName(this->Component1Prefix,prevTimeIndex,arrayName); component1Prev = dataset->GetPointData()->GetArray(arrayName); this->BuildArrayName(this->Component2Prefix,prevTimeIndex,arrayName); component2Prev = dataset->GetPointData()->GetArray(arrayName); if (!component0Prev || !component1Prev || !component2Prev) { vtkErrorMacro(<<"Component array not found for index "<BuildArrayName(this->Component0Prefix,nextTimeIndex,arrayName); component0Next = dataset->GetPointData()->GetArray(arrayName); this->BuildArrayName(this->Component1Prefix,nextTimeIndex,arrayName); component1Next = dataset->GetPointData()->GetArray(arrayName); this->BuildArrayName(this->Component2Prefix,nextTimeIndex,arrayName); component2Next = dataset->GetPointData()->GetArray(arrayName); if (timeP > 0.0 && (!component0Next || !component1Next || !component2Next)) { vtkErrorMacro(<<"Component array not found for index "<BuildArrayName(this->VectorPrefix,prevTimeIndex,arrayName); vectorsPrev = dataset->GetPointData()->GetArray(arrayName); if (timeP > 0.0 && !vectorsPrev) { vtkErrorMacro(<<"Vector array not found for index "<BuildArrayName(this->VectorPrefix,nextTimeIndex,arrayName); vectorsNext = dataset->GetPointData()->GetArray(arrayName); if (!vectorsNext) { vtkErrorMacro(<<"Vector array not found for index "<GetLength() * vtkAbstractInterpolatedVelocityField::TOLERANCE_SCALE; int found = 0; if ( this->Caching ) { // See if the point is in the cached cell if ( this->LastCellId == -1 || !( ret = this->GenCell->EvaluatePosition ( x, 0, subId, this->LastPCoords, dist2, this->Weights) ) || ret == -1 ) { // if not, find and get it if ( this->LastCellId != - 1 ) { this->CacheMiss ++; dataset->GetCell( this->LastCellId, this->Cell ); this->LastCellId = dataset->FindCell( x, this->Cell, this->GenCell, this->LastCellId, tol2, subId, this->LastPCoords, this->Weights ); if ( this->LastCellId != -1 ) { dataset->GetCell( this->LastCellId, this->GenCell ); found = 1; } } } else { this->CacheHit ++; found = 1; } } if ( !found ) { // if the cell is not found, do a global search (ignore initial // cell if there is one) this->LastCellId = dataset->FindCell( x, 0, this->GenCell, -1, tol2, subId, this->LastPCoords, this->Weights ); if ( this->LastCellId != -1 ) { dataset->GetCell( this->LastCellId, this->GenCell ); } else { return 0; } } // if the cell is valid if ( this->LastCellId >= 0 ) { numPts = this->GenCell->GetNumberOfPoints(); // interpolate the vectors for ( j = 0; j < numPts; j ++ ) { id = this->GenCell->PointIds->GetId( j ); if (this->UseVectorComponents) { vecPrev[0] = this->VelocityScale * component0Prev->GetTuple1(id); vecPrev[1] = this->VelocityScale * component1Prev->GetTuple1(id); vecPrev[2] = this->VelocityScale * component2Prev->GetTuple1(id); if (timeP > 0.0) { vecNext[0] = this->VelocityScale * component0Next->GetTuple1(id); vecNext[1] = this->VelocityScale * component1Next->GetTuple1(id); vecNext[2] = this->VelocityScale * component2Next->GetTuple1(id); } } else { vectorsPrev->GetTuple( id, vecPrev ); for ( i = 0; i < 3; i ++ ) { vecPrev[i] *= this->VelocityScale; } if (timeP > 0.0) { vectorsNext->GetTuple( id, vecNext ); for ( i = 0; i < 3; i ++ ) { vecNext[i] *= this->VelocityScale; } } } if (timeP > 0.0) { for ( i = 0; i < 3; i ++ ) { f[i] += (timeP * vecNext[i] + (1.0 - timeP) * vecPrev[i]) * this->Weights[j]; } } else { for ( i = 0; i < 3; i ++ ) { f[i] += vecPrev[i] * this->Weights[j]; } } } if ( this->NormalizeVector == true ) { vtkMath::Normalize( f ); } } // if not, return false else { return 0; } return 1; } void vtkvmtkStaticTemporalInterpolatedVelocityField::CopyParameters( vtkAbstractInterpolatedVelocityField * from ) { this->Superclass::CopyParameters(from); if (from->IsA("vtkvmtkStaticTemporalInterpolatedVelocityField")) { vtkvmtkStaticTemporalInterpolatedVelocityField* fromCast = vtkvmtkStaticTemporalInterpolatedVelocityField::SafeDownCast(from); vtkTable* timeStepsTable = vtkTable::New(); timeStepsTable->DeepCopy(fromCast->GetTimeStepsTable()); this->SetTimeStepsTable(timeStepsTable); this->SetPeriodic(fromCast->GetPeriodic()); this->SetVelocityScale(fromCast->GetVelocityScale()); this->SetUseVectorComponents(fromCast->UseVectorComponents); this->SetVectorPrefix(fromCast->VectorPrefix); this->SetComponent0Prefix(fromCast->Component0Prefix); this->SetComponent1Prefix(fromCast->Component1Prefix); this->SetComponent2Prefix(fromCast->Component2Prefix); timeStepsTable->Delete(); } } void vtkvmtkStaticTemporalInterpolatedVelocityField::PrintSelf( ostream & os, vtkIndent indent ) { this->Superclass::PrintSelf( os, indent ); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataToUnstructuredGridFilter.h0000664000175000017500000000351711757446472023742 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataToUnstructuredGridFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataToUnstructuredGridFilter - ... // .SECTION Description // ... #ifndef __vtkvmtkPolyDataToUnstructuredGridFilter_h #define __vtkvmtkPolyDataToUnstructuredGridFilter_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class VTK_VMTK_MISC_EXPORT vtkvmtkPolyDataToUnstructuredGridFilter : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataToUnstructuredGridFilter,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataToUnstructuredGridFilter *New(); protected: vtkvmtkPolyDataToUnstructuredGridFilter() {} ~vtkvmtkPolyDataToUnstructuredGridFilter() {} int FillInputPortInformation(int, vtkInformation *info); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); private: vtkvmtkPolyDataToUnstructuredGridFilter(const vtkvmtkPolyDataToUnstructuredGridFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataToUnstructuredGridFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStaticTemporalInterpolatedVelocityField.h0000664000175000017500000001144411757446472025305 0ustar lucaluca/*========================================================================= Program: Visualization Toolkit Module: vtkvmtkStaticTemporalInterpolatedVelocityField.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 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) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkAbstractInterpolatedVelocityField.h" #include "vtkvmtkWin32Header.h" class vtkTable; class VTK_VMTK_MISC_EXPORT vtkvmtkStaticTemporalInterpolatedVelocityField : public vtkAbstractInterpolatedVelocityField { public: vtkTypeMacro( vtkvmtkStaticTemporalInterpolatedVelocityField, vtkAbstractInterpolatedVelocityField ); void PrintSelf( ostream & os, vtkIndent indent ); // Description: // Construct a vtkvmtkStaticTemporalInterpolatedVelocityField without an initial dataset. // Caching is set on and LastCellId is set to -1. static vtkvmtkStaticTemporalInterpolatedVelocityField * New(); // 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 ); 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); // Description: // Evaluate the velocity field f at point (x, y, z, t). virtual int FunctionValues( double * x, double * f ); // Description: // Set the cell id cached by the last evaluation within a specified dataset. virtual void SetLastCellId( vtkIdType c, int dataindex ); // Description: // Set the cell id cached by the last evaluation. virtual void SetLastCellId( vtkIdType c ) { this->Superclass::SetLastCellId( c ); } virtual void CopyParameters( vtkAbstractInterpolatedVelocityField * from ); 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 ); 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; private: vtkvmtkStaticTemporalInterpolatedVelocityField ( const vtkvmtkStaticTemporalInterpolatedVelocityField & ); // Not implemented. void operator = ( const vtkvmtkStaticTemporalInterpolatedVelocityField & ); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataBoundaryExtractor.cxx0000664000175000017500000001126411757446472023004 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBoundaryExtractor.cxx,v $ Language: C++ Date: $Date: 2006/07/27 08:27:40 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataBoundaryExtractor, "$Revision: 1.5 $"); 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())); // Declare vtkIdList *boundary, *boundaryIds, *cellEdgeNeighbors, *newCell; vtkIdType i, j, currentId, firstId, id, newId, id0, id1; vtkCell* cell; bool foundAny, foundNeighbor, done; vtkPoints* newPoints; vtkCellArray* newLines; vtkIdTypeArray* newScalars; newId = -1; // Initialize if ( ((input->GetNumberOfPoints()) < 1) ) { return 1; } 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; iGetNumberOfCells(); 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); } } } foundAny = false; foundNeighbor = false; done = false; currentId = -1; while (!done) { foundAny = false; foundNeighbor = false; for (i=0; iGetNumberOfIds(); i++) { id = boundaryIds->GetId(i); if (id!=-1) { foundAny = true; if ((currentId==-1)||(input->IsEdge(currentId,id))) { 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; jGetNumberOfIds(); 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; } } 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); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLinearizeMeshFilter.cxx0000664000175000017500000001663311757446472021601 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearizeMeshFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkLinearizeMeshFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPoints.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkIdTypeArray.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkLinearizeMeshFilter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkLinearizeMeshFilter); vtkvmtkLinearizeMeshFilter::vtkvmtkLinearizeMeshFilter() { this->CleanOutput = 1; } vtkvmtkLinearizeMeshFilter::~vtkvmtkLinearizeMeshFilter() { } int vtkvmtkLinearizeMeshFilter::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* outputPoints = vtkPoints::New(); vtkCellArray* outputCellArray = vtkCellArray::New(); vtkIdList* outputCellTypes = vtkIdList::New(); int numberOfPoints = input->GetNumberOfPoints(); int numberOfCells = input->GetNumberOfCells(); vtkPointData* inputPointData = input->GetPointData(); vtkPointData* outputPointData = output->GetPointData(); outputPointData->CopyAllocate(inputPointData,numberOfPoints); vtkCellData* inputCellData = input->GetCellData(); vtkCellData* outputCellData = output->GetCellData(); outputCellData->CopyAllocate(inputCellData,numberOfCells); vtkIdTypeArray* pointUsedArray = vtkIdTypeArray::New(); pointUsedArray->SetNumberOfTuples(numberOfPoints); pointUsedArray->FillComponent(0,0.0); vtkIdList* cellPoints = vtkIdList::New(); vtkIdList* outputCellPoints = vtkIdList::New(); int pointId; int outputCellId; int i,j; for (i=0; iGetCellType(i); cellPoints->Initialize(); input->GetCellPoints(i,cellPoints); outputCellPoints->Initialize(); switch (cellType) { case VTK_TRIANGLE: case VTK_QUADRATIC_TRIANGLE: for (j=0; j<3; j++) { pointId = cellPoints->GetId(j); outputCellPoints->InsertNextId(pointId); pointUsedArray->SetValue(pointId,1); } outputCellId = outputCellTypes->InsertNextId(VTK_TRIANGLE); outputCellArray->InsertNextCell(outputCellPoints); outputCellData->CopyData(inputCellData,i,outputCellId); break; case VTK_QUAD: case VTK_QUADRATIC_QUAD: #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_QUADRATIC_LINEAR_QUAD: case VTK_BIQUADRATIC_QUAD: #endif for (j=0; j<4; j++) { pointId = cellPoints->GetId(j); outputCellPoints->InsertNextId(pointId); pointUsedArray->SetValue(pointId,1); } outputCellId = outputCellTypes->InsertNextId(VTK_QUAD); outputCellArray->InsertNextCell(outputCellPoints); outputCellData->CopyData(inputCellData,i,outputCellId); break; case VTK_TETRA: case VTK_QUADRATIC_TETRA: for (j=0; j<4; j++) { pointId = cellPoints->GetId(j); outputCellPoints->InsertNextId(pointId); pointUsedArray->SetValue(pointId,1); } outputCellId = outputCellTypes->InsertNextId(VTK_TETRA); outputCellArray->InsertNextCell(outputCellPoints); outputCellData->CopyData(inputCellData,i,outputCellId); break; case VTK_HEXAHEDRON: case VTK_QUADRATIC_HEXAHEDRON: #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_HEXAHEDRON: case VTK_TRIQUADRATIC_HEXAHEDRON: #endif for (j=0; j<8; j++) { pointId = cellPoints->GetId(j); outputCellPoints->InsertNextId(pointId); pointUsedArray->SetValue(pointId,1); } outputCellId = outputCellTypes->InsertNextId(VTK_HEXAHEDRON); outputCellArray->InsertNextCell(outputCellPoints); outputCellData->CopyData(inputCellData,i,outputCellId); break; case VTK_WEDGE: case VTK_QUADRATIC_WEDGE: #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: #endif for (j=0; j<6; j++) { pointId = cellPoints->GetId(j); outputCellPoints->InsertNextId(pointId); pointUsedArray->SetValue(pointId,1); } outputCellId = outputCellTypes->InsertNextId(VTK_WEDGE); outputCellArray->InsertNextCell(outputCellPoints); outputCellData->CopyData(inputCellData,i,outputCellId); break; default: vtkWarningMacro(<<"Unsupported element to linearize. Skipping element."); break; } } vtkIdTypeArray* pointIdMapArray = vtkIdTypeArray::New(); pointIdMapArray->SetNumberOfTuples(numberOfPoints); for (i=0; iCleanOutput) { if (!pointUsedArray->GetValue(i)) { continue; } } pointId = outputPoints->InsertNextPoint(input->GetPoint(i)); outputPointData->CopyData(inputPointData,i,pointId); pointIdMapArray->SetValue(i,pointId); } vtkCellArray* remappedOutputCellArray = vtkCellArray::New(); int numberOfOutputCells = outputCellArray->GetNumberOfCells(); outputCellArray->InitTraversal(); vtkIdType npts = 0; vtkIdType *pts = NULL; for (i=0; iGetNextCell(npts,pts); outputCellPoints->Initialize(); for (j=0; jInsertNextId(pointIdMapArray->GetValue(pts[j])); } remappedOutputCellArray->InsertNextCell(outputCellPoints); } output->GetPointData()->Squeeze(); output->GetCellData()->Squeeze(); output->SetPoints(outputPoints); int* outputCellTypesInt = new int[outputCellTypes->GetNumberOfIds()]; for (i=0; iGetNumberOfIds(); i++) { outputCellTypesInt[i] = outputCellTypes->GetId(i); } output->SetCells(outputCellTypesInt,remappedOutputCellArray); delete[] outputCellTypesInt; outputPoints->Delete(); outputCellArray->Delete(); remappedOutputCellArray->Delete(); outputCellTypes->Delete(); pointUsedArray->Delete(); pointIdMapArray->Delete(); cellPoints->Delete(); outputCellPoints->Delete(); return 1; } void vtkvmtkLinearizeMeshFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSurfaceProjection.h0000664000175000017500000000347111757446472020742 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfaceProjection.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSurfaceProjection - ... // .SECTION Description // . #ifndef __vtkvmtkSurfaceProjection_h #define __vtkvmtkSurfaceProjection_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class VTK_VMTK_MISC_EXPORT vtkvmtkSurfaceProjection : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkSurfaceProjection,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSurfaceProjection *New(); // Description: // Set/Get the reference surface to compute distance from. vtkSetObjectMacro(ReferenceSurface,vtkPolyData); vtkGetObjectMacro(ReferenceSurface,vtkPolyData); protected: vtkvmtkSurfaceProjection(); ~vtkvmtkSurfaceProjection(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkPolyData *ReferenceSurface; private: vtkvmtkSurfaceProjection(const vtkvmtkSurfaceProjection&); // Not implemented. void operator=(const vtkvmtkSurfaceProjection&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshVelocityStatistics.h0000664000175000017500000000350611757446472022002 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshVelocityStatistics.h,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .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: vtkTypeRevisionMacro(vtkvmtkMeshVelocityStatistics,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkMeshVelocityStatistics *New(); vtkSetObjectMacro(VelocityArrayIds,vtkIdList); vtkGetObjectMacro(VelocityArrayIds,vtkIdList); protected: vtkvmtkMeshVelocityStatistics(); ~vtkvmtkMeshVelocityStatistics(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdList* VelocityArrayIds; private: vtkvmtkMeshVelocityStatistics(const vtkvmtkMeshVelocityStatistics&); // Not implemented. void operator=(const vtkvmtkMeshVelocityStatistics&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkSurfMeshWrapper.cxx0000664000175000017500000000703711757446472020767 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfMeshWrapper.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSurfMeshWrapper.h" #include "vtkPolyData.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "SurfaceMesher.h" vtkCxxRevisionMacro(vtkvmtkSurfMeshWrapper, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkSurfMeshWrapper); vtkvmtkSurfMeshWrapper::vtkvmtkSurfMeshWrapper() { this->NodeSpacing = 0.1; } vtkvmtkSurfMeshWrapper::~vtkvmtkSurfMeshWrapper() { } class Remesh : public SurfaceMesher::RemeshSurface { public: Remesh() { this->NodeSpacing = 0.1; } Remesh(real nodeSpacing) { this->NodeSpacing = nodeSpacing; } real NodeSpace(real *x) { return this->NodeSpacing; } private: real NodeSpacing; }; int vtkvmtkSurfMeshWrapper::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())); Remesh *nb = new Remesh(this->NodeSpacing); int numberOfInputPoints = input->GetNumberOfPoints(); nb->SetNumberOfPoints(numberOfInputPoints); double point[3]; real xpos[3]; int i; for (i=0; iGetPoint(i,point); xpos[0] = static_cast(point[0]); xpos[1] = static_cast(point[1]); xpos[2] = static_cast(point[2]); nb->AddPoint(i,xpos[0],xpos[1],xpos[2]); } input->BuildCells(); int numberOfInputCells = input->GetNumberOfCells(); vtkIdType npts, *pts; for (i=0; iGetCellType(i) != VTK_TRIANGLE) { continue; } input->GetCellPoints(i,npts,pts); nb->AddTriangle(pts[0],pts[1],pts[2]); } try { nb->Run2D(); } catch(Error *e) { e->Print(std::cerr); } nb->IterateOnOutput(false); vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputCellArray = vtkCellArray::New(); while (nb->NextNode(xpos)!=-1) { point[0] = static_cast(xpos[0]); point[1] = static_cast(xpos[1]); point[2] = static_cast(xpos[2]); outputPoints->InsertNextPoint(point); } int icorn[3]; while (nb->NextCell(icorn)) { outputCellArray->InsertNextCell(3,icorn); } output->SetPoints(outputPoints); output->SetPolys(outputCellArray); outputPoints->Delete(); outputCellArray->Delete(); delete nb; return 1; } void vtkvmtkSurfMeshWrapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkLinearToQuadraticMeshFilter.cxx0000664000175000017500000007625711757446472023242 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearToQuadraticMeshFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkLinearToQuadraticMeshFilter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkLinearToQuadraticMeshFilter); vtkvmtkLinearToQuadraticMeshFilter::vtkvmtkLinearToQuadraticMeshFilter() { this->UseBiquadraticWedge = 1; 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; iInsertNextPoint(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(); int numberOfInputCells = numberOfInputTetras + numberOfInputTriangles + numberOfInputWedges; output->SetPoints(outputPoints); output->Allocate(numberOfInputCells); int numberOfCells = input->GetNumberOfCells(); vtkIdList* inputToOutputCellIds = vtkIdList::New(); inputToOutputCellIds->SetNumberOfIds(numberOfInputCells); for (i=0; iSetId(i,-1); } vtkIdType cellId; double point0[3], point1[3], point2[3], point3[3], point4[3], point5[3]; vtkIdType pointId0, pointId1, pointId2, pointId3, pointId4, pointId5; double point[3]; vtkIdType edgePointId01, edgePointId02, edgePointId03, edgePointId12, edgePointId13, edgePointId23; vtkIdType edgePointId14, edgePointId34, edgePointId45, edgePointId35, edgePointId25; vtkIdType facePointId0143, facePointId1254, facePointId2035; facePointId0143 = facePointId1254 = facePointId2035 = -1; vtkIdType neighborCellId; vtkIdType pts[18]; double weights[4]; weights[0] = weights[1] = weights[2] = weights[3] = 0.25; vtkIdList* facePointIds = vtkIdList::New(); vtkIdList* cellNeighbors = vtkIdList::New(); for (i=0; iGetValue(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; jGetNumberOfIds(); 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; jGetNumberOfIds(); 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; jGetNumberOfIds(); 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; iGetValue(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); } 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(); surfaceEdgeTable->InitEdgeInsertion(numberOfInputPoints,1); for (i=0; iGetValue(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); } } //#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; iGetValue(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 "<Delete(); continue; } if (volumeCellIds->GetNumberOfIds() > 1) { vtkWarningMacro(<<"Warning: surface element "<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; sHasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell)) { break; } anySignChange = true; vtkWarningMacro(<<"Warning: projection causes element "<SetPoint(edgePointId01,point01); outputPoints->SetPoint(edgePointId12,point12); outputPoints->SetPoint(edgePointId02,point02); 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; iGetId(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; sHasJacobianChangedSign(linearVolumeCell,quadraticVolumeCell)) { break; } anySignChange = true; vtkWarningMacro(<<"Warning: projection causes element "<GetNumberOfEdges(); int e; for (e=0; eGetEdge(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 if (this->TestFinalJacobians) { for (i=0; iGetCell(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 "<Delete(); outputPoints->Delete(); edgeTable->Delete(); faceTable->Delete(); triangleIds->Delete(); tetraIds->Delete(); wedgeIds->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; jGetPoints()->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; qGetQuadraturePoint(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; qComputeJacobian(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); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshWallShearRate.h0000664000175000017500000000441311757446472020625 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshWallShearRate.h,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // . #ifndef __vtkvmtkMeshWallShearRate_h #define __vtkvmtkMeshWallShearRate_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkMeshWallShearRate : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkMeshWallShearRate,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkMeshWallShearRate *New(); vtkSetStringMacro(VelocityArrayName); vtkGetStringMacro(VelocityArrayName); vtkSetStringMacro(WallShearRateArrayName); vtkGetStringMacro(WallShearRateArrayName); vtkSetMacro(ComputeIndividualPartialDerivatives,int); vtkGetMacro(ComputeIndividualPartialDerivatives,int); vtkBooleanMacro(ComputeIndividualPartialDerivatives,int); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); protected: vtkvmtkMeshWallShearRate(); ~vtkvmtkMeshWallShearRate(); int FillInputPortInformation(int, vtkInformation *info); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* VelocityArrayName; char* WallShearRateArrayName; int ComputeIndividualPartialDerivatives; double ConvergenceTolerance; int QuadratureOrder; private: vtkvmtkMeshWallShearRate(const vtkvmtkMeshWallShearRate&); // Not implemented. void operator=(const vtkvmtkMeshWallShearRate&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkPolyDataNetworkExtraction.cxx0000664000175000017500000020451211757446472023017 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataNetworkExtraction.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataNetworkExtraction.h" #include "vtkCleanPolyData.h" #include "vtkStripper.h" #include "vtkAppendPolyData.h" #include "vtkFeatureEdges.h" #include "vtkMath.h" #include "vtkPolyDataCollection.h" #include "vtkCollection.h" #include "vtkPolyData.h" #include "vtkCellArray.h" #include "vtkPoints.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyLine.h" #include "vtkIdTypeArray.h" #include "vtkDoubleArray.h" #include "vtkLine.h" #include "vtkCommand.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataNetworkExtraction, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkPolyDataNetworkExtraction); vtkvmtkPolyDataNetworkExtraction::vtkvmtkPolyDataNetworkExtraction() { this->MarksArrayName = new char[256]; strcpy(this->MarksArrayName,"Marks"); this->RadiusArrayName = new char[256]; strcpy(this->RadiusArrayName,"Radius"); this->TopologyArrayName = new char[256]; strcpy(this->TopologyArrayName,"Topology"); this->MinimumStep = 5E-4; this->TotalMarkedPoints = 0; this->GraphLayout = NULL; } vtkvmtkPolyDataNetworkExtraction::~vtkvmtkPolyDataNetworkExtraction() { if (this->MarksArrayName) { delete[] this->MarksArrayName; this->MarksArrayName = NULL; } if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->TopologyArrayName) { delete[] this->TopologyArrayName; this->TopologyArrayName = NULL; } if (this->GraphLayout) { this->GraphLayout->Delete(); this->GraphLayout = NULL; } } void vtkvmtkPolyDataNetworkExtraction::BoundaryExtractor(vtkPolyData* polyInput, vtkPolyData* boundary) { if (polyInput->GetNumberOfCells()==0) { return; } vtkFeatureEdges *boundaryExtractor = vtkFeatureEdges::New(); boundaryExtractor->BoundaryEdgesOn(); boundaryExtractor->FeatureEdgesOff(); boundaryExtractor->NonManifoldEdgesOff(); boundaryExtractor->ManifoldEdgesOff(); boundaryExtractor->SetInput(polyInput); boundaryExtractor->Update(); if (boundaryExtractor->GetOutput()->GetNumberOfCells()==0) { boundaryExtractor->Delete(); return; } vtkCleanPolyData *boundaryExtractorCleaner = vtkCleanPolyData::New(); boundaryExtractorCleaner->SetInput(boundaryExtractor->GetOutput()); vtkStripper *boundaryExtractorStripper = vtkStripper::New(); boundaryExtractorStripper->SetInput(boundaryExtractorCleaner->GetOutput()); boundaryExtractorStripper->Update(); boundary->DeepCopy(boundaryExtractorStripper->GetOutput()); boundary->Update(); boundaryExtractorStripper->Delete(); boundaryExtractorCleaner->Delete(); boundaryExtractor->Delete(); } void vtkvmtkPolyDataNetworkExtraction::BoundarySeparator(vtkPolyData* appendedBoundaries, vtkPolyDataCollection* boundaries) { appendedBoundaries->BuildLinks(); appendedBoundaries->Update(); vtkIdType i; for (i=0; iGetNumberOfCells(); i++) { vtkPoints* boundaryPoints = vtkPoints::New(); vtkCellArray* boundaryCellArray = vtkCellArray::New(); vtkIdType npts, *pts; appendedBoundaries->GetCellPoints(i,npts,pts); boundaryCellArray->InsertNextCell(npts+1); vtkIdType j; for (j=0; jInsertNextPoint(appendedBoundaries->GetPoint(pts[j])); boundaryCellArray->InsertCellPoint(j); } boundaryCellArray->InsertCellPoint(0); vtkPolyData* boundary = vtkPolyData::New(); boundary->SetPoints(boundaryPoints); boundary->SetLines(boundaryCellArray); boundary->Update(); boundaries->AddItem(boundary); boundary->Delete(); boundaryPoints->Delete(); boundaryCellArray->Delete(); } } void vtkvmtkPolyDataNetworkExtraction::InsertInEdgeTable(vtkIdTypeArray* edgeTable, vtkIdType pointId0, vtkIdType pointId1) { vtkIdType edge[2]; edge[0] = pointId0; edge[1] = pointId1; edgeTable->InsertNextTupleValue(edge); } bool vtkvmtkPolyDataNetworkExtraction::InsertUniqueInEdgeTable(vtkIdTypeArray* edgeTable, vtkIdType pointId0, vtkIdType pointId1) { vtkIdType edge[2]; edge[0] = pointId0; edge[1] = pointId1; vtkIdType i; for (i=0; iGetNumberOfTuples(); i++) { vtkIdType currentEdge[2]; edgeTable->GetTupleValue(i,currentEdge); if (currentEdge[0]==edge[0] && currentEdge[1]==edge[1]) { return false; } } edgeTable->InsertNextTupleValue(edge); return true; } void vtkvmtkPolyDataNetworkExtraction::GetFromEdgeTable(vtkIdTypeArray* edgeTable, vtkIdType position, vtkIdType edge[2]) { edgeTable->GetTupleValue(position,edge); } void vtkvmtkPolyDataNetworkExtraction::UpdateEdgeTableCollectionReal(vtkPolyData* model,vtkPolyDataCollection* profiles,vtkCollection* edgeTables) { profiles->InitTraversal(); vtkIdType j; for (j=0; jGetNumberOfItems(); j++) { vtkPolyData* profile=profiles->GetNextItem(); profile->Update(); vtkIdTypeArray* edgeTable = vtkIdTypeArray::New(); edgeTable->SetNumberOfComponents(2); vtkIdType i; for (i=0; iGetNumberOfPoints(); i++) { vtkIdType modelPointId = model->FindPoint(profile->GetPoint(i)); this->InsertInEdgeTable(edgeTable,modelPointId,modelPointId); } edgeTables->AddItem(edgeTable); edgeTable->Delete(); } } double vtkvmtkPolyDataNetworkExtraction::Distance(double point1[3], double point2[3]) { return sqrt(vtkMath::Distance2BetweenPoints(point1,point2)); } double vtkvmtkPolyDataNetworkExtraction::GetFurthestDistance(vtkPolyDataCollection* polyDataCollection, double fromPoint[3]) { vtkIdType i,j; double dist, maxDist = 0.0; polyDataCollection->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* item = polyDataCollection->GetNextItem(); for (j=0; jGetNumberOfPoints(); j++) { dist = vtkMath::Distance2BetweenPoints(item->GetPoint(j),fromPoint); if (dist > maxDist) { maxDist = dist; } } } return sqrt(maxDist); } void vtkvmtkPolyDataNetworkExtraction::Barycenter(vtkPoints* points, double barycenter[3]) { vtkIdType numberOfPoints = points->GetNumberOfPoints(); vtkIdType i,j; for (i=0; i<3; i++) { double sum = 0.0; for (j=0; jGetPoint(j))[i]); } barycenter[i] = sum / numberOfPoints; } } void vtkvmtkPolyDataNetworkExtraction::ProfileBarycenter(vtkPoints* points, double barycenter[3]) { vtkIdType numberOfPoints = points->GetNumberOfPoints(); if (numberOfPoints == 0) { barycenter[0] = barycenter[1] = barycenter[2] = 0.0; return; } vtkDoubleArray* lineLengths = vtkDoubleArray::New(); double totalLength = 0.0; vtkIdType i; for (i=0; iGetPoint(i,point0); if (i < numberOfPoints-1) { points->GetPoint(i+1,point1); } else { points->GetPoint(0,point1); } double lineLength = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); lineLengths->InsertNextValue(lineLength); totalLength += lineLength; } if (totalLength == 0.0) { points->GetPoint(0,barycenter); lineLengths->Delete(); return; } vtkDoubleArray* pointWeights = vtkDoubleArray::New(); for (i=0; iGetValue(i-1); } else { length0 = lineLengths->GetValue(numberOfPoints-1); } double length1 = lineLengths->GetValue(i); double pointWeight = (length0 + length1) / 2.0; pointWeights->InsertNextValue(pointWeight); } for (i=0; i<3; i++) { double sum = 0.0; vtkIdType j; for (j=0; jGetPoint(j)[i]; double weight = pointWeights->GetValue(j); sum += pointCoord * weight; } barycenter[i] = sum / totalLength; } lineLengths->Delete(); pointWeights->Delete(); } void vtkvmtkPolyDataNetworkExtraction::DefineVirtualSphere(vtkPolyDataCollection* baseProfiles, double center[3], double &radius, double ratio) { vtkPoints* barycenters = vtkPoints::New(); baseProfiles->InitTraversal(); vtkIdType i; for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* baseProfile = baseProfiles->GetNextItem(); baseProfile->Update(); double barycenter[3]; this->ProfileBarycenter(baseProfile->GetPoints(),barycenter); barycenters->InsertNextPoint(barycenter); } this->Barycenter(barycenters,center); barycenters->Delete(); double distance = this->GetFurthestDistance(baseProfiles,center); radius = distance * ratio; } vtkIdType vtkvmtkPolyDataNetworkExtraction::CurrentPointId(vtkPolyData* model,vtkIdType currentEdge[2]) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); vtkIdType currentPointId; if (currentEdge[0] != currentEdge[1]) { if (marksArray->GetValue(currentEdge[1]) == NON_VISITED) { currentPointId = currentEdge[1]; } else if (marksArray->GetValue(currentEdge[0]) == NON_VISITED) { currentPointId = currentEdge[0]; } else { currentPointId = -1; } } else { currentPointId = currentEdge[0]; } return currentPointId; } void vtkvmtkPolyDataNetworkExtraction::InsertEdgeForNewProfiles(vtkPolyData* model, vtkIdType* edge, vtkIdTypeArray* edgeTable, vtkIdTypeArray* cellPairs, vtkIdList* pointIds) { if (this->InsertUniqueInEdgeTable(edgeTable,edge[0],edge[1])) { unsigned short ncells0; vtkIdType *cell0; model->GetPointCells(edge[0],ncells0,cell0); unsigned short ncells1; vtkIdType *cell1; model->GetPointCells(edge[1],ncells1,cell1); vtkIdType cellPair[2]; cellPair[0] = -1; cellPair[1] = -1; vtkIdType i,j; for (i=0; iInsertInEdgeTable(cellPairs,cellPair[0],cellPair[1]); pointIds->InsertUniqueId(edge[0]); pointIds->InsertUniqueId(edge[1]); } } bool vtkvmtkPolyDataNetworkExtraction::LookForNeighbors(vtkPolyData* model, vtkIdType pointId, vtkIdList* notVisitedIds, vtkIdTypeArray* edgeTableForIncludedGlobalProfiles) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); bool someNeighborsFound = false; // return non visited neighbors, and true if there are any, false otherwise unsigned short ncells; vtkIdType *cell; model->GetPointCells(pointId,ncells,cell); vtkIdType i; for (i=0; iGetCellPoints(cell[i],npts,pts); vtkIdType j; for (j=0; jGetValue(pts[j]); if (scalar == NON_VISITED) { notVisitedIds->InsertUniqueId(pts[j]); someNeighborsFound=true; } else if (scalar == GLOBAL) { this->InsertInEdgeTable(edgeTableForIncludedGlobalProfiles,pointId,pts[j]); } } } } return someNeighborsFound; } void vtkvmtkPolyDataNetworkExtraction::PropagateFromBaseProfilePoint(vtkPolyData* model, vtkIdList* toVisitPointIds, double center[3], double radius, vtkIdTypeArray* edgeTableForNewProfiles, vtkIdTypeArray* cellPairsForNewProfiles, vtkIdList* pointIdsForNewProfiles, vtkPoints* markedPoints, vtkIdList* markedPointIds, vtkIdTypeArray* edgeTableForIncludedGlobalProfiles) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); while (toVisitPointIds->GetNumberOfIds()) { vtkIdType currentPointId = toVisitPointIds->GetId(0); if (marksArray->GetValue(currentPointId) == NON_VISITED) { marksArray->InsertValue(currentPointId,VISITED); if (markedPointIds->IsId(currentPointId)==-1) { double markedPoint[3]; model->GetPoint(currentPointId,markedPoint); markedPoints->InsertNextPoint(markedPoint); markedPointIds->InsertNextId(currentPointId); } } // call LookForNeighbors, compare distances and call PropagateFromBaseProfilePovtkIdType again is povtkIdType // is non visited and falls inside the sphere. If it falls outside add adge to edge list vtkIdList* notVisitedNeighbors = vtkIdList::New(); if (LookForNeighbors(model,currentPointId,notVisitedNeighbors,edgeTableForIncludedGlobalProfiles)) { marksArray->InsertValue(currentPointId,VISITED); vtkIdType edge[2]; vtkIdType i; for (i=0; iGetNumberOfIds(); i++) { double point[3]; model->GetPoint(notVisitedNeighbors->GetId(i),point); if (this->Distance(center,point) > radius) { edge[0]=currentPointId; edge[1]=notVisitedNeighbors->GetId(i); this->InsertEdgeForNewProfiles(model,edge,edgeTableForNewProfiles,cellPairsForNewProfiles,pointIdsForNewProfiles); } else { toVisitPointIds->InsertUniqueId(notVisitedNeighbors->GetId(i)); } } } toVisitPointIds->DeleteId(currentPointId); notVisitedNeighbors->Delete(); } } void vtkvmtkPolyDataNetworkExtraction::LocateVirtualPoint(vtkIdType edge[2], double center[3], double radius, vtkIdList* pointIdsForNewProfiles, vtkPoints* pointsForNewProfiles, vtkDoubleArray* pointDistancesForNewProfiles, double virtualPoint[3]) { virtualPoint[0] = virtualPoint[1] = virtualPoint[2] = 0.0; vtkIdType position0 = pointIdsForNewProfiles->IsId(edge[0]); vtkIdType position1 = pointIdsForNewProfiles->IsId(edge[1]); double point0[3], point1[3]; pointsForNewProfiles->GetPoint(position0,point0); pointsForNewProfiles->GetPoint(position1,point1); double distance0 = pointDistancesForNewProfiles->GetValue(position0); double distance1 = pointDistancesForNewProfiles->GetValue(position1); double distance2 = vtkMath::Distance2BetweenPoints(point0,point1); if (radius > 0.0 && distance2 > 1E-12) { double h2 = vtkLine::DistanceToLine(center,point0,point1); double distance = sqrt(distance2); double b = 0.0; if (radius*radius - h2 > 0.0) { b = sqrt(radius*radius - h2); } double a = 0.0; if (distance0*distance0 - h2 > 0.0) { a = sqrt(distance0*distance0 - h2); } double parametricCoordinate = 0.0; if (distance2 < (distance1*distance1 - h2)) { parametricCoordinate = b - a; } else { parametricCoordinate = b + a; } virtualPoint[0] = point0[0] + parametricCoordinate * (point1[0]-point0[0]) / distance; virtualPoint[1] = point0[1] + parametricCoordinate * (point1[1]-point0[1]) / distance; virtualPoint[2] = point0[2] + parametricCoordinate * (point1[2]-point0[2]) / distance; } else { if (distance0GetNumberOfPoints(); i++) { notVisitedIds->InsertNextId(i); } while (notVisitedIds->GetNumberOfIds()) { vtkPolyData* newProfile = vtkPolyData::New(); vtkPoints* newProfilePoints = vtkPoints::New(); newProfile->SetPoints(newProfilePoints); vtkIdTypeArray* newProfileEdgeTable = vtkIdTypeArray::New(); newProfileEdgeTable->SetNumberOfComponents(2); vtkIdType cellPair0[2]; vtkIdType position1 = notVisitedIds->GetId(0); this->GetFromEdgeTable(cellPairs,position1,cellPair0); vtkIdType initialCellId = cellPair0[0]; vtkIdType cellIdToSearch = cellPair0[1]; newProfile->GetPoints()->InsertNextPoint(virtualPoints->GetPoint(position1)); vtkIdType newProfileEdge[2]; this->GetFromEdgeTable(edgeTable,position1,newProfileEdge); notVisitedIds->DeleteId(position1); this->InsertInEdgeTable(newProfileEdgeTable,newProfileEdge[0],newProfileEdge[1]); bool closed = false; vtkIdType cellPair1[2]; while (!closed) { bool foundNext = false; vtkIdType j = 0; while (!foundNext) { if (j >= notVisitedIds->GetNumberOfIds()) { vtkErrorMacro(<<"Error: can't reconstruct new profile."); return; } vtkIdType position2 = notVisitedIds->GetId(j); this->GetFromEdgeTable(cellPairs,position2,cellPair1); if (cellPair1[0] == cellIdToSearch) { double virtualPoint[3]; virtualPoints->GetPoint(position2,virtualPoint); newProfile->GetPoints()->InsertNextPoint(virtualPoint); this->GetFromEdgeTable(edgeTable,position2,newProfileEdge); this->InsertInEdgeTable(newProfileEdgeTable,newProfileEdge[0],newProfileEdge[1]); foundNext = true; notVisitedIds->DeleteId(position2); cellIdToSearch = cellPair1[1]; } else if (cellPair1[1] == cellIdToSearch) { double virtualPoint[3]; virtualPoints->GetPoint(position2,virtualPoint); newProfile->GetPoints()->InsertNextPoint(virtualPoint); this->GetFromEdgeTable(edgeTable,position2,newProfileEdge); this->InsertInEdgeTable(newProfileEdgeTable,newProfileEdge[0],newProfileEdge[1]); foundNext = true; notVisitedIds->DeleteId(position2); cellIdToSearch = cellPair1[0]; } j++; } if (cellIdToSearch == initialCellId) { closed = true; } } vtkCellArray* newProfileLines = vtkCellArray::New(); newProfileLines->InsertNextCell(newProfile->GetNumberOfPoints() + 1); vtkIdType i; for (i=0; iGetNumberOfPoints(); i++) { newProfileLines->InsertCellPoint(i); } newProfileLines->InsertCellPoint(0); newProfile->SetLines(newProfileLines); newProfile->Update(); newProfiles->AddItem(newProfile); newProfilesEdgeTables->AddItem(newProfileEdgeTable); newProfile->Delete(); newProfilePoints->Delete(); newProfileLines->Delete(); newProfileEdgeTable->Delete(); } notVisitedIds->Delete(); } void vtkvmtkPolyDataNetworkExtraction::GenerateNewProfiles(vtkPolyData* model, double center[3], double radius, vtkIdTypeArray* edgeTableForNewProfiles, vtkIdTypeArray* cellPairsForNewProfiles, vtkIdList* pointIdsForNewProfiles, vtkPolyDataCollection* newProfiles, vtkCollection* newProfilesEdgeTables) { if (edgeTableForNewProfiles->GetNumberOfTuples()) { vtkPoints* pointsForNewProfiles = vtkPoints::New(); vtkDoubleArray* pointDistancesForNewProfiles = vtkDoubleArray::New(); vtkIdType i; for (i=0; iGetNumberOfIds(); i++) { double point[3]; model->GetPoint(pointIdsForNewProfiles->GetId(i),point); pointsForNewProfiles->InsertNextPoint(point); pointDistancesForNewProfiles->InsertNextValue(Distance(center,point)); } vtkPoints* virtualPointsForNewProfiles = vtkPoints::New(); vtkIdType edge[2]; for (i=0; iGetNumberOfTuples(); i++) { this->GetFromEdgeTable(edgeTableForNewProfiles,i,edge); double virtualPoint[3]; this->LocateVirtualPoint(edge,center,radius,pointIdsForNewProfiles,pointsForNewProfiles,pointDistancesForNewProfiles,virtualPoint); virtualPointsForNewProfiles->InsertNextPoint(virtualPoint); } this->ReconstructNewProfiles(virtualPointsForNewProfiles,edgeTableForNewProfiles,cellPairsForNewProfiles,newProfiles,newProfilesEdgeTables); pointsForNewProfiles->Delete(); pointDistancesForNewProfiles->Delete(); virtualPointsForNewProfiles->Delete(); } } void vtkvmtkPolyDataNetworkExtraction::UnmarkPoints(vtkPolyData* model, vtkIdList* markedPointIds) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); vtkIdType i; for (i=0; iGetNumberOfIds(); i++) { marksArray->InsertValue(markedPointIds->GetId(i),NON_VISITED); } } double vtkvmtkPolyDataNetworkExtraction::ComputeStepRadius(vtkPoints* points, double point1[3], double point2[3]) { vtkIdType i; double radius = 0.0; for (i=0; iGetNumberOfPoints(); i++) { double point[3]; points->GetPoint(i,point); radius += sqrt(vtkLine::DistanceToLine(point,point1,point2)); } radius /= points->GetNumberOfPoints(); return radius; } double vtkvmtkPolyDataNetworkExtraction::ComputeMeanRadius(vtkPoints* points, double point1[3]) { vtkIdType i; double radius = 0.0; for (i=0; iGetNumberOfPoints(); i++) { double point[3]; points->GetPoint(i,point); radius += sqrt(vtkMath::Distance2BetweenPoints(point,point1)); } radius /= points->GetNumberOfPoints(); return radius; } void vtkvmtkPolyDataNetworkExtraction::PointsForRadius(vtkPoints *markedPoints, vtkPolyDataCollection *baseProfiles, vtkPolyDataCollection *newProfiles, vtkPoints *pointsForRadius) { vtkIdType i,j; if (markedPoints) { for (i=0; iGetNumberOfPoints(); i++) { pointsForRadius->InsertNextPoint(markedPoints->GetPoint(i)); } } if (baseProfiles) { baseProfiles->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPoints *baseProfilePoints = baseProfiles->GetNextItem()->GetPoints(); for (j=0; jGetNumberOfPoints(); j++) { pointsForRadius->InsertNextPoint(baseProfilePoints->GetPoint(j)); } } } if (newProfiles) { newProfiles->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPoints *newProfilePoints = newProfiles->GetNextItem()->GetPoints(); for (j=0; jGetNumberOfPoints(); j++) { pointsForRadius->InsertNextPoint(newProfilePoints->GetPoint(j)); } } } } void vtkvmtkPolyDataNetworkExtraction::LookForIntersectingPoint(vtkPoints* segmentPoints, double center[3], double radius, vtkIdType &intersectingPointId) { intersectingPointId = segmentPoints->GetNumberOfPoints()-1; vtkIdType i; for (i=segmentPoints->GetNumberOfPoints()-2; i>=0; i--) { double segmentPoint[3]; segmentPoints->GetPoint(i,segmentPoint); if (this->Distance(center,segmentPoint)>radius) { intersectingPointId = i+1; break; } } } vtkIdType vtkvmtkPolyDataNetworkExtraction::StepIteration(vtkPolyData* model, vtkPolyDataCollection* baseProfiles, vtkCollection* baseProfilesEdgeTables, vtkPolyDataCollection* globalProfiles, vtkCollection* globalProfilesEdgeTables, vtkPolyDataCollection* newProfiles, vtkCollection* newProfilesEdgeTables, vtkPoints* segmentPoints, vtkDoubleArray* segmentRadii, vtkPoints* bifurcationPoints, vtkDoubleArray* bifurcationRadii, double oldCenter[3], double &oldRadius, double advancementRatio) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); double center[3]; double radius; this->DefineVirtualSphere(baseProfiles,center,radius,advancementRatio); bool sameCenter = false; if (oldRadius > 0.0) { if (this->Distance(center,oldCenter) < this->MinimumStep && radius <= oldRadius) { radius = 2.0 * oldRadius; sameCenter = true; } } // now propagate and build virtual profile(s) vtkIdTypeArray* edgeTableForNewProfiles = vtkIdTypeArray::New(); edgeTableForNewProfiles->SetNumberOfComponents(2); vtkIdTypeArray* cellPairsForNewProfiles = vtkIdTypeArray::New(); cellPairsForNewProfiles->SetNumberOfComponents(2); vtkIdList* pointIdsForNewProfiles = vtkIdList::New(); //for doubleScalars mapping vtkIdTypeArray* edgeTableForIncludedGlobalProfiles = vtkIdTypeArray::New(); edgeTableForIncludedGlobalProfiles->SetNumberOfComponents(2); vtkPoints* markedPoints = vtkPoints::New(); vtkIdList* markedPointIds = vtkIdList::New(); vtkIdType i; baseProfiles->InitTraversal(); baseProfilesEdgeTables->InitTraversal(); vtkIdList* old2MarkedPointIds = vtkIdList::New(); for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* baseProfile = baseProfiles->GetNextItem(); vtkIdTypeArray* baseProfileEdgeTable = (vtkIdTypeArray*)baseProfilesEdgeTables->GetNextItemAsObject(); vtkIdType j; for (j=0; jGetNumberOfPoints(); j++) { vtkIdType currentEdge[2]; this->GetFromEdgeTable(baseProfileEdgeTable,j,currentEdge); if (marksArray->GetValue(currentEdge[0]) == GLOBAL) { marksArray->InsertValue(currentEdge[0],VISITED); old2MarkedPointIds->InsertNextId(currentEdge[0]); } } } // propagate from base profiles baseProfiles->InitTraversal(); baseProfilesEdgeTables->InitTraversal(); vtkIdList* toVisitPointIds = vtkIdList::New(); for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* baseProfile = baseProfiles->GetNextItem(); vtkIdTypeArray* baseProfileEdgeTable = (vtkIdTypeArray*)baseProfilesEdgeTables->GetNextItemAsObject(); vtkIdType j; for (j=0; jGetNumberOfPoints(); j++) { vtkIdType currentEdge[2]; this->GetFromEdgeTable(baseProfileEdgeTable,j,currentEdge); vtkIdType currentPointId = CurrentPointId(model,currentEdge); if (marksArray->GetValue(currentEdge[1]) == GLOBAL) { this->InsertInEdgeTable(edgeTableForIncludedGlobalProfiles,currentEdge[0],currentEdge[1]); } if (currentPointId!=-1) { if (this->Distance(model->GetPoint(currentPointId),center)>radius) { this->InsertEdgeForNewProfiles(model,currentEdge,edgeTableForNewProfiles,cellPairsForNewProfiles,pointIdsForNewProfiles); } else { toVisitPointIds->InsertNextId(currentPointId); } } } } this->PropagateFromBaseProfilePoint(model,toVisitPointIds,center,radius,edgeTableForNewProfiles,cellPairsForNewProfiles,pointIdsForNewProfiles,markedPoints,markedPointIds,edgeTableForIncludedGlobalProfiles); toVisitPointIds->Delete(); for (i=0; iGetNumberOfIds(); i++) { marksArray->InsertValue(old2MarkedPointIds->GetId(i),GLOBAL); } old2MarkedPointIds->Delete(); if (edgeTableForIncludedGlobalProfiles->GetNumberOfTuples() > 0) { vtkIdTypeArray* edgeTableForEffectiveIncludedGlobalProfiles = vtkIdTypeArray::New(); edgeTableForEffectiveIncludedGlobalProfiles->SetNumberOfComponents(2); vtkIdType i; for (i=0; iGetNumberOfTuples(); i++) { vtkIdType edgeForIncludedGlobalProfile[2]; this->GetFromEdgeTable(edgeTableForIncludedGlobalProfiles,i,edgeForIncludedGlobalProfile); if (this->Distance(model->GetPoint(edgeForIncludedGlobalProfile[1]),center) <= radius) { this->InsertInEdgeTable(edgeTableForEffectiveIncludedGlobalProfiles,edgeForIncludedGlobalProfile[0],edgeForIncludedGlobalProfile[1]); } } if (edgeTableForEffectiveIncludedGlobalProfiles->GetNumberOfTuples() > 0) { vtkIdList* includedGlobalProfilesIds = vtkIdList::New(); for (i=0; iGetNumberOfTuples(); i++) { vtkIdType edgeForIncludedGlobalProfile[2]; this->GetFromEdgeTable(edgeTableForEffectiveIncludedGlobalProfiles,i,edgeForIncludedGlobalProfile); globalProfiles->InitTraversal(); globalProfilesEdgeTables->InitTraversal(); vtkIdType j; for (j=0; jGetNumberOfItems(); j++) { // vtkPolyData* globalProfile = globalProfiles->GetNextItem(); vtkIdTypeArray* globalProfileEdgeTable = (vtkIdTypeArray*)globalProfilesEdgeTables->GetNextItemAsObject(); vtkIdType k; for (k=0; kGetNumberOfTuples(); k++) { vtkIdType globalProfileEdge[2]; this->GetFromEdgeTable(globalProfileEdgeTable,k,globalProfileEdge); if (globalProfileEdge[0]!=globalProfileEdge[1]) { if ((edgeForIncludedGlobalProfile[0] == globalProfileEdge[0] && edgeForIncludedGlobalProfile[1] == globalProfileEdge[1]) || (edgeForIncludedGlobalProfile[0] == globalProfileEdge[1] && edgeForIncludedGlobalProfile[1] == globalProfileEdge[0])) { includedGlobalProfilesIds->InsertUniqueId(j); } } else if (globalProfileEdge[0] == globalProfileEdge[1]) { if (edgeForIncludedGlobalProfile[0] == globalProfileEdge[0] || edgeForIncludedGlobalProfile[1] == globalProfileEdge[0]) { includedGlobalProfilesIds->InsertUniqueId(j); } } } } } vtkPolyDataCollection* includedGlobalProfiles = vtkPolyDataCollection::New(); vtkCollection* includedGlobalProfilesEdgeTables = vtkCollection::New(); globalProfiles->InitTraversal(); globalProfilesEdgeTables->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* globalProfile = globalProfiles->GetNextItem(); vtkIdTypeArray* globalProfileEdgeTable = (vtkIdTypeArray*)globalProfilesEdgeTables->GetNextItemAsObject(); if (includedGlobalProfilesIds->IsId(i) != -1) { includedGlobalProfiles->AddItem(globalProfile); baseProfiles->AddItem(globalProfile); includedGlobalProfilesEdgeTables->AddItem(globalProfileEdgeTable); baseProfilesEdgeTables->AddItem(globalProfileEdgeTable); } } includedGlobalProfiles->InitTraversal(); includedGlobalProfilesEdgeTables->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { globalProfiles->RemoveItem(includedGlobalProfiles->GetNextItem()); globalProfilesEdgeTables->RemoveItem(includedGlobalProfilesEdgeTables->GetNextItemAsObject()); } this->UnmarkPoints(model,markedPointIds); edgeTableForNewProfiles->Delete(); cellPairsForNewProfiles->Delete(); pointIdsForNewProfiles->Delete(); edgeTableForIncludedGlobalProfiles->Delete(); markedPoints->Delete(); markedPointIds->Delete(); edgeTableForEffectiveIncludedGlobalProfiles->Delete(); includedGlobalProfilesIds->Delete(); includedGlobalProfiles->Delete(); includedGlobalProfilesEdgeTables->Delete(); return STEP_ITERATION_REDEFINE; } else { for (i=0; iGetNumberOfTuples(); i++) { vtkIdType currentEdge[2]; this->GetFromEdgeTable(edgeTableForIncludedGlobalProfiles,i,currentEdge); this->InsertEdgeForNewProfiles(model,currentEdge,edgeTableForNewProfiles,cellPairsForNewProfiles,pointIdsForNewProfiles); } } edgeTableForEffectiveIncludedGlobalProfiles->Delete(); } // build new profiles from lists (virtual points and connectivity) this->GenerateNewProfiles(model,center,radius,edgeTableForNewProfiles,cellPairsForNewProfiles,pointIdsForNewProfiles,newProfiles,newProfilesEdgeTables); this->TotalMarkedPoints += markedPointIds->GetNumberOfIds(); // classify step counting base and new profiles vtkIdType numberOfBaseProfiles = baseProfiles->GetNumberOfItems(); vtkIdType numberOfNewProfiles = newProfiles->GetNumberOfItems(); if (numberOfBaseProfiles == 1 && numberOfNewProfiles == 0) { segmentPoints->InsertNextPoint(center); edgeTableForNewProfiles->Delete(); cellPairsForNewProfiles->Delete(); pointIdsForNewProfiles->Delete(); edgeTableForIncludedGlobalProfiles->Delete(); markedPoints->Delete(); markedPointIds->Delete(); return STEP_ITERATION_STOP_CLOSED; } else if (numberOfBaseProfiles == 2 && numberOfNewProfiles == 0) { baseProfiles->InitTraversal(); vtkPolyData* profile; profile = baseProfiles->GetNextItem(); double point1[3]; this->ProfileBarycenter(profile->GetPoints(),point1); segmentPoints->InsertNextPoint(point1); profile = baseProfiles->GetNextItem(); double point2[3]; this->ProfileBarycenter(profile->GetPoints(),point2); segmentPoints->InsertNextPoint(point2); vtkPoints *pointsForRadius = vtkPoints::New(); this->PointsForRadius(markedPoints,baseProfiles,NULL,pointsForRadius); segmentRadii->InsertNextValue(ComputeStepRadius(pointsForRadius,point1,point2)); pointsForRadius->Delete(); edgeTableForNewProfiles->Delete(); cellPairsForNewProfiles->Delete(); pointIdsForNewProfiles->Delete(); edgeTableForIncludedGlobalProfiles->Delete(); markedPoints->Delete(); markedPointIds->Delete(); return STEP_ITERATION_STOP_END; } else if (numberOfBaseProfiles + numberOfNewProfiles > 2) { double lastCenter[3]; if (numberOfBaseProfiles==1) { lastCenter[0] = center[0]; lastCenter[1] = center[1]; lastCenter[2] = center[2]; } else { baseProfiles->InitTraversal(); vtkPolyData* profile; profile = baseProfiles->GetNextItem(); this->ProfileBarycenter(profile->GetPoints(),lastCenter); } segmentPoints->InsertNextPoint(lastCenter); double firstBranchRadius = 0.0; vtkIdType intersectingPointId = -1; if (segmentRadii->GetNumberOfTuples() > 0) { this->LookForIntersectingPoint(segmentPoints,center,radius,intersectingPointId); vtkIdType i; vtkPoints* backupSegmentPoints = vtkPoints::New(); for (i=0; iGetNumberOfPoints(); i++) { backupSegmentPoints->InsertNextPoint(segmentPoints->GetPoint(i)); } vtkDoubleArray* backupSegmentRadii = vtkDoubleArray::New(); for (i=0; iGetNumberOfTuples(); i++) { backupSegmentRadii->InsertNextValue(segmentRadii->GetValue(i)); } segmentPoints->Initialize(); for (i=0; i<=intersectingPointId; i++) { segmentPoints->InsertNextPoint(backupSegmentPoints->GetPoint(i)); } segmentRadii->Initialize(); for (i=0; iInsertNextValue(backupSegmentRadii->GetValue(i)); } firstBranchRadius = backupSegmentRadii->GetValue(intersectingPointId-1); backupSegmentPoints->Delete(); backupSegmentRadii->Delete(); } double bifurcationBarycenter[3]; bifurcationBarycenter[0] = center[0]; bifurcationBarycenter[1] = center[1]; bifurcationBarycenter[2] = center[2]; bifurcationPoints->InsertNextPoint(bifurcationBarycenter); bifurcationRadii->InsertNextValue(0.0); vtkPolyData* profile; baseProfiles->InitTraversal(); vtkIdType i; double bifurcationPoint[3]; for (i=0; iGetNumberOfItems(); i++) { profile=baseProfiles->GetNextItem(); if (i==0 && segmentRadii->GetNumberOfTuples()) { bifurcationPoints->InsertNextPoint(segmentPoints->GetPoint(intersectingPointId)); bifurcationRadii->InsertNextValue(firstBranchRadius); } else { this->ProfileBarycenter(profile->GetPoints(),bifurcationPoint); bifurcationPoints->InsertNextPoint(bifurcationPoint); bifurcationRadii->InsertNextValue(this->ComputeMeanRadius(profile->GetPoints(),bifurcationPoint)); } } newProfiles->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { profile=newProfiles->GetNextItem(); this->ProfileBarycenter(profile->GetPoints(),bifurcationPoint); bifurcationPoints->InsertNextPoint(bifurcationPoint); bifurcationRadii->InsertNextValue(this->ComputeMeanRadius(profile->GetPoints(),bifurcationPoint)); } vtkIdType j; bifurcationBarycenter[0] = bifurcationBarycenter[1] = bifurcationBarycenter[2] = 0.0; double weightSum = 0.0; for (i=1; iGetNumberOfPoints(); i++) { double bifurcationPoint[3]; bifurcationPoints->GetPoint(i,bifurcationPoint); double bifurcationPointRadius = bifurcationRadii->GetValue(i); weightSum+=bifurcationPointRadius; for (j=0; j<3; j++) { bifurcationBarycenter[j] += bifurcationPoint[j] * bifurcationPointRadius; } } for (j=0; j<3; j++) { bifurcationBarycenter[j] /= weightSum; } bifurcationPoints->InsertPoint(0,bifurcationBarycenter); edgeTableForNewProfiles->Delete(); cellPairsForNewProfiles->Delete(); pointIdsForNewProfiles->Delete(); edgeTableForIncludedGlobalProfiles->Delete(); markedPoints->Delete(); markedPointIds->Delete(); return STEP_ITERATION_STOP_BIFURCATION; } vtkPoints *pointsForRadius = vtkPoints::New(); this->PointsForRadius(markedPoints,baseProfiles,newProfiles,pointsForRadius); newProfiles->InitTraversal(); double profileBarycenter[3]; this->ProfileBarycenter(newProfiles->GetNextItem()->GetPoints(),profileBarycenter); double stepRadius = this->ComputeStepRadius(pointsForRadius,center,profileBarycenter); pointsForRadius->Delete(); if (!sameCenter) { segmentRadii->InsertNextValue(stepRadius); segmentPoints->InsertNextPoint(center); } else { segmentRadii->InsertValue(segmentRadii->GetNumberOfTuples()-1,stepRadius); segmentPoints->InsertPoint(segmentPoints->GetNumberOfPoints()-1,center); } oldCenter[0] = center[0]; oldCenter[1] = center[1]; oldCenter[2] = center[2]; oldRadius = radius; edgeTableForNewProfiles->Delete(); cellPairsForNewProfiles->Delete(); pointIdsForNewProfiles->Delete(); edgeTableForIncludedGlobalProfiles->Delete(); markedPoints->Delete(); markedPointIds->Delete(); return STEP_ITERATION_PROCEED; } void vtkvmtkPolyDataNetworkExtraction::MarkModelGlobalProfile(vtkPolyData* model, vtkIdTypeArray* newGlobalProfileEdgeTable) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); vtkIdType i; for (i=0; iGetNumberOfTuples(); i++) { // the first is currentId, the second is not yet visited vtkIdType edge[2]; this->GetFromEdgeTable(newGlobalProfileEdgeTable,i,edge); marksArray->InsertValue(edge[0],GLOBAL); } } void vtkvmtkPolyDataNetworkExtraction::SegmentTopology(vtkCollection* bifurcations, vtkCollection* bifurcationsRadii, double firstSegmentPoint[3], double lastSegmentPoint[3], double firstPoint[3], double &firstRadius, double lastPoint[3], double &lastRadius, vtkIdType segmentTopology[2]) { segmentTopology[0] = segmentTopology[1] = 0; bool firstPointFound = false; bool lastPointFound = false; if (!lastSegmentPoint) { segmentTopology[1] = -1; lastPointFound = true; } vtkIdType i; bifurcations->InitTraversal(); bifurcationsRadii->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPoints* bifurcation = (vtkPoints*)bifurcations->GetNextItemAsObject(); vtkDoubleArray* bifurcationRadii = (vtkDoubleArray*)bifurcationsRadii->GetNextItemAsObject(); vtkIdType j; for (j=0; jGetNumberOfPoints(); j++) { if (i == 0 || (i > 0 && j > 0)) { double point[3]; bifurcation->GetPoint(j,point); if (!firstPointFound) { if (point[0] == firstSegmentPoint[0] && point[1] == firstSegmentPoint[1] && point[2] == firstSegmentPoint[2]) { segmentTopology[0] = i; if (j > 0) { bifurcation->GetPoint(0,firstPoint); firstRadius = bifurcationRadii->GetValue(j); } firstPointFound = true; } } if (lastSegmentPoint && !lastPointFound) { if (point[0] == lastSegmentPoint[0] && point[1] == lastSegmentPoint[1] && point[2] == lastSegmentPoint[2]) { segmentTopology[1] = i; if (j>0) { bifurcation->GetPoint(0,lastPoint); lastRadius = bifurcationRadii->GetValue(j); } lastPointFound = true; } } } if (firstPointFound && lastPointFound) { break; } } if (firstPointFound && lastPointFound) { break; } } } void vtkvmtkPolyDataNetworkExtraction::BuildSegment(vtkPoints* segmentPoints, vtkDoubleArray* segmentRadii, vtkIdType segmentTopology[2], double firstPoint[3], double firstRadius, double lastPoint[3], double lastRadius, const double* centralPoint, vtkPolyData* segment) { vtkPoints* segmentPolyPoints = vtkPoints::New(); vtkDoubleArray* segmentPolyScalars = vtkDoubleArray::New(); segmentPolyScalars->SetName(RadiusArrayName); vtkIdTypeArray* segmentTopologyArray = vtkIdTypeArray::New(); segmentTopologyArray->SetName(TopologyArrayName); segmentTopologyArray->SetNumberOfComponents(2); segmentTopologyArray->InsertNextTupleValue(segmentTopology); // start if (segmentTopology[0] > 0) { segmentPolyPoints->InsertNextPoint(firstPoint); segmentPolyScalars->InsertNextValue(firstRadius); segmentPolyScalars->InsertNextValue(firstRadius); } else { segmentPolyScalars->InsertNextValue(0.0); } vtkIdType i; // mid if (segmentPoints) { for (i=0; iGetNumberOfPoints(); i++) { segmentPolyPoints->InsertNextPoint(segmentPoints->GetPoint(i)); } for (i=0; iGetNumberOfTuples(); i++) { segmentPolyScalars->InsertNextValue(segmentRadii->GetValue(i)); } } else { segmentPolyPoints->InsertNextPoint(centralPoint); } // end if (segmentTopology[1] > 0) { segmentPolyScalars->InsertNextValue(lastRadius); segmentPolyPoints->InsertNextPoint(lastPoint); segmentPolyScalars->InsertNextValue(lastRadius); } else { segmentPolyScalars->InsertNextValue(0.0); } vtkCellArray* segmentPolyLine = vtkCellArray::New(); segmentPolyLine->InsertNextCell(segmentPolyPoints->GetNumberOfPoints()); vtkIdType j; for (j=0; jGetNumberOfPoints(); j++) { segmentPolyLine->InsertCellPoint(j); } segment->SetPoints(segmentPolyPoints); segment->GetPointData()->AddArray(segmentPolyScalars); segment->GetCellData()->AddArray(segmentTopologyArray); segment->SetLines(segmentPolyLine); segment->Update(); segmentPolyPoints->Delete(); segmentPolyScalars->Delete(); segmentPolyLine->Delete(); segmentTopologyArray->Delete(); } void vtkvmtkPolyDataNetworkExtraction::InsertNewBifurcation(vtkCollection* bifurcations, vtkCollection* bifurcationsRadii, vtkPoints* bifurcationPoints, vtkDoubleArray* bifurcationRadii, vtkPolyDataCollection* additionalSegments) { vtkIdType i; bifurcations->InitTraversal(); bifurcationsRadii->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPoints* currentBifurcationPoints = (vtkPoints*)bifurcations->GetNextItemAsObject(); vtkDoubleArray* currentBifurcationRadii = (vtkDoubleArray*)bifurcationsRadii->GetNextItemAsObject(); vtkIdType j; for (j=0; jGetNumberOfPoints(); j++) { if (i == 0 || (i > 0 && j > 0)) { double currentBifurcationPoint[3]; currentBifurcationPoints->GetPoint(j,currentBifurcationPoint); vtkIdType k; for (k=0; kGetNumberOfPoints(); k++) { double bifurcationPoint[3]; bifurcationPoints->GetPoint(k,bifurcationPoint); if ((currentBifurcationPoint[0]==bifurcationPoint[0]) && (currentBifurcationPoint[1]==bifurcationPoint[1]) && (currentBifurcationPoint[2]==bifurcationPoint[2])) { vtkIdType additionalSegmentTopology[2]; additionalSegmentTopology[0] = i; additionalSegmentTopology[1] = bifurcations->GetNumberOfItems(); double currentBifurcationPoint0[3], bifurcationPoint0[3]; currentBifurcationPoints->GetPoint(0,currentBifurcationPoint0); bifurcationPoints->GetPoint(0,bifurcationPoint0); vtkPolyData* additionalSegment = vtkPolyData::New(); this->BuildSegment(NULL,NULL,additionalSegmentTopology,currentBifurcationPoint0,currentBifurcationRadii->GetValue(j),bifurcationPoint0,bifurcationRadii->GetValue(k),bifurcationPoint,additionalSegment); additionalSegments->AddItem(additionalSegment); additionalSegment->Delete(); } } } } } bifurcations->AddItem(bifurcationPoints); bifurcationsRadii->AddItem(bifurcationRadii); } void vtkvmtkPolyDataNetworkExtraction::SegmentIteration(vtkPolyData* model, vtkPolyData* initialProfile, vtkIdTypeArray* initialProfileEdgeTable, vtkPolyDataCollection* globalProfiles, vtkCollection* globalProfilesEdgeTables, vtkCollection* bifurcations, vtkCollection* bifurcationsRadii, vtkPolyDataCollection* segments, double advancementRatio) { vtkPolyDataCollection* baseProfiles = vtkPolyDataCollection::New(); baseProfiles->AddItem(initialProfile); vtkCollection* baseProfilesEdgeTables = vtkCollection::New(); baseProfilesEdgeTables->AddItem(initialProfileEdgeTable); vtkPolyDataCollection* newProfiles = vtkPolyDataCollection::New(); vtkCollection* newProfilesEdgeTables = vtkCollection::New(); vtkPoints* segmentPoints = vtkPoints::New(); vtkDoubleArray* segmentRadii = vtkDoubleArray::New(); vtkPoints* bifurcationPoints = vtkPoints::New(); vtkDoubleArray* bifurcationRadii = vtkDoubleArray::New(); double oldCenter[3]; double oldRadius = 0.0; vtkIdType stepIterationState = STEP_ITERATION_PROCEED; while (stepIterationState == STEP_ITERATION_PROCEED || stepIterationState == STEP_ITERATION_REDEFINE) { stepIterationState = STEP_ITERATION_PROCEED; stepIterationState = this->StepIteration(model,baseProfiles,baseProfilesEdgeTables,globalProfiles,globalProfilesEdgeTables,newProfiles,newProfilesEdgeTables,segmentPoints,segmentRadii,bifurcationPoints,bifurcationRadii,oldCenter,oldRadius,advancementRatio); // avoid zero steps if (stepIterationState == STEP_ITERATION_PROCEED && oldRadius == 0.0) { stepIterationState = STEP_ITERATION_STOP_CLOSED; } if (stepIterationState == STEP_ITERATION_PROCEED) { baseProfiles->RemoveAllItems(); baseProfilesEdgeTables->RemoveAllItems(); newProfiles->InitTraversal(); newProfilesEdgeTables->InitTraversal(); baseProfiles->AddItem(newProfiles->GetNextItem()); baseProfilesEdgeTables->AddItem(newProfilesEdgeTables->GetNextItemAsObject()); newProfiles->RemoveAllItems(); newProfilesEdgeTables->RemoveAllItems(); } } vtkPolyData* segment = vtkPolyData::New(); vtkPolyDataCollection* additionalSegments = vtkPolyDataCollection::New(); vtkIdType segmentTopology[2]; double firstPoint[3], lastPoint[3]; double firstRadius, lastRadius; if (stepIterationState == STEP_ITERATION_STOP_BIFURCATION) { vtkIdType i; newProfiles->InitTraversal(); newProfilesEdgeTables->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { globalProfiles->AddItem(newProfiles->GetNextItem()); vtkIdTypeArray* newGlobalProfileEdgeTable = (vtkIdTypeArray*)newProfilesEdgeTables->GetNextItemAsObject(); globalProfilesEdgeTables->AddItem(newGlobalProfileEdgeTable); this->MarkModelGlobalProfile(model,newGlobalProfileEdgeTable); } // adjacent check this->InsertNewBifurcation(bifurcations,bifurcationsRadii,bifurcationPoints,bifurcationRadii,additionalSegments); if (segmentPoints->GetNumberOfPoints()>=2) { double segmentPoint0[3], segmentPoint1[3]; segmentPoints->GetPoint(0,segmentPoint0); segmentPoints->GetPoint(segmentPoints->GetNumberOfPoints()-1,segmentPoint1); this->SegmentTopology(bifurcations,bifurcationsRadii,segmentPoint0,segmentPoint1,firstPoint,firstRadius,lastPoint,lastRadius,segmentTopology); this->BuildSegment(segmentPoints,segmentRadii,segmentTopology,firstPoint,firstRadius,lastPoint,lastRadius,NULL,segment); segments->AddItem(segment); } } else if (stepIterationState == STEP_ITERATION_STOP_END) { if (segmentPoints->GetNumberOfPoints() >= 2) { double segmentPoint0[3], segmentPoint1[3]; segmentPoints->GetPoint(0,segmentPoint0); segmentPoints->GetPoint(segmentPoints->GetNumberOfPoints()-1,segmentPoint1); this->SegmentTopology(bifurcations,bifurcationsRadii,segmentPoint0,segmentPoint1,firstPoint,firstRadius,lastPoint,lastRadius,segmentTopology); this->BuildSegment(segmentPoints,segmentRadii,segmentTopology,firstPoint,firstRadius,lastPoint,lastRadius,NULL,segment); segments->AddItem(segment); } } else if (stepIterationState == STEP_ITERATION_STOP_CLOSED) { if (segmentPoints->GetNumberOfPoints() >= 2) { double segmentPoint0[3]; segmentPoints->GetPoint(0,segmentPoint0); this->SegmentTopology(bifurcations,bifurcationsRadii,segmentPoint0,NULL,firstPoint,firstRadius,lastPoint,lastRadius,segmentTopology); this->BuildSegment(segmentPoints,segmentRadii,segmentTopology,firstPoint,firstRadius,lastPoint,lastRadius,NULL,segment); segments->AddItem(segment); } } segment->Delete(); additionalSegments->InitTraversal(); vtkIdType k; for (k=0; kGetNumberOfItems(); k++) { segments->AddItem(additionalSegments->GetNextItem()); } additionalSegments->Delete(); baseProfiles->Delete(); baseProfilesEdgeTables->Delete(); newProfiles->Delete(); newProfilesEdgeTables->Delete(); segmentPoints->Delete(); segmentRadii->Delete(); bifurcationPoints->Delete(); bifurcationRadii->Delete(); } void vtkvmtkPolyDataNetworkExtraction::JoinSegments (vtkPolyData* segment0, vtkPolyData* segment1, bool first0, bool first1, vtkPolyData* segment) { vtkPoints* segmentPoints = vtkPoints::New(); vtkDoubleArray* radiusArray = vtkDoubleArray::New(); radiusArray->SetName(RadiusArrayName); vtkIdTypeArray* topologyArray = vtkIdTypeArray::New(); topologyArray->SetNumberOfComponents(2); topologyArray->SetName(TopologyArrayName); vtkDoubleArray* segment0RadiusArray = vtkDoubleArray::SafeDownCast(segment0->GetPointData()->GetArray(RadiusArrayName)); vtkDoubleArray* segment1RadiusArray = vtkDoubleArray::SafeDownCast(segment1->GetPointData()->GetArray(RadiusArrayName)); vtkIdTypeArray* segment0TopologyArray = vtkIdTypeArray::SafeDownCast(segment0->GetCellData()->GetArray(TopologyArrayName)); vtkIdTypeArray* segment1TopologyArray = vtkIdTypeArray::SafeDownCast(segment1->GetCellData()->GetArray(TopologyArrayName)); vtkIdType segmentTopology0[2]; vtkIdType segmentTopology1[2]; segment0TopologyArray->GetTupleValue(0,segmentTopology0); segment1TopologyArray->GetTupleValue(0,segmentTopology1); vtkIdType segmentTopology[2]; vtkIdType i; if (first0) { segmentTopology[0] = segmentTopology0[1]; for (i=segment0->GetNumberOfPoints()-1; i>=1; i--) { segmentPoints->InsertNextPoint(segment0->GetPoint(i)); radiusArray->InsertNextValue(segment0RadiusArray->GetValue(i)); } } else { segmentTopology[0] = segmentTopology0[0]; for (i=0; iGetNumberOfPoints()-1; i++) { segmentPoints->InsertNextPoint(segment0->GetPoint(i)); radiusArray->InsertNextValue(segment0RadiusArray->GetValue(i)); } } if (first1) { segmentTopology[1] = segmentTopology1[1]; for (i=1; iGetNumberOfPoints(); i++) { segmentPoints->InsertNextPoint(segment1->GetPoint(i)); radiusArray->InsertNextValue(segment1RadiusArray->GetValue(i)); } } else { segmentTopology[1] = segmentTopology1[1]; for (i=segment1->GetNumberOfPoints()-2; i>=0; i--) { segmentPoints->InsertNextPoint(segment1->GetPoint(i)); radiusArray->InsertNextValue(segment1RadiusArray->GetValue(i)); } } topologyArray->InsertNextTupleValue(segmentTopology); vtkCellArray* segmentCell = vtkCellArray::New(); segmentCell->InsertNextCell(segmentPoints->GetNumberOfPoints()); for (i=0; iGetNumberOfPoints(); i++) { segmentCell->InsertCellPoint(i); } segment->SetPoints(segmentPoints); segment->SetLines(segmentCell); segment->GetPointData()->AddArray(radiusArray); segment->GetCellData()->AddArray(topologyArray); segment->Update(); radiusArray->Delete(); topologyArray->Delete(); segmentPoints->Delete(); segmentCell->Delete(); } void vtkvmtkPolyDataNetworkExtraction::RemoveDegenerateBifurcations(vtkPolyDataCollection* segments,vtkCollection* bifurcations) { vtkIdList* realBifurcations = vtkIdList::New(); realBifurcations->InsertNextId(0); vtkIdList* degenerateBifurcations = vtkIdList::New(); vtkIdTypeArray* bifurcationFrequency = vtkIdTypeArray::New(); bifurcations->InitTraversal(); vtkIdType i; for (i=0; iGetNumberOfItems(); i++) { bifurcationFrequency->InsertNextValue(0); } segments->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* segment = segments->GetNextItem(); // vtkDoubleArray* radiusArray = vtkDoubleArray::SafeDownCast(segment->GetPointData()->GetArray(RadiusArrayName)); vtkIdTypeArray* topologyArray = vtkIdTypeArray::SafeDownCast(segment->GetCellData()->GetArray(TopologyArrayName)); vtkIdType topology[2]; topologyArray->GetTupleValue(0,topology); vtkIdType bifurcation0 = topology[0]; if (bifurcation0 > 0) { vtkIdType frequency0 = bifurcationFrequency->GetValue(bifurcation0); bifurcationFrequency->InsertValue(bifurcation0,frequency0+1); } vtkIdType bifurcation1 = topology[1]; if (bifurcation1 > 0) { vtkIdType frequency1 = bifurcationFrequency->GetValue(bifurcation1); bifurcationFrequency->InsertValue(bifurcation1,frequency1+1); } } for (i=0; iGetNumberOfTuples(); i++) { if (i > 0) { if (bifurcationFrequency->GetValue(i) < 3) { degenerateBifurcations->InsertNextId(i); } else { realBifurcations->InsertNextId(i); } } } // vtkIdType n = degenerateBifurcations->GetNumberOfIds(); while (degenerateBifurcations->GetNumberOfIds() > 0) { segments->InitTraversal(); vtkPolyData* segment0 = NULL,* segment1 = NULL,* currentSegment; vtkIdType degenerateId = -1; bool first0, first1; first0 = first1 = false; for (i=0; iGetNumberOfItems(); i++) { currentSegment = segments->GetNextItem(); // vtkDoubleArray* radiusArray = vtkDoubleArray::SafeDownCast(currentSegment->GetPointData()->GetArray(RadiusArrayName)); vtkIdTypeArray* topologyArray = vtkIdTypeArray::SafeDownCast(currentSegment->GetCellData()->GetArray(TopologyArrayName)); vtkIdType topology[2]; topologyArray->GetTupleValue(0,topology); if (!segment0) { degenerateId = topology[0]; if (degenerateBifurcations->IsId(degenerateId) != -1) { segment0 = currentSegment; first0 = true; degenerateBifurcations->DeleteId(degenerateId); } if (!segment0) { degenerateId = topology[1]; if (degenerateBifurcations->IsId(degenerateId) != -1) { segment0 = currentSegment; first0 = false; degenerateBifurcations->DeleteId(degenerateId); } } } else if (!segment1) { if (topology[0] == degenerateId) { segment1 = currentSegment; first1 = true; } if (topology[1] == degenerateId) { segment1 = currentSegment; first1 = false; } } } if (segment0 && segment1) { segment0->Register((vtkObjectBase*)NULL); segment1->Register((vtkObjectBase*)NULL); segments->RemoveItem(segment0); segments->RemoveItem(segment1); vtkPolyData* joinedSegment = vtkPolyData::New(); this->JoinSegments(segment0,segment1,first0,first1,joinedSegment); segments->AddItem(joinedSegment); joinedSegment->Delete(); segment0->UnRegister((vtkObjectBase*)NULL); segment1->UnRegister((vtkObjectBase*)NULL); } } // rename bifurcations segments->InitTraversal(); vtkIdType scalar0, scalar1, position0, position1; for (i=0; iGetNumberOfItems(); i++) { vtkPolyData* currentSegment = segments->GetNextItem(); // vtkDoubleArray* radiusArray = vtkDoubleArray::SafeDownCast(currentSegment->GetPointData()->GetArray(RadiusArrayName)); vtkIdTypeArray* topologyArray = vtkIdTypeArray::SafeDownCast(currentSegment->GetCellData()->GetArray(TopologyArrayName)); vtkIdType topology[2]; topologyArray->GetTupleValue(0,topology); scalar0 = topology[0]; scalar1 = topology[1]; if (scalar0 > 0) { position0 = realBifurcations->InsertUniqueId(scalar0); topology[0] = position0; } if (scalar1>0) { position1=realBifurcations->InsertUniqueId(scalar1); topology[1] = position1; } topologyArray->InsertTupleValue(0,topology); } realBifurcations->Delete(); degenerateBifurcations->Delete(); bifurcationFrequency->Delete(); } void vtkvmtkPolyDataNetworkExtraction::GlobalIteration(vtkPolyData* model, vtkPolyDataCollection* globalProfiles, vtkPolyData* network, double advancementRatio) { vtkCollection* globalProfilesEdgeTables = vtkCollection::New(); this->UpdateEdgeTableCollectionReal(model,globalProfiles,globalProfilesEdgeTables); vtkCollection* bifurcations = vtkCollection::New(); vtkCollection* bifurcationsRadii = vtkCollection::New(); vtkPolyDataCollection* segments = vtkPolyDataCollection::New(); vtkPoints* globalBoundaryBarycenters = vtkPoints::New(); vtkDoubleArray* globalBoundaryRadii = vtkDoubleArray::New(); vtkPolyData* profile; vtkIdType i; globalProfiles->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { profile=globalProfiles->GetNextItem(); double barycenter[3]; this->ProfileBarycenter(profile->GetPoints(),barycenter); globalBoundaryBarycenters->InsertNextPoint(barycenter); globalBoundaryRadii->InsertNextValue(ComputeMeanRadius(profile->GetPoints(),barycenter)); } bifurcations->AddItem(globalBoundaryBarycenters); bifurcationsRadii->AddItem(globalBoundaryRadii); while (globalProfiles->GetNumberOfItems()) { globalProfiles->InitTraversal(); vtkPolyData* initialProfile = globalProfiles->GetNextItem(); initialProfile->Register((vtkObjectBase*)NULL); globalProfiles->RemoveItem(initialProfile); globalProfilesEdgeTables->InitTraversal(); vtkIdTypeArray* initialProfileEdgeTable = (vtkIdTypeArray*)globalProfilesEdgeTables->GetNextItemAsObject(); initialProfileEdgeTable->Register((vtkObjectBase*)NULL); globalProfilesEdgeTables->RemoveItem(initialProfileEdgeTable); this->SegmentIteration(model,initialProfile,initialProfileEdgeTable,globalProfiles,globalProfilesEdgeTables,bifurcations,bifurcationsRadii,segments,advancementRatio); double progress = (double)this->TotalMarkedPoints/(double)model->GetNumberOfPoints(); this->InvokeEvent(vtkCommand::ProgressEvent,&progress); initialProfile->UnRegister((vtkObjectBase*)NULL); initialProfileEdgeTable->UnRegister((vtkObjectBase*)NULL); } this->RemoveDegenerateBifurcations(segments,bifurcations); vtkIdTypeArray* topologyArray = vtkIdTypeArray::New(); topologyArray->SetName(TopologyArrayName); topologyArray->SetNumberOfComponents(2); segments->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { vtkIdType topology[2]; vtkIdTypeArray* segmentTopologyArray = vtkIdTypeArray::SafeDownCast(segments->GetNextItem()->GetCellData()->GetArray(TopologyArrayName)); segmentTopologyArray->GetTupleValue(0,topology); topologyArray->InsertNextTupleValue(topology); } vtkAppendPolyData* segmentsAppended = vtkAppendPolyData::New(); segments->InitTraversal(); for (i=0; iGetNumberOfItems(); i++) { segmentsAppended->AddInput(segments->GetNextItem()); } segmentsAppended->Update(); network->DeepCopy(segmentsAppended->GetOutput()); network->GetCellData()->AddArray(topologyArray); network->Update(); globalProfilesEdgeTables->Delete(); bifurcations->Delete(); bifurcationsRadii->Delete(); segments->Delete(); globalBoundaryBarycenters->Delete(); globalBoundaryRadii->Delete(); segmentsAppended->Delete(); topologyArray->Delete(); } void vtkvmtkPolyDataNetworkExtraction::MarkModelRealBoundary(vtkPolyData* model, vtkPolyData* modelBoundary) { vtkIdTypeArray* marksArray = vtkIdTypeArray::SafeDownCast(model->GetPointData()->GetArray(MarksArrayName)); vtkIdType i; for (i=0; iGetNumberOfPoints(); i++) { marksArray->InsertValue(i,NON_VISITED); } for (i=0; iGetNumberOfPoints(); i++) { marksArray->InsertValue(model->FindPoint(modelBoundary->GetPoint(i)),GLOBAL); } } void vtkvmtkPolyDataNetworkExtraction::Graph(vtkPolyData* network, vtkPolyData* graphLayout) { vtkPoints* graphPoints = vtkPoints::New(); vtkCellArray* graphLines = vtkCellArray::New(); vtkDoubleArray* graphRadiusArray = vtkDoubleArray::New(); graphRadiusArray->SetName(this->RadiusArrayName); graphLayout->SetPoints(graphPoints); graphLayout->SetLines(graphLines); graphLayout->GetCellData()->AddArray(graphRadiusArray); vtkIdType numberOfPoints = network->GetNumberOfPoints(); vtkIdType numberOfCells = network->GetNumberOfCells(); vtkIdTypeArray* isPointInserted = vtkIdTypeArray::New(); isPointInserted->SetNumberOfTuples(numberOfPoints); isPointInserted->FillComponent(0,-1); vtkDoubleArray* radiusArray = vtkDoubleArray::SafeDownCast(network->GetPointData()->GetArray(this->RadiusArrayName)); vtkIdTypeArray* topologyArray = vtkIdTypeArray::SafeDownCast(network->GetCellData()->GetArray(this->TopologyArrayName)); for (int i=0; iGetCell(i); vtkIdType topology[2]; topologyArray->GetTupleValue(i,topology); vtkIdType numberOfCellPoints = cell->GetNumberOfPoints(); double meanRadius = 0.0; for (int j=0; jGetValue(cell->GetPointId(j)); meanRadius += radius; } meanRadius /= numberOfCellPoints; vtkIdType pointId0 = cell->GetPointId(0); vtkIdType pointId1 = cell->GetPointId(numberOfCellPoints-1); vtkIdType newPointId0 = -1; vtkIdType newPointId1 = -1; if (isPointInserted->GetValue(pointId0) == -1) { newPointId0 = graphPoints->InsertNextPoint(network->GetPoint(pointId0)); isPointInserted->SetValue(pointId0,newPointId0); } else { newPointId0 = isPointInserted->GetValue(pointId0); } if (isPointInserted->GetValue(pointId1) == -1) { newPointId1 = graphPoints->InsertNextPoint(network->GetPoint(pointId1)); isPointInserted->SetValue(pointId1,newPointId1); } else { newPointId1 = isPointInserted->GetValue(pointId1); } graphLines->InsertNextCell(2); graphLines->InsertCellPoint(newPointId0); graphLines->InsertCellPoint(newPointId1); graphRadiusArray->InsertNextValue(meanRadius); } graphPoints->Delete(); graphLines->Delete(); graphRadiusArray->Delete(); isPointInserted->Delete(); } int vtkvmtkPolyDataNetworkExtraction::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())); this->TotalMarkedPoints = 0; vtkPolyData* model = vtkPolyData::New(); model->DeepCopy(input); vtkIdTypeArray* marksArray = vtkIdTypeArray::New(); marksArray->SetName(this->MarksArrayName); marksArray->SetNumberOfTuples(model->GetNumberOfPoints()); model->GetPointData()->AddArray(marksArray); vtkPolyData* modelBoundary = vtkPolyData::New(); this->BoundaryExtractor(model,modelBoundary); vtkPolyData* network = vtkPolyData::New(); if (modelBoundary->GetNumberOfPoints() > 0) { this->MarkModelRealBoundary(model,modelBoundary); model->BuildCells(); model->BuildLinks(); vtkPolyDataCollection* globalProfiles = vtkPolyDataCollection::New(); this->BoundarySeparator(modelBoundary,globalProfiles); this->GlobalIteration(model,globalProfiles,network,this->AdvancementRatio); globalProfiles->Delete(); } marksArray->Delete(); modelBoundary->Delete(); double progress = 1.0; this->InvokeEvent(vtkCommand::ProgressEvent,&progress); output->DeepCopy(network); if (this->GraphLayout) { this->GraphLayout->Delete(); this->GraphLayout = NULL; } this->GraphLayout = vtkPolyData::New(); this->Graph(network,this->GraphLayout); network->Delete(); return 1; } void vtkvmtkPolyDataNetworkExtraction::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkRBFInterpolation.cxx0000664000175000017500000001073511757446472021052 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkRBFInterpolation.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:28 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkRBFInterpolation.h" #include "vtkvmtkConstants.h" #include "vtkPointData.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkRBFInterpolation, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkRBFInterpolation); vtkvmtkRBFInterpolation::vtkvmtkRBFInterpolation() { this->Source = NULL; this->RBFType = THIN_PLATE_SPLINE; this->Coefficients = NULL; this->RBFInterpolationValue = 1.0; } vtkvmtkRBFInterpolation::~vtkvmtkRBFInterpolation() { if (this->Source) { this->Source->Delete(); this->Source = NULL; } if (this->Coefficients) { this->Coefficients->Delete(); this->Coefficients = NULL; } } double vtkvmtkRBFInterpolation::EvaluateRBF(double c[3], double x[3]) { if (this->RBFType == THIN_PLATE_SPLINE) { double r2 = vtkMath::Distance2BetweenPoints(c,x); if (!r2) { return 0.0; } return r2 * log(sqrt(r2)); } else if (this->RBFType == BIHARMONIC) { return sqrt(vtkMath::Distance2BetweenPoints(c,x)); } else if (this->RBFType == TRIHARMONIC) { return pow(vtkMath::Distance2BetweenPoints(c,x),1.5); } else { vtkErrorMacro(<<"Error: Unsupported RBFType!"); return 0.0; } } void vtkvmtkRBFInterpolation::ComputeCoefficients() { if (this->Coefficients) { this->Coefficients->Delete(); this->Coefficients = NULL; } if (!this->Source) { vtkErrorMacro("No Source specified!"); return; } int numberOfPoints = this->Source->GetNumberOfPoints(); if (!numberOfPoints) { vtkWarningMacro("Empty Source specified!"); return; } this->Coefficients = vtkDoubleArray::New(); this->Coefficients->SetNumberOfValues(numberOfPoints); double **A, *x; x = new double[numberOfPoints]; A = new double* [numberOfPoints]; int i; for (i=0; iRBFInterpolationValue; } double center[3]; int j; for (i=0; iSource->GetPoint(i,center); for (j=0; jEvaluateRBF(center,this->Source->GetPoint(j)); } } int ret = vtkMath::SolveLinearSystem(A,x,numberOfPoints); if (!ret) { vtkErrorMacro(<<"Cannot compute coefficients: error during linear system solve"); } for (i=0; iCoefficients->SetValue(i,x[i]); } delete[] x; for (i=0; iSource) { vtkErrorMacro("No Source specified!"); return 0.0; } int numberOfPoints = this->Source->GetNumberOfPoints(); if (!numberOfPoints) { vtkWarningMacro("Empty Source specified!"); return 0.0; } if (!this->Coefficients) { this->ComputeCoefficients(); } double rbfValue = 0.0; double center[3]; int i; for (i=0; iSource->GetPoint(i,center); rbfValue += this->Coefficients->GetValue(i) * this->EvaluateRBF(center,x); } rbfValue -= this->RBFInterpolationValue; return rbfValue; } void vtkvmtkRBFInterpolation::EvaluateGradient(double x[3], double n[3]) { vtkWarningMacro("RBF gradient computation not implemented."); } unsigned long vtkvmtkRBFInterpolation::GetMTime() { unsigned long mTime=this->Superclass::GetMTime(); unsigned long sourceMTime; if (this->Source != NULL) { sourceMTime = this->Source->GetMTime(); mTime = ( sourceMTime > mTime ? sourceMTime : mTime ); } return mTime; } void vtkvmtkRBFInterpolation::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkAnnularCapPolyData.h0000664000175000017500000000404011757446472020770 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkAnnularCapPolyData.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkAnnularCapPolyData - Add annular caps between the boundaries of a walled surface. // .SECTION Description // This class closes the boundaries between the surfaces of a walled surface with caps. The // surfaces are required to be dense for the algorithm to produce legal caps. #ifndef __vtkvmtkAnnularCapPolyData_h #define __vtkvmtkAnnularCapPolyData_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkAnnularCapPolyData : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkAnnularCapPolyData,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkAnnularCapPolyData *New(); vtkSetStringMacro(CellEntityIdsArrayName); vtkGetStringMacro(CellEntityIdsArrayName); vtkSetMacro(CellEntityIdOffset,int); vtkGetMacro(CellEntityIdOffset,int); protected: vtkvmtkAnnularCapPolyData(); ~vtkvmtkAnnularCapPolyData(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* CellEntityIdsArrayName; int CellEntityIdOffset; private: vtkvmtkAnnularCapPolyData(const vtkvmtkAnnularCapPolyData&); // Not implemented. void operator=(const vtkvmtkAnnularCapPolyData&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStaticTemporalStreamTracer.cxx0000664000175000017500000006115311757446472023141 0ustar lucaluca/*========================================================================= Program: Visualization Toolkit Module: vtkvmtkStaticTemporalStreamTracer.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 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. =========================================================================*/ #include "vtkvmtkStaticTemporalStreamTracer.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkCompositeDataIterator.h" #include "vtkCompositeDataSet.h" #include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkSmartPointer.h" #include "vtkvmtkStaticTemporalInterpolatedVelocityField.h" #include "vtkTable.h" vtkStandardNewMacro(vtkvmtkStaticTemporalStreamTracer); vtkCxxSetObjectMacro(vtkvmtkStaticTemporalStreamTracer, TimeStepsTable, vtkTable); vtkvmtkStaticTemporalStreamTracer::vtkvmtkStaticTemporalStreamTracer() { this->SeedTime = 0.0; this->SeedTimesArrayName = NULL; this->Periodic = 0; this->VelocityScale = 1.0; this->TimeStepsTable = NULL; this->UseVectorComponents = 0; this->VectorPrefix = NULL; this->Component0Prefix = NULL; this->Component1Prefix = NULL; this->Component2Prefix = NULL; } vtkvmtkStaticTemporalStreamTracer::~vtkvmtkStaticTemporalStreamTracer() { if (this->SeedTimesArrayName) { delete[] this->SeedTimesArrayName; this->SeedTimesArrayName = NULL; } if (this->VectorPrefix) { delete[] this->VectorPrefix; this->VectorPrefix = NULL; } if (this->Component0Prefix) { delete[] this->Component0Prefix; this->Component0Prefix = NULL; } if (this->Component1Prefix) { delete[] this->Component1Prefix; this->Component1Prefix = NULL; } if (this->Component2Prefix) { delete[] this->Component2Prefix; this->Component2Prefix = NULL; } this->SetTimeStepsTable(NULL); } void vtkvmtkStaticTemporalStreamTracer::InitializeDefaultInterpolatorPrototype() { vtkvmtkStaticTemporalInterpolatedVelocityField* staticTemporalInterpolator = vtkvmtkStaticTemporalInterpolatedVelocityField::New(); staticTemporalInterpolator->SetUseVectorComponents(this->UseVectorComponents); staticTemporalInterpolator->SetVectorPrefix(this->VectorPrefix); staticTemporalInterpolator->SetComponent0Prefix(this->Component0Prefix); staticTemporalInterpolator->SetComponent1Prefix(this->Component1Prefix); staticTemporalInterpolator->SetComponent2Prefix(this->Component2Prefix); staticTemporalInterpolator->SetTimeStepsTable(this->TimeStepsTable); staticTemporalInterpolator->SetPeriodic(this->Periodic); staticTemporalInterpolator->SetVelocityScale(this->VelocityScale); this->SetInterpolatorPrototype(staticTemporalInterpolator); staticTemporalInterpolator->Delete(); } void vtkvmtkStaticTemporalStreamTracer::InitializeSeeds(vtkDataArray*& seeds, vtkIdList*& seedIds, vtkDoubleArray*& startTimes, vtkIntArray*& integrationDirections, vtkDataSet *source) { this->Superclass::InitializeSeeds(seeds,seedIds,integrationDirections,source); startTimes = vtkDoubleArray::New(); if (!source) { return; } vtkDataArray* sourceSeedTimes = source->GetPointData()->GetArray(this->SeedTimesArrayName); if (sourceSeedTimes) { startTimes->DeepCopy(sourceSeedTimes); } else { startTimes->SetNumberOfTuples(source->GetNumberOfPoints()); startTimes->FillComponent(0,this->SeedTime); } } int vtkvmtkStaticTemporalStreamTracer::CheckInputs(vtkAbstractInterpolatedVelocityField*& func, int* maxCellSize) { if (!this->InputData) { return VTK_ERROR; } vtkCompositeDataIterator* iter = this->InputData->NewIterator(); vtkSmartPointer iterP(iter); iter->Delete(); iterP->GoToFirstItem(); if (iterP->IsDoneWithTraversal()) { return VTK_ERROR; } // Set the function set to be integrated if ( !this->InterpolatorPrototype ) { func = vtkvmtkStaticTemporalInterpolatedVelocityField::New(); // turn on the following segment, in place of the above line, if an // interpolator equipped with a cell locator is dedired as the default // // func = vtkCellLocatorInterpolatedVelocityField::New(); // vtkSmartPointer< vtkModifiedBSPTree > locator = // vtkSmartPointer< vtkModifiedBSPTree >::New(); // vtkCellLocatorInterpolatedVelocityField::SafeDownCast( func ) // ->SetCellLocatorPrototype( locator.GetPointer() ); } else { func = this->InterpolatorPrototype->NewInstance(); func->CopyParameters(this->InterpolatorPrototype); } //vtkDataArray *vectors = this->GetInputArrayToProcess( // 0,iterP->GetCurrentDataObject()); //if (!vectors) // { // return VTK_ERROR; // } //const char *vecName = vectors->GetName(); //func->SelectVectors(vecName); // Add all the inputs ( except source, of course ) which // have the appropriate vectors and compute the maximum // cell size. int numInputs = 0; iterP->GoToFirstItem(); while (!iterP->IsDoneWithTraversal()) { vtkDataSet* inp = vtkDataSet::SafeDownCast(iterP->GetCurrentDataObject()); if (inp) { //if (!inp->GetPointData()->GetVectors(vecName)) // { // vtkDebugMacro("One of the input blocks does not contain a " // "velocity vector."); // iterP->GoToNextItem(); // continue; // } int cellSize = inp->GetMaxCellSize(); if ( cellSize > *maxCellSize ) { *maxCellSize = cellSize; } func->AddDataSet(inp); numInputs++; } iterP->GoToNextItem(); } if ( numInputs == 0 ) { vtkDebugMacro("No appropriate inputs have been found. Can not execute."); return VTK_ERROR; } return VTK_OK; } int vtkvmtkStaticTemporalStreamTracer::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); if (!this->SetupOutput(inInfo, outInfo)) { return 0; } vtkInformation *sourceInfo = inputVector[1]->GetInformationObject(0); vtkDataSet *source = 0; if (sourceInfo) { source = vtkDataSet::SafeDownCast( sourceInfo->Get(vtkDataObject::DATA_OBJECT())); } vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); if (this->InterpolatorPrototype == 0) { this->InitializeDefaultInterpolatorPrototype(); } vtkDataArray* seeds = 0; vtkIdList* seedIds = 0; vtkIntArray* integrationDirections = 0; vtkDoubleArray* startTimes = 0; this->InitializeSeeds(seeds, seedIds, startTimes, integrationDirections, source); if (seeds) { double lastPoint[3]; vtkAbstractInterpolatedVelocityField * func; int maxCellSize = 0; if (this->CheckInputs(func, &maxCellSize) != VTK_OK) { vtkDebugMacro("No appropriate inputs have been found. Can not execute."); func->Delete(); seeds->Delete(); startTimes->Delete(); integrationDirections->Delete(); seedIds->Delete(); this->InputData->UnRegister(this); return 1; } vtkCompositeDataIterator* iter = this->InputData->NewIterator(); vtkSmartPointer iterP(iter); iter->Delete(); iterP->GoToFirstItem(); vtkDataSet* input0 = 0; if (!iterP->IsDoneWithTraversal()) { input0 = vtkDataSet::SafeDownCast(iterP->GetCurrentDataObject()); } double propagation = 0; vtkIdType numSteps = 0; this->Integrate(input0, output, seeds, seedIds, startTimes, integrationDirections, lastPoint, func, maxCellSize, propagation, numSteps); func->Delete(); seeds->Delete(); } startTimes->Delete(); integrationDirections->Delete(); seedIds->Delete(); this->InputData->UnRegister(this); return 1; } void vtkvmtkStaticTemporalStreamTracer::Integrate(vtkDataSet *input0, vtkPolyData* output, vtkDataArray* seedSource, vtkIdList* seedIds, vtkDoubleArray* startTimes, vtkIntArray* integrationDirections, double lastPoint[3], vtkAbstractInterpolatedVelocityField* func, int maxCellSize, double& inPropagation, vtkIdType& inNumSteps) { int i; vtkIdType numLines = seedIds->GetNumberOfIds(); double propagation = inPropagation; vtkIdType numSteps = inNumSteps; // Useful pointers vtkDataSetAttributes* outputPD = output->GetPointData(); vtkDataSetAttributes* outputCD = output->GetCellData(); vtkPointData* inputPD; vtkDataSet* input; //TODO: this one will potentially change at every evaluation. int direction=1; double* weights = 0; if ( maxCellSize > 0 ) { weights = new double[maxCellSize]; } if (this->GetIntegrator() == 0) { vtkErrorMacro("No integrator is specified."); return; } // Used in GetCell() vtkGenericCell* cell = vtkGenericCell::New(); // Create a new integrator, the type is the same as Integrator vtkInitialValueProblemSolver* integrator = this->GetIntegrator()->NewInstance(); integrator->SetFunctionSet(func); // Since we do not know what the total number of points // will be, we do not allocate any. This is important for // cases where a lot of streamers are used at once. If we // were to allocate any points here, potentially, we can // waste a lot of memory if a lot of streamers are used. // Always insert the first point vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputLines = vtkCellArray::New(); // We will keep track of integration time in this array vtkDoubleArray* time = vtkDoubleArray::New(); time->SetName("IntegrationTime"); // This array explains why the integration stopped vtkIntArray* retVals = vtkIntArray::New(); retVals->SetName("ReasonForTermination"); vtkDoubleArray* cellVectors = 0; vtkDoubleArray* velocityArray = 0; vtkDoubleArray* speedArray = 0; vtkDoubleArray* vorticity = 0; vtkDoubleArray* rotation = 0; vtkDoubleArray* angularVel = 0; velocityArray = vtkDoubleArray::New(); velocityArray->SetName("Velocity"); velocityArray->SetNumberOfComponents(3); speedArray = vtkDoubleArray::New(); speedArray->SetName("Speed"); if (this->ComputeVorticity) { cellVectors = vtkDoubleArray::New(); cellVectors->SetNumberOfComponents(3); cellVectors->Allocate(3*VTK_CELL_SIZE); vorticity = vtkDoubleArray::New(); vorticity->SetName("Vorticity"); vorticity->SetNumberOfComponents(3); rotation = vtkDoubleArray::New(); rotation->SetName("Rotation"); angularVel = vtkDoubleArray::New(); angularVel->SetName("AngularVelocity"); } // We will interpolate all point attributes of the input on each point of // the output (unless they are turned off). Note that we are using only // the first input, if there are more than one, the attributes have to match. // // Note: We have to use a specific value (safe to employ the maximum number // of steps) as the size of the initial memory allocation here. The // use of the default argument might incur a crash problem (due to // "insufficient memory") in the parallel mode. This is the case when // a streamline intensely shuttles between two processes in an exactly // interleaving fashion --- only one point is produced on each process // (and actually two points, after point duplication, are saved to a // vtkPolyData in vtkDistributedStreamTracer::NoBlockProcessTask) and // as a consequence a large number of such small vtkPolyData objects // are needed to represent a streamline, consuming up the memory before // the intermediate memory is timely released. // TODO: this one should be avoided - or at least we should interpolate all vectors that are not in the list of temporal vector fields //outputPD->InterpolateAllocate( input0->GetPointData(), // this->MaximumNumberOfSteps ); vtkIdType numPtsTotal=0; double velocity[3]; int shouldAbort = 0; for(int currentLine = 0; currentLine < numLines; currentLine++) { double progress = static_cast(currentLine)/numLines; this->UpdateProgress(progress); switch (integrationDirections->GetValue(currentLine)) { case FORWARD: direction = 1; break; case BACKWARD: direction = -1; break; } // temporary variables used in the integration double point1[3], point2[3], pcoords[3], vort[3], omega; vtkIdType index, numPts=0; // Clear the last cell to avoid starting a search from // the last point in the streamline func->ClearLastCellId(); double startTime = startTimes->GetValue(currentLine); // Initial point seedSource->GetTuple(seedIds->GetId(currentLine), point1); memcpy(point2, point1, 3*sizeof(double)); double point1t[4]; memcpy(point1t, point1, 3*sizeof(double)); point1t[3] = startTime; if (!func->FunctionValues(point1t, velocity)) { continue; } if ( propagation >= this->MaximumPropagation || numSteps > this->MaximumNumberOfSteps) { continue; } numPts++; numPtsTotal++; vtkIdType nextPoint = outputPoints->InsertNextPoint(point1); time->InsertNextValue(startTime); // We will always pass an arc-length step size to the integrator. // If the user specifies a step size in cell length unit, we will // have to convert it to arc length. IntervalInformation stepSize; // either positive or negative stepSize.Unit = LENGTH_UNIT; stepSize.Interval = 0; IntervalInformation aStep; // always positive aStep.Unit = LENGTH_UNIT; double step, minStep=0, maxStep=0; double stepTaken, accumTime=startTime; double speed; double cellLength; int retVal=OUT_OF_LENGTH, tmp; // Make sure we use the dataset found by the vtkAbstractInterpolatedVelocityField input = func->GetLastDataSet(); inputPD = input->GetPointData(); // Convert intervals to arc-length unit input->GetCell(func->GetLastCellId(), cell); cellLength = sqrt(static_cast(cell->GetLength2())); speed = vtkMath::Norm(velocity); // Never call conversion methods if speed == 0 if ( speed != 0.0 ) { this->ConvertIntervals( stepSize.Interval, minStep, maxStep, direction, cellLength ); } // Interpolate all point attributes on first point func->GetLastWeights(weights); //TODO: avoid this at least for time vectors //outputPD->InterpolatePoint(inputPD, nextPoint, cell->PointIds, weights); velocityArray->InsertNextTuple(velocity); speedArray->InsertNextValue(speed); // Compute vorticity if required // This can be used later for streamribbon generation. if (this->ComputeVorticity) { //TODO: for vorticity to work, inVectors should be updated with the vector field at the correct time step //inVectors->GetTuples(cell->PointIds, cellVectors); func->GetLastLocalCoordinates(pcoords); vort[0] = vort[1] = vort[2] = 0.0; //vtkStreamTracer::CalculateVorticity(cell, pcoords, cellVectors, vort); vorticity->InsertNextTuple(vort); // rotation // local rotation = vorticity . unit tangent ( i.e. velocity/speed ) if (speed != 0.0) { omega = vtkMath::Dot(vort, velocity); omega /= speed; omega *= this->RotationScale; } else { omega = 0.0; } angularVel->InsertNextValue(omega); rotation->InsertNextValue(0.0); } double error = 0; // Integrate until the maximum propagation length is reached, // maximum number of steps is reached or until a boundary is encountered. // Begin Integration while ( propagation < this->MaximumPropagation ) { if (numSteps > this->MaximumNumberOfSteps) { retVal = OUT_OF_STEPS; break; } if ( numSteps++ % 1000 == 1 ) { progress = ( currentLine + propagation / this->MaximumPropagation ) / numLines; this->UpdateProgress(progress); if (this->GetAbortExecute()) { shouldAbort = 1; break; } } // Never call conversion methods if speed == 0 if ( (speed == 0) || (speed <= this->TerminalSpeed) ) { retVal = STAGNATION; break; } // If, with the next step, propagation will be larger than // max, reduce it so that it is (approximately) equal to max. aStep.Interval = fabs( stepSize.Interval ); if ( ( propagation + aStep.Interval ) > this->MaximumPropagation ) { aStep.Interval = this->MaximumPropagation - propagation; if ( stepSize.Interval >= 0 ) { stepSize.Interval = this->ConvertToLength( aStep, cellLength ); } else { stepSize.Interval = this->ConvertToLength( aStep, cellLength ) * ( -1.0 ); } maxStep = stepSize.Interval; } this->LastUsedStepSize = stepSize.Interval; // Calculate the next step using the integrator provided // Break if the next point is out of bounds. func->SetNormalizeVector( true ); tmp = integrator->ComputeNextStep( point1, point2, accumTime, stepSize.Interval, stepTaken, minStep, maxStep, this->MaximumError, error ); func->SetNormalizeVector( false ); if ( tmp != 0 ) { retVal = tmp; memcpy(lastPoint, point2, 3*sizeof(double)); break; } // It is not enough to use the starting point for stagnation calculation // Use delX/stepSize to calculate speed and check if it is below // stagnation threshold double disp[3]; for (i=0; i<3; i++) { disp[i] = point2[i] - point1[i]; } if ( (stepSize.Interval == 0) || (vtkMath::Norm(disp) / fabs(stepSize.Interval) <= this->TerminalSpeed) ) { retVal = STAGNATION; break; } accumTime += stepTaken / speed; // Calculate propagation (using the same units as MaximumPropagation propagation += fabs( stepSize.Interval ); // This is the next starting point for(i=0; i<3; i++) { point1[i] = point2[i]; } double point2t[4]; memcpy(point2t, point2, 3*sizeof(double)); point2t[3] = accumTime; // Interpolate the velocity at the next point if ( !func->FunctionValues(point2t, velocity) ) { retVal = OUT_OF_DOMAIN; memcpy(lastPoint, point2, 3*sizeof(double)); break; } // Make sure we use the dataset found by the vtkAbstractInterpolatedVelocityField input = func->GetLastDataSet(); inputPD = input->GetPointData(); // Point is valid. Insert it. numPts++; numPtsTotal++; nextPoint = outputPoints->InsertNextPoint(point1); time->InsertNextValue(accumTime); // Calculate cell length and speed to be used in unit conversions input->GetCell(func->GetLastCellId(), cell); cellLength = sqrt(static_cast(cell->GetLength2())); velocityArray->InsertNextTuple(velocity); speed = vtkMath::Norm(velocity); speedArray->InsertNextValue(speed); // Interpolate all point attributes on current point func->GetLastWeights(weights); //TODO: avoid this at least for time vectors //outputPD->InterpolatePoint(inputPD, nextPoint, cell->PointIds, weights); // Compute vorticity if required // This can be used later for streamribbon generation. if (this->ComputeVorticity) { //TODO //inVectors->GetTuples(cell->PointIds, cellVectors); func->GetLastLocalCoordinates(pcoords); vort[0] = vort[1] = vort[2] = 0.0; //vtkStreamTracer::CalculateVorticity(cell, pcoords, cellVectors, vort); vorticity->InsertNextTuple(vort); // rotation // angular velocity = vorticity . unit tangent ( i.e. velocity/speed ) // rotation = sum ( angular velocity * stepSize ) omega = vtkMath::Dot(vort, velocity); omega /= speed; omega *= this->RotationScale; index = angularVel->InsertNextValue(omega); rotation->InsertNextValue(rotation->GetValue(index-1) + (angularVel->GetValue(index-1) + omega)/2 * (accumTime - time->GetValue(index-1))); } // Never call conversion methods if speed == 0 if ( (speed == 0) || (speed <= this->TerminalSpeed) ) { retVal = STAGNATION; break; } // Convert all intervals to arc length this->ConvertIntervals( step, minStep, maxStep, direction, cellLength ); // If the solver is adaptive and the next step size (stepSize.Interval) // that the solver wants to use is smaller than minStep or larger // than maxStep, re-adjust it. This has to be done every step // because minStep and maxStep can change depending on the cell // size (unless it is specified in arc-length unit) if (integrator->IsAdaptive()) { if (fabs(stepSize.Interval) < fabs(minStep)) { stepSize.Interval = fabs( minStep ) * stepSize.Interval / fabs( stepSize.Interval ); } else if (fabs(stepSize.Interval) > fabs(maxStep)) { stepSize.Interval = fabs( maxStep ) * stepSize.Interval / fabs( stepSize.Interval ); } } else { stepSize.Interval = step; } // End Integration } if (shouldAbort) { break; } if (numPts > 1) { outputLines->InsertNextCell(numPts); for (i=numPtsTotal-numPts; iInsertCellPoint(i); } retVals->InsertNextValue(retVal); } // Initialize these to 0 before starting the next line. // The values passed in the function call are only used // for the first line. inPropagation = propagation; inNumSteps = numSteps; propagation = 0; numSteps = 0; } if (!shouldAbort) { // Create the output polyline output->SetPoints(outputPoints); outputPD->AddArray(time); outputPD->AddArray(velocityArray); outputPD->AddArray(speedArray); if (vorticity) { outputPD->AddArray(vorticity); outputPD->AddArray(rotation); outputPD->AddArray(angularVel); } vtkIdType numPts = outputPoints->GetNumberOfPoints(); if ( numPts > 1 ) { // Assign geometry and attributes output->SetLines(outputLines); if (this->GenerateNormalsInIntegrate) { ////////////////////////////// TODO ////////////////////////////// //this->GenerateNormals(output, 0, vecName); } outputCD->AddArray(retVals); } } velocityArray->Delete(); speedArray->Delete(); if (vorticity) { vorticity->Delete(); rotation->Delete(); angularVel->Delete(); } if (cellVectors) { cellVectors->Delete(); } retVals->Delete(); outputPoints->Delete(); outputLines->Delete(); time->Delete(); integrator->Delete(); cell->Delete(); delete[] weights; output->Squeeze(); return; } void vtkvmtkStaticTemporalStreamTracer::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Seed time: " << this->SeedTime << " unit: time." << endl; } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkTetGenWrapper.h0000664000175000017500000001101111757446472020031 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkTetGenWrapper.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkTetGenWrapper - Converts linear elements to quadratic. // .SECTION Description // ... #ifndef __vtkvmtkTetGenWrapper_h #define __vtkvmtkTetGenWrapper_h #include "vtkUnstructuredGridAlgorithm.h" //#include "vtkPointSet.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkTetGenWrapper : public vtkUnstructuredGridAlgorithm { public: static vtkvmtkTetGenWrapper *New(); vtkTypeRevisionMacro(vtkvmtkTetGenWrapper,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); vtkSetMacro(PLC,int); vtkGetMacro(PLC,int); vtkBooleanMacro(PLC,int); vtkSetMacro(Refine,int); vtkGetMacro(Refine,int); vtkBooleanMacro(Refine,int); vtkSetMacro(Coarsen,int); vtkGetMacro(Coarsen,int); vtkBooleanMacro(Coarsen,int); vtkSetMacro(NoBoundarySplit,int); vtkGetMacro(NoBoundarySplit,int); vtkBooleanMacro(NoBoundarySplit,int); vtkSetMacro(Quality,int); vtkGetMacro(Quality,int); vtkBooleanMacro(Quality,int); vtkSetMacro(MinRatio,double); vtkGetMacro(MinRatio,double); vtkSetMacro(VarVolume,int); vtkGetMacro(VarVolume,int); vtkBooleanMacro(VarVolume,int); vtkSetMacro(FixedVolume,int); vtkGetMacro(FixedVolume,int); vtkBooleanMacro(FixedVolume,int); vtkSetMacro(MaxVolume,double); vtkGetMacro(MaxVolume,double); vtkSetMacro(RemoveSliver,int); vtkGetMacro(RemoveSliver,int); vtkBooleanMacro(RemoveSliver,int); vtkSetMacro(MaxDihedral,double); vtkGetMacro(MaxDihedral,double); vtkSetMacro(MinDihedral,double); vtkGetMacro(MinDihedral,double); vtkSetMacro(RegionAttrib,int); vtkGetMacro(RegionAttrib,int); vtkBooleanMacro(RegionAttrib,int); vtkSetMacro(Epsilon,double); vtkGetMacro(Epsilon,double); vtkSetMacro(NoMerge,int); vtkGetMacro(NoMerge,int); vtkBooleanMacro(NoMerge,int); vtkSetMacro(DetectInter,int); vtkGetMacro(DetectInter,int); vtkBooleanMacro(DetectInter,int); vtkSetMacro(CheckClosure,int); vtkGetMacro(CheckClosure,int); vtkBooleanMacro(CheckClosure,int); vtkSetMacro(Order,int); vtkGetMacro(Order,int); vtkSetMacro(DoCheck,int); vtkGetMacro(DoCheck,int); vtkBooleanMacro(DoCheck,int); vtkSetMacro(Verbose,int); vtkGetMacro(Verbose,int); vtkBooleanMacro(Verbose,int); vtkSetStringMacro(CellEntityIdsArrayName); vtkGetStringMacro(CellEntityIdsArrayName); vtkSetStringMacro(TetrahedronVolumeArrayName); vtkGetStringMacro(TetrahedronVolumeArrayName); vtkSetStringMacro(SizingFunctionArrayName); vtkGetStringMacro(SizingFunctionArrayName); vtkSetMacro(OutputSurfaceElements,int); vtkGetMacro(OutputSurfaceElements,int); vtkBooleanMacro(OutputSurfaceElements,int); vtkSetMacro(OutputVolumeElements,int); vtkGetMacro(OutputVolumeElements,int); vtkBooleanMacro(OutputVolumeElements,int); vtkSetMacro(UseSizingFunction,int); vtkGetMacro(UseSizingFunction,int); vtkBooleanMacro(UseSizingFunction,int); vtkSetMacro(LastRunExitStatus,int); protected: vtkvmtkTetGenWrapper(); ~vtkvmtkTetGenWrapper(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int PLC; int Refine; int Coarsen; int NoBoundarySplit; int Quality; double MinRatio; int VarVolume; int FixedVolume; double MaxVolume; int RemoveSliver; double MinDihedral; double MaxDihedral; int RegionAttrib; double Epsilon; int NoMerge; int DetectInter; int CheckClosure; int Order; int DoCheck; int Verbose; int UseSizingFunction; int LastRunExitStatus; char* CellEntityIdsArrayName; char* TetrahedronVolumeArrayName; char* SizingFunctionArrayName; int OutputSurfaceElements; int OutputVolumeElements; private: vtkvmtkTetGenWrapper(const vtkvmtkTetGenWrapper&); // Not implemented. void operator=(const vtkvmtkTetGenWrapper&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkMeshVorticity.h0000664000175000017500000000431511757446472020124 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMeshVorticity.h,v $ Language: C++ Date: $Date: 2006/07/27 08:28:36 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkMeshVorticity - ... // .SECTION Description // . #ifndef __vtkvmtkMeshVorticity_h #define __vtkvmtkMeshVorticity_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkUnstructuredGrid.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_MISC_EXPORT vtkvmtkMeshVorticity : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkMeshVorticity,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkMeshVorticity *New(); vtkSetStringMacro(VelocityArrayName); vtkGetStringMacro(VelocityArrayName); vtkSetStringMacro(VorticityArrayName); vtkGetStringMacro(VorticityArrayName); vtkSetMacro(ComputeIndividualPartialDerivatives,int); vtkGetMacro(ComputeIndividualPartialDerivatives,int); vtkBooleanMacro(ComputeIndividualPartialDerivatives,int); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); protected: vtkvmtkMeshVorticity(); ~vtkvmtkMeshVorticity(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* VelocityArrayName; char* VorticityArrayName; int ComputeIndividualPartialDerivatives; double ConvergenceTolerance; int QuadratureOrder; private: vtkvmtkMeshVorticity(const vtkvmtkMeshVorticity&); // Not implemented. void operator=(const vtkvmtkMeshVorticity&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkStreamlineOsculatingCentersFilter.h0000664000175000017500000000427611757446472024147 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStreamlineOsculatingCentersFilter.h,v $ Language: C++ Date: $Date: 2006/07/17 09:53:14 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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: vtkTypeRevisionMacro(vtkvmtkStreamlineOsculatingCentersFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); vtkPolyData* VoronoiDiagram; char* VoronoiSheetIdsArrayName; vtkPolyData* OsculatingCenters; private: vtkvmtkStreamlineOsculatingCentersFilter(const vtkvmtkStreamlineOsculatingCentersFilter&); // Not implemented. void operator=(const vtkvmtkStreamlineOsculatingCentersFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkImageBoxPainter.cxx0000664000175000017500000001101111757446472020673 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkImageBoxPainter.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:13:24 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkImageBoxPainter.h" #include "vtkImageData.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkImageBoxPainter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkImageBoxPainter); vtkvmtkImageBoxPainter::vtkvmtkImageBoxPainter() { this->PaintValue = 0.0; this->BoxBounds[0] = this->BoxBounds[2] = this->BoxBounds[4] = 0.0; this->BoxBounds[1] = this->BoxBounds[3] = this->BoxBounds[5] = 1.0; this->BoxExtent[0] = this->BoxExtent[2] = this->BoxExtent[4] = 0; this->BoxExtent[1] = this->BoxExtent[3] = this->BoxExtent[5] = 1; this->BoxDefinition = vtkvmtkImageBoxPainter::USE_EXTENT; } // The switch statement in Execute will call this method with // the appropriate input type (IT). Note that this example assumes // that the output data type is the same as the input data type. // This is not always the case. template void vtkvmtkImageBoxPainterExecute(vtkImageData* input, vtkImageData* output, IT* inPtr, IT* outPtr, int* boxExtent, IT paintValue) { int dims[3]; input->GetDimensions(dims); if (input->GetScalarType() != output->GetScalarType()) { vtkGenericWarningMacro(<< "Execute: input ScalarType, " << input->GetScalarType() << ", must match out ScalarType " << output->GetScalarType()); return; } int size = dims[0]*dims[1]*dims[2]; int ijk[3]; vtkIdType id; for (int i=0; iComputePointId(ijk); outPtr[id] = paintValue; } } } } void vtkvmtkImageBoxPainter::SimpleExecute(vtkImageData* input, vtkImageData* output) { void* inPtr = input->GetScalarPointer(); void* outPtr = output->GetScalarPointer(); double spacing[3]; input->GetSpacing(spacing); if (this->BoxDefinition == vtkvmtkImageBoxPainter::USE_BOUNDS) { this->BoxExtent[0] = (vtkIdType) ceil(this->BoxBounds[0] / spacing[0]); this->BoxExtent[1] = (vtkIdType) floor(this->BoxBounds[1] / spacing[0]); this->BoxExtent[2] = (vtkIdType) ceil(this->BoxBounds[2] / spacing[1]); this->BoxExtent[3] = (vtkIdType) floor(this->BoxBounds[3] / spacing[1]); this->BoxExtent[4] = (vtkIdType) ceil(this->BoxBounds[4] / spacing[2]); this->BoxExtent[5] = (vtkIdType) floor(this->BoxBounds[5] / spacing[2]); } int extent[6]; input->GetWholeExtent(extent); if ( this->BoxExtent[0] < extent[0] || this->BoxExtent[1] > extent[1] || this->BoxExtent[2] < extent[2] || this->BoxExtent[3] > extent[3] || this->BoxExtent[4] < extent[4] || this->BoxExtent[5] > extent[5] ) { vtkErrorMacro(<<"BoxExtent exceeds input WholeExtent"); return; } int relativeBoxExtent[6]; relativeBoxExtent[0] = this->BoxExtent[0] - extent[0]; relativeBoxExtent[1] = this->BoxExtent[1] - extent[0]; relativeBoxExtent[2] = this->BoxExtent[2] - extent[2]; relativeBoxExtent[3] = this->BoxExtent[3] - extent[2]; relativeBoxExtent[4] = this->BoxExtent[4] - extent[4]; relativeBoxExtent[5] = this->BoxExtent[5] - extent[4]; switch(output->GetScalarType()) { // This is simple a #define for a big case list. It handles // all data types vtk can handle. vtkTemplateMacro6(vtkvmtkImageBoxPainterExecute, input, output, (VTK_TT *)(inPtr), (VTK_TT *)(outPtr), relativeBoxExtent, (VTK_TT)this->PaintValue); default: vtkGenericWarningMacro("Execute: Unknown input ScalarType"); return; } } vmtk-1.0.1/vtkVmtk/Misc/vtkvmtkCurvedMPRImageFilter.cxx0000664000175000017500000003265011757446472021611 0ustar lucaluca#include "vtkvmtkCurvedMPRImageFilter.h" #include "vtkObjectFactory.h" //------------------------------------------------------------------------------ vtkCxxRevisionMacro(vtkvmtkCurvedMPRImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkCurvedMPRImageFilter); vtkvmtkCurvedMPRImageFilter::vtkvmtkCurvedMPRImageFilter() { this->Centerline = NULL; this->InplaneOutputSpacing[0] = 1.0; this->InplaneOutputSpacing[1] = 1.0; this->InplaneOutputSize[0] = 100; this->InplaneOutputSize[1] = 100; this->ReslicingBackgroundLevel = 0.0; for (int i = 0;i<6;i++) { this->OutputExtent[i] = 0; } for (int i = 0;i<3;i++) { this->OutputOrigin[i] = 0.0; } for (int i = 0;i<3;i++) { this->OutputSpacing[i] = 0.0; } this->FrenetTangentArrayName = NULL; this->ParallelTransportNormalsArrayName = NULL; } vtkvmtkCurvedMPRImageFilter::~vtkvmtkCurvedMPRImageFilter() { if (this->Centerline) { this->Centerline->Delete(); this->Centerline = NULL; } if (this->FrenetTangentArrayName) { delete[] this->FrenetTangentArrayName; this->FrenetTangentArrayName = NULL; } if (this->ParallelTransportNormalsArrayName) { delete[] this->ParallelTransportNormalsArrayName; this->ParallelTransportNormalsArrayName = NULL; } } //This is called by the superclass //---------------------------------------------------------------------------- int vtkvmtkCurvedMPRImageFilter::RequestUpdateExtent ( vtkInformation * vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *vtkNotUsed( outputVector )) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); // always request the whole extent inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()),6); return 1; } //---------------------------------------------------------------------------- // Compute new extent int vtkvmtkCurvedMPRImageFilter::RequestInformation ( vtkInformation * vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { // get the info objects vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkImageData *outputImage = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkInformation *inInfoImage = inputVector[0]->GetInformationObject(0); vtkImageData *inputImage = vtkImageData::SafeDownCast(inInfoImage->Get(vtkDataObject::DATA_OBJECT())); if (!this->Centerline) { vtkErrorMacro(<<"Centerline not set"); return 1; } //Check if the inputs are NULL if (inputImage == NULL || this->Centerline == NULL || outputImage==NULL) { if (outputImage) { outputImage->SetExtent(0,-1,0,-1,0,-1); outputImage->SetWholeExtent(0,-1,0,-1,0,-1); outputImage->SetUpdateExtent(0,-1,0,-1,0,-1); outputImage->AllocateScalars(); } if ( inputImage == NULL) { vtkErrorMacro(<< "RequestInformation: InputImageData is not set."); return 1; } else //Centerline==NULL { vtkErrorMacro(<< "RequestInformation: Centerline is not set."); return 1; } } int firstLineInCells; vtkCell* line = NULL; //get the first line in the vktPolyData for (firstLineInCells=0; firstLineInCells < this->Centerline->GetNumberOfCells(); firstLineInCells++) { line = this->Centerline->GetCell(firstLineInCells); if (line->GetCellType() == VTK_LINE || line->GetCellType() == VTK_POLY_LINE) { break; } } if (!line || (!(firstLineInCells < (int) this->Centerline->GetNumberOfCells()))) { vtkErrorMacro(<< "RequestInformation: no line in input vtkPolyData."); return 1; } vtkPoints* linePoints = line->GetPoints(); int numberOfLinePoints = linePoints->GetNumberOfPoints(); if (numberOfLinePoints < 2) { vtkErrorMacro(<< "RequestInformation: Too few points in Centerline."); return 1; } int inDataExtent[6]; double inDataOrigin[3]; inputImage->GetWholeExtent(inDataExtent); inputImage->GetSpacing(this->OutputSpacing); inputImage->GetOrigin(inDataOrigin); this->OutputExtent[0] = 0; this->OutputExtent[1] = this->InplaneOutputSize[0]-1; this->OutputExtent[2] = 0; this->OutputExtent[3] = this->InplaneOutputSize[1]-1; this->OutputExtent[4] = 0; this->OutputExtent[5] = numberOfLinePoints-1; double firstPoint[3], secondPoint[3], zspace; linePoints->GetPoint(0,firstPoint); linePoints->GetPoint(1,secondPoint); zspace = sqrt(vtkMath::Distance2BetweenPoints(firstPoint,secondPoint)); this->OutputSpacing[0]= this->InplaneOutputSpacing[0]; this->OutputSpacing[1]= this->InplaneOutputSpacing[1]; this->OutputSpacing[2]= zspace; this->OutputOrigin[0]=-1*((this->OutputExtent[1]-this->OutputExtent[0])/2)*this->OutputSpacing[0]; this->OutputOrigin[1]=-1*((this->OutputExtent[3]-this->OutputExtent[2])/2)*this->OutputSpacing[1]; this->OutputOrigin[2]=0; outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),this->OutputExtent,6); outInfo->Set(vtkDataObject::SPACING(),this->OutputSpacing,3); outInfo->Set(vtkDataObject::ORIGIN(),this->OutputOrigin,3); return 1; } template void vtkvmtkCurvedMPRImageFilter::FillSlice(T* outReslicePtr, T* outputImagePtr, int* resliceUpdateExtent, int* outExtent, vtkIdType* outputInc, int slice) { //write result to the new dataset int size = (outExtent[1]-outExtent[0]+1)*(outExtent[3]-outExtent[2]+1); for(int i=0; iGetInformationObject(0); vtkImageData *outputImage = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkInformation *inInfoImage = inputVector[0]->GetInformationObject(0); vtkImageData *inputImage = vtkImageData::SafeDownCast(inInfoImage->Get(vtkDataObject::DATA_OBJECT())); if (!this->Centerline) { vtkErrorMacro(<<"Centerline not set"); return 1; } if (inputImage == NULL) { vtkErrorMacro(<< "RequestData: InputImageData is not set."); return 1; } //check if everything is allright if (inputImage == NULL || outputImage==NULL) { if (outputImage) { outputImage->SetExtent(0,-1,0,-1,0,-1); outputImage->SetWholeExtent(0,-1,0,-1,0,-1); outputImage->SetUpdateExtent(0,-1,0,-1,0,-1); outputImage->AllocateScalars(); } } //check if FrenetTangent s are available if ( this->FrenetTangentArrayName == NULL) { vtkErrorMacro(<< "RequestData: FrenetTangentArrayName is not set."); return 1; } vtkDataArray* frenetArray = this->Centerline->GetPointData()->GetArray(this->FrenetTangentArrayName); if (!frenetArray) { vtkErrorMacro(<< "RequestData: InputPolyData does not contain an array with the specified FrenetTangentArrayName."); return 1; } //check if ParallelTransportNormals are available if ( this->ParallelTransportNormalsArrayName == NULL) { vtkErrorMacro(<< "RequestData: ParallelTransportNormalsArrayName is not set."); return 1; } //check if a Centerline is available vtkDataArray* parallelArray = this->Centerline->GetPointData()->GetArray(this->ParallelTransportNormalsArrayName); if (!parallelArray) { vtkErrorMacro(<< "RequestData: InputPolyData does not contain an array with the specified ParallelTransportNormalsArrayName."); return 1; } int firstLineInCells; vtkCell* line = NULL; //get the first line in the vktPolyData for (firstLineInCells=0; firstLineInCellsCenterline->GetNumberOfCells(); firstLineInCells++) { line = this->Centerline->GetCell(firstLineInCells); if (line->GetCellType() == VTK_LINE || line->GetCellType() == VTK_POLY_LINE) { break; } } if (!line || (!(firstLineInCells < (int) this->Centerline->GetNumberOfCells()))) { vtkErrorMacro(<< "RequestData: no line in input vtkPolyData."); return 1; } if (line->GetNumberOfPoints() < 2) { vtkErrorMacro(<< "RequestData: Too few points in Centerline."); return 1; } vtkPoints* linePoints = line->GetPoints(); int outExtent[6]; outputImage->GetUpdateExtent(outExtent); outputImage->SetExtent(outExtent); outputImage->SetWholeExtent(outExtent); outputImage->SetUpdateExtent(outExtent); outputImage->AllocateScalars(); vtkDataArray* frenetTangentArray = this->Centerline->GetPointData()->GetArray(this->FrenetTangentArrayName); vtkDataArray* parallelTransportNormalsArray = this->Centerline->GetPointData()->GetArray(this->ParallelTransportNormalsArrayName); //start computing int inExtent[6]; inputImage->GetWholeExtent(inExtent); // if the input extent is empty then exit if (inExtent[1] < inExtent[0] || inExtent[3] < inExtent[2] || inExtent[5] < inExtent[4]) { return 1; } vtkImageReslice* reslice = vtkImageReslice::New(); reslice->SetOutputDimensionality(2); reslice->SetInput(inputImage); reslice->SetInterpolationModeToCubic(); //turn off transformation of the input spacin, origin and extent, so we can define what we want reslice->TransformInputSamplingOff(); //set the value of the voxels that are out of the input data reslice->SetBackgroundLevel(this->ReslicingBackgroundLevel); //set the outputspacing //reslice->SetOutputSpacing(this->OutputSpacing[0],this->OutputSpacing[1],this->OutputSpacing[2]); reslice->SetOutputSpacing(this->OutputSpacing); // going to MPR for (int slice=outExtent[4]; slice<(outExtent[5] + 1);slice++) {// for each slice (or point on the line) double centerSlice[3]; linePoints->GetPoint(slice,centerSlice); // To calculate the outputorigin & the necessarry transform // the vectors are retreived from the array's //t is the vector in the direction of the Centerline, so along the z-axis in the MPR volume double t[3]; frenetTangentArray->GetTuple(slice,t); //p is a normal of the Centerline, directed to the 'North' direction of the inputvolume,in the MPR volume this will be along the x-axis double p[3]; parallelTransportNormalsArray->GetTuple(slice,p); double tp[3]; //tp is the crossproduct of t and p, and will be directed to the 'West' direction of the inputvolume,in the MPR volume this will be along the y-axis tp[0] = (t[1]*p[2]- t[2]*p[1]); tp[1] = (t[2]*p[0]- t[0]*p[2]); tp[2] = (t[0]*p[1]- t[1]*p[0]); //set the axis of the first slice according to the vectors of the first point in the line reslice->SetResliceAxesDirectionCosines(p[0],p[1],p[2],tp[0],tp[1],tp[2],t[0],t[1],t[2]); // the firstPoint on the Centerline coresponds to the origin of the output axes unit vectors reslice->SetResliceAxesOrigin(centerSlice[0],centerSlice[1],centerSlice[2]); //the outputextent will be one slice reslice->SetOutputExtent(this->OutputExtent[0],this->OutputExtent[1],this->OutputExtent[2],this->OutputExtent[3],0,0); //the outputorigin in the input coordinate system is set to zero double outputorigin[3]; outputorigin[0] = 0.0; outputorigin[1] = 0.0; outputorigin[2] = 0.0; reslice->SetOutputOrigin(this->OutputOrigin); reslice->Update(); int resliceUpdateExtent[6]; resliceUpdateExtent[0] = outExtent[0]; resliceUpdateExtent[1] = outExtent[1]; resliceUpdateExtent[2] = outExtent[2]; resliceUpdateExtent[3] = outExtent[3]; resliceUpdateExtent[4] = 0; resliceUpdateExtent[5] = 0; vtkIdType outputInc[3]; outputImage->GetIncrements(outputInc); int scalarType = reslice->GetOutput()->GetScalarType(); switch (scalarType) { vtkTemplateMacro( FillSlice( static_cast(reslice->GetOutput()->GetScalarPointerForExtent(resliceUpdateExtent)), static_cast(outputImage->GetScalarPointerForExtent(outExtent)), resliceUpdateExtent, outExtent, outputInc, slice)); } }// for each slice reslice->Delete(); return 1; } void vtkvmtkCurvedMPRImageFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Centerline: " << this->Centerline << "\n"; os << indent << "InplaneOutputSpacing: (" << this->InplaneOutputSpacing[0] << " " << this->InplaneOutputSpacing[1] << ")\n"; os << indent << "InplaneOutputSize: (" << this->InplaneOutputSize[0] << " " << this->InplaneOutputSize[1] << ")\n"; os << indent << "OutputSpacing: (" << this->OutputSpacing[0] << ", " << this->OutputSpacing[1] << ", " << this->OutputSpacing[2] << ")\n"; os << indent << "ReslicingBackgroundLevel: (" << this->ReslicingBackgroundLevel << ")\n"; os << indent << "OutputExtent: (" << this->OutputExtent[0] << ", " << this->OutputExtent[1] << ", " << this->OutputExtent[2] << ")\n"; os << indent << "OutputExtent(3-5): (" << this->OutputExtent[3] << ", " << this->OutputExtent[4] << ", " << this->OutputExtent[5] << ")\n"; os << indent << "OutputOrigin: (" << this->OutputOrigin[0] << ", " << this->OutputOrigin[1] << ", " << this->OutputOrigin[2] << ")\n"; os << indent << "OutputSpacing: (" << this->OutputSpacing[0] << ", " << this->OutputSpacing[1] << ", " << this->OutputSpacing[2] << ")\n"; } vmtk-1.0.1/vtkVmtk/vtkvmtkConfigure.h.in0000664000175000017500000000052211757446472016742 0ustar lucaluca/* * Here is where system computed values get stored. * These values should only change when the target compile platform changes. */ #cmakedefine VTK_VMTK_BUILD_SHARED_LIBS #ifndef VTK_VMTK_BUILD_SHARED_LIBS #define VTK_VMTK_STATIC #endif #if defined(_MSC_VER) && !defined(VTK_VMTK_STATIC) #pragma warning ( disable : 4275 ) #endif vmtk-1.0.1/vtkVmtk/Rendering/0000775000175000017500000000000011757446472014532 5ustar lucalucavmtk-1.0.1/vtkVmtk/Rendering/vtkvmtkInteractorStyleTrackballCamera.h0000664000175000017500000000324511757446472024422 0ustar lucaluca/*========================================================================= Program: VMTK Module: vtkvmtkInteractorStyleTrackballCamera Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .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(); vtkTypeRevisionMacro(vtkvmtkInteractorStyleTrackballCamera,vtkInteractorStyleTrackballCamera); //void PrintSelf(ostream& os, vtkIndent indent); protected: vtkvmtkInteractorStyleTrackballCamera() {}; ~vtkvmtkInteractorStyleTrackballCamera() {}; virtual void OnChar(); private: vtkvmtkInteractorStyleTrackballCamera(const vtkvmtkInteractorStyleTrackballCamera&); //Not implemented void operator=(const vtkvmtkInteractorStyleTrackballCamera&); //Not implemented }; #endif vmtk-1.0.1/vtkVmtk/Rendering/CMakeLists.txt0000664000175000017500000000735411757446472017303 0ustar lucalucaSET (VTK_VMTK_RENDERING_SRCS vtkvmtkInteractorStyleTrackballCamera.cxx ) SET (VTK_VMTK_RENDERING_TARGET_LINK_LIBRARIES vtkvmtkRendering vtkCommon vtkFiltering vtkGraphics vtkHybrid vtkRendering vtkWidgets) ADD_LIBRARY (vtkvmtkRendering ${VTK_VMTK_RENDERING_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkRendering PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkRendering ${VTK_VMTK_RENDERING_TARGET_LINK_LIBRARIES}) INSTALL(TARGETS vtkvmtkRendering LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_RENDERING_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/Rendering/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkRendering) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkRenderingPython VTK_VMTK_RENDERING_PYTHON_SRCS "${VTK_VMTK_RENDERING_SRCS}") ADD_LIBRARY(vtkvmtkRenderingPythonD ${VTK_VMTK_RENDERING_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkRenderingPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkRenderingPython MODULE vtkvmtkRenderingPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkRenderingPythonD vtkvmtkRendering vtkCommon vtkCommonPythonD vtkFiltering vtkFilteringPythonD vtkGraphics vtkGraphicsPythonD vtkRendering vtkRenderingPythonD vtkWidgets vtkWidgetsPythonD) TARGET_LINK_LIBRARIES (vtkvmtkRenderingPython vtkvmtkRenderingPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkRenderingPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkRenderingPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkRenderingPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkRenderingTCL VTK_VMTK_RENDERING_TCL_SRCS "${VTK_VMTK_RENDERING_SRCS}" "") ADD_LIBRARY(vtkvmtkRenderingTCL ${VTK_VMTK_RENDERING_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkRenderingTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkRenderingTCL vtkvmtkRendering vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkGraphics vtkGraphicsTCL vtkRendering vtkRenderingTCL vtkWidgets vtkWidgetsTCL) INSTALL(TARGETS vtkvmtkRenderingTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkRenderingTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/Rendering/vtkvmtkInteractorStyleTrackballCamera.cxx0000664000175000017500000000202111757446472024764 0ustar lucaluca/*========================================================================= Program: VMTK Module: vtkvmtkInteractorStyleTrackballCamera Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkInteractorStyleTrackballCamera.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkInteractorStyleTrackballCamera, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkInteractorStyleTrackballCamera); void vtkvmtkInteractorStyleTrackballCamera::OnChar() { } vmtk-1.0.1/vtkVmtk/IO/0000775000175000017500000000000011757446472013124 5ustar lucalucavmtk-1.0.1/vtkVmtk/IO/vtkvmtkFDNEUTWriter.h0000664000175000017500000000415511757446472017113 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFDNEUTWriter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkFDNEUTWriter - // .SECTION Description // vtkvmtkFDNEUTWriter writes FDNEUT Fidap files // .SECTION See Also // vtkvmtkFDNEUTWriter #ifndef __vtkvmtkFDNEUTWriter_h #define __vtkvmtkFDNEUTWriter_h #include "vtkvmtkWin32Header.h" #include "vtkUnstructuredGridWriter.h" class VTK_VMTK_IO_EXPORT vtkvmtkFDNEUTWriter : public vtkUnstructuredGridWriter { public: static vtkvmtkFDNEUTWriter *New(); vtkTypeRevisionMacro(vtkvmtkFDNEUTWriter,vtkUnstructuredGridWriter); void PrintSelf(ostream& os, vtkIndent indent); //BTX enum { EDGE = 0, QUADRILATERAL, TRIANGLE, BRICK, WEDGE, TETRAHEDRON }; //ETX protected: vtkvmtkFDNEUTWriter(); ~vtkvmtkFDNEUTWriter(); void WriteData(); static void ZeroToOneOffset(vtkIdType npts, vtkIdType* pts) { for (int i=0; i class VTK_VMTK_IO_EXPORT vtkvmtkTetGenReader : public vtkUnstructuredGridReader { public: vtkTypeRevisionMacro(vtkvmtkTetGenReader,vtkUnstructuredGridReader); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkTetGenReader *New(); vtkSetStringMacro(BoundaryDataArrayName); vtkGetStringMacro(BoundaryDataArrayName); protected: vtkvmtkTetGenReader(); ~vtkvmtkTetGenReader(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); //BTX void Tokenize(const std::string& str, std::vector& tokens, const std::string& delimiters); //ETX char* BoundaryDataArrayName; private: vtkvmtkTetGenReader(const vtkvmtkTetGenReader&); // Not implemented. void operator=(const vtkvmtkTetGenReader&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/IO/vtkvmtkFDNEUTWriter.cxx0000664000175000017500000003263111757446472017466 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFDNEUTWriter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkFDNEUTWriter.h" #include "vtkUnstructuredGrid.h" #include "vtkCellType.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkFDNEUTWriter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkFDNEUTWriter); vtkvmtkFDNEUTWriter::vtkvmtkFDNEUTWriter() { } vtkvmtkFDNEUTWriter::~vtkvmtkFDNEUTWriter() { } void vtkvmtkFDNEUTWriter::WriteData() { vtkUnstructuredGrid *input= vtkUnstructuredGrid::SafeDownCast(this->GetInput()); if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return; } FILE* FDNEUTFile = fopen(this->FileName,"w"); if (!FDNEUTFile) { vtkErrorMacro(<<"Could not open file for writing."); return; } int numberOfNodes, numberOfElements, numberOfGroups; numberOfNodes = input->GetNumberOfPoints(); numberOfElements = input->GetNumberOfCells(); int cellType; const int numberOfCellTypes = VTK_QUADRATIC_PYRAMID+1; int numberOfTypeCells[numberOfCellTypes]; int firstCellIdOfType[numberOfCellTypes]; int k; for (k=0; kGetCellType(k); switch (cellType) { case VTK_QUAD: case VTK_QUADRATIC_QUAD: case VTK_TRIANGLE: case VTK_QUADRATIC_TRIANGLE: case VTK_HEXAHEDRON: case VTK_QUADRATIC_HEXAHEDRON: case VTK_WEDGE: case VTK_QUADRATIC_WEDGE: case VTK_TETRA: case VTK_QUADRATIC_TETRA: ++numberOfTypeCells[cellType]; firstCellIdOfType[cellType] = k; break; default: vtkWarningMacro(<<"Unsupported cell type found"); break; } } numberOfGroups = 0; for (k=0; k 0) { ++numberOfGroups; } } fprintf(FDNEUTFile,"** FIDAP NEUTRAL FILE\n"); fprintf(FDNEUTFile,"foo\n"); // TODO: set user-defined title fprintf(FDNEUTFile,"VERSION 8.6\n"); fprintf(FDNEUTFile," Jan 2004 \n"); fprintf(FDNEUTFile," NO. OF NODES NO. ELEMENTS NO. ELT GROUPS NDFCD NDFVL\n"); fprintf(FDNEUTFile,"%15d%15d%15d%15d%15d\n",numberOfNodes,numberOfElements,numberOfGroups,3,3); fprintf(FDNEUTFile," STEADY/TRANS TURB. FLAG FREE SURF FLAG COMPR. FLAG RESULTS ONLY\n"); fprintf(FDNEUTFile," 0 0 0 0 0\n"); fprintf(FDNEUTFile,"TEMPERATURE/SPECIES FLAGS\n"); fprintf(FDNEUTFile," 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"); fprintf(FDNEUTFile,"PRESSURE FLAGS - IDCTS, IPENY MPDF\n"); fprintf(FDNEUTFile," 1 1 0\n"); fprintf(FDNEUTFile,"NODAL COORDINATES\n"); double point[3]; for (k=0; kGetPoint(k,point); fprintf(FDNEUTFile,"%10d%20.10e%20.10e%20.10e\n",k+1,point[0],point[1],point[2]); } fprintf(FDNEUTFile,"BOUNDARY CONDITIONS\n"); fprintf(FDNEUTFile," 0 0 0 0.0\n"); fprintf(FDNEUTFile,"ELEMENT GROUPS\n"); int cellCount = 1; int groupCount = 1; // for (cellType=0; cellType=0; cellType--) { if (numberOfTypeCells[cellType] == 0) { continue; } int fdneutElementType, fdneutElementGeometry, numberOfNodesInElement; vtkIdType npts, *pts, *cellPoints; fdneutElementType = -1; fdneutElementGeometry = -1; input->GetCellPoints(firstCellIdOfType[cellType],npts,pts); numberOfNodesInElement = npts; switch (cellType) { case VTK_QUAD: case VTK_QUADRATIC_QUAD: fdneutElementType = 15; fdneutElementGeometry = QUADRILATERAL; break; case VTK_TRIANGLE: case VTK_QUADRATIC_TRIANGLE: fdneutElementType = 15; fdneutElementGeometry = TRIANGLE; break; case VTK_HEXAHEDRON: case VTK_QUADRATIC_HEXAHEDRON: fdneutElementType = BRICK; fdneutElementGeometry = BRICK; break; case VTK_WEDGE: case VTK_QUADRATIC_WEDGE: fdneutElementType = WEDGE; fdneutElementGeometry = WEDGE; break; case VTK_TETRA: case VTK_QUADRATIC_TETRA: fdneutElementType = TETRAHEDRON; fdneutElementGeometry = TETRAHEDRON; break; } int groupNumber, numberOfElementsInGroup; groupNumber = groupCount; numberOfElementsInGroup = numberOfTypeCells[cellType]; fprintf(FDNEUTFile,"GROUP: %5d ELEMENTS:%10d NODES: %10d GEOMETRY:%5d TYPE:%4d\n",groupNumber,numberOfElementsInGroup,numberOfNodesInElement,fdneutElementGeometry,fdneutElementType); fprintf(FDNEUTFile,"ENTITY NAME: Entity%d\n",groupNumber); for (k=0; kGetCellType(k) != cellType) { continue; } input->GetCellPoints(k,npts,pts); cellPoints = new vtkIdType[npts]; memcpy(cellPoints,pts,npts*sizeof(vtkIdType)); this->ZeroToOneOffset(npts,cellPoints); if (npts != numberOfNodesInElement) { vtkErrorMacro(<<"Can't handle same cell types with different number of points"); return; } fprintf(FDNEUTFile,"%8d",(int)cellCount); int i; switch (cellType) { case VTK_QUAD: for (i=0; i #include "vtkvmtkFluentWriter.h" #include "vtkUnstructuredGrid.h" #include "vtkTetra.h" #include "vtkCellType.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkIntArray.h" #include "vtkIdTypeArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkFluentWriter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkFluentWriter); vtkvmtkFluentWriter::vtkvmtkFluentWriter() { this->BoundaryDataArrayName = NULL; } vtkvmtkFluentWriter::~vtkvmtkFluentWriter() { if (this->BoundaryDataArrayName) { delete[] this->BoundaryDataArrayName; this->BoundaryDataArrayName = NULL; } } void vtkvmtkFluentWriter::ConvertFaceToLeftHanded(vtkUnstructuredGrid* input, vtkIdType tetraCellId, vtkIdType& id0, vtkIdType& id1, vtkIdType& id2) { vtkTetra* tetra = vtkTetra::SafeDownCast(input->GetCell(tetraCellId)); vtkIdList* cellPointIds = tetra->GetPointIds(); vtkIdType id3 = -1; vtkIdType tmpId = -1; int k; for (k=0; k<4; k++) { tmpId = cellPointIds->GetId(k); if (tmpId != id0 && tmpId != id1 && tmpId != id2) { id3 = tmpId; break; } } bool reverse = false; double point0[3], point1[3], point2[3], point3[3]; double vector0[3], vector1[3], vector2[3]; double cross[3]; input->GetPoint(id0,point0); input->GetPoint(id1,point1); input->GetPoint(id2,point2); input->GetPoint(id3,point3); vector0[0] = point1[0] - point0[0]; vector0[1] = point1[1] - point0[1]; vector0[2] = point1[2] - point0[2]; vector1[0] = point2[0] - point0[0]; vector1[1] = point2[1] - point0[1]; vector1[2] = point2[2] - point0[2]; vector2[0] = point3[0] - point0[0]; vector2[1] = point3[1] - point0[1]; vector2[2] = point3[2] - point0[2]; vtkMath::Cross(vector0,vector1,cross); if (vtkMath::Dot(cross,vector2) < 0.0) { reverse = true; } if (reverse) { tmpId = id2; id2 = id1; id1 = tmpId; } } void vtkvmtkFluentWriter::WriteData() { vtkUnstructuredGrid *input= vtkUnstructuredGrid::SafeDownCast(this->GetInput()); if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return; } ofstream out (this->FileName); if (!out.good()) { vtkErrorMacro(<<"Could not open file for writing."); return; } input->BuildLinks(); int numberOfPoints = input->GetNumberOfPoints(); int numberOfCells = input->GetNumberOfCells(); vtkIntArray* boundaryDataArray = vtkIntArray::New(); if (this->BoundaryDataArrayName) { if (input->GetCellData()->GetArray(this->BoundaryDataArrayName)) { boundaryDataArray->DeepCopy(input->GetCellData()->GetArray(this->BoundaryDataArrayName)); } else { vtkErrorMacro(<<"BoundaryDataArray with name specified does not exist"); boundaryDataArray->Delete(); return; } } else { boundaryDataArray->SetNumberOfValues(numberOfCells); boundaryDataArray->FillComponent(0,0.0); } vtkIdTypeArray* tetraCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TETRA,tetraCellIdArray); int numberOfTetras = tetraCellIdArray->GetNumberOfTuples(); vtkIdList* tetraCellIdMap = vtkIdList::New(); tetraCellIdMap->SetNumberOfIds(numberOfCells); int i; for (i=0; iSetId(i,-1); } for (i=0; iSetId(tetraCellIdArray->GetValue(i),i); } vtkIdTypeArray* triangleCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TRIANGLE,triangleCellIdArray); int numberOfTriangles = triangleCellIdArray->GetNumberOfTuples(); // out << "(0 \"Fluent file generated by the Vascular Modeling Toolkit - www.vmtk.org\" )" << endl; out << "(0 \"GAMBIT to Fluent File\")" << endl; out << "(0 \"Dimension:\")" << endl; out << "(2 3)" << endl; out << endl; char str[200]; sprintf(str,"(10 (0 1 %x 1 3))",numberOfPoints); out << str << endl; sprintf(str,"(10 (1 1 %x 1 3)(",numberOfPoints); out << str << endl; out.precision(6); double point[3]; for (i=0; iGetPoint(i,point); sprintf(str," %17.10e %17.10e %17.10e",point[0],point[1],point[2]); out << str << endl; } out << " ))" << endl << endl; out << "(0 \"Faces:\")" << endl; int numberOfInteriorFaces = 2*numberOfTetras - numberOfTriangles/2; sprintf(str,"(13 (0 1 %x 0))",numberOfInteriorFaces+numberOfTriangles); out << str << endl; int faceOffset = 1; vtkIdList* boundaryDataNumberOfTriangles = vtkIdList::New(); int boundaryDataRange = static_cast(boundaryDataArray->GetRange()[1]); boundaryDataNumberOfTriangles->SetNumberOfIds(boundaryDataRange+1); for (i=0; iSetId(i,0); } int boundaryDataValue, value; for (i=0; iGetValue(i); boundaryDataValue = boundaryDataArray->GetValue(triangleCellId); value = boundaryDataNumberOfTriangles->GetId(boundaryDataValue); boundaryDataNumberOfTriangles->SetId(boundaryDataValue,value+1); } vtkIdList* neighborCellIds = vtkIdList::New(); const int entityOffset = 3; int entityId = entityOffset; int n; for (n=0; nGetId(n); if (numberOfBoundaryTriangles == 0) { continue; } //sprintf(str,"(13 (%x %x %x %x 0)(",entityId,faceOffset,faceOffset+numberOfBoundaryTriangles-1,entityId); sprintf(str,"(13 (%x %x %x 3 0)(",entityId,faceOffset,faceOffset+numberOfBoundaryTriangles-1); entityId++; out << str << endl; for (i=0; iGetValue(i); if (boundaryDataArray->GetValue(triangleCellId) != n) { continue; } vtkIdList* cellPointIds = input->GetCell(triangleCellId)->GetPointIds(); vtkIdType id0 = cellPointIds->GetId(0); vtkIdType id1 = cellPointIds->GetId(1); vtkIdType id2 = cellPointIds->GetId(2); input->GetCellNeighbors(triangleCellId,cellPointIds,neighborCellIds); vtkIdType tetraCellId = neighborCellIds->GetId(0); this->ConvertFaceToLeftHanded(input,tetraCellId,id0,id1,id2); sprintf(str," 3 %x %x %x %x 0",(int)id0+1,(int)id1+1,(int)id2+1,(int)tetraCellId+1); out << str << endl; } out << "))" << endl << endl; faceOffset += numberOfBoundaryTriangles; } sprintf(str,"(13 (%x %x %x 2 0)(",(int)entityId,faceOffset,faceOffset+numberOfInteriorFaces-1); out << str << endl; //TODO: loop over tets and write interior faces. //one space, #points on the face, pid1, pid2, pid3, tetraid1, tetraid2 for (i=0; iGetValue(i); vtkTetra* tetra = vtkTetra::SafeDownCast(input->GetCell(tetraCellId)); int j; for (j=0; j<4; j++) { vtkCell* face = tetra->GetFace(j); vtkIdList* facePointIds = face->GetPointIds(); vtkIdType id0 = facePointIds->GetId(0); vtkIdType id1 = facePointIds->GetId(1); vtkIdType id2 = facePointIds->GetId(2); input->GetCellNeighbors(tetraCellId,facePointIds,neighborCellIds); if (neighborCellIds->GetNumberOfIds() != 1) { continue; } if (input->GetCellType(neighborCellIds->GetId(0)) != VTK_TETRA) { continue; } if (neighborCellIds->GetId(0) < tetraCellId) { continue; } this->ConvertFaceToLeftHanded(input,tetraCellId,id0,id1,id2); sprintf(str," 3 %x %x %x %x %x",(int)id0+1,(int)id1+1,(int)id2+1,(int)tetraCellIdMap->GetId(tetraCellId)+1,(int)tetraCellIdMap->GetId(neighborCellIds->GetId(0))+1); out << str << endl; } } out << "))" << endl << endl; faceOffset += numberOfInteriorFaces; neighborCellIds->Delete(); out << "(0 \"Cells:\")" << endl; sprintf(str,"(12 (0 1 %x 0))",numberOfTetras); out << str << endl; sprintf(str,"(12 (2 1 %x 1 2))",numberOfTetras); out << str << endl << endl; out << "(0 \"Zones:\")" << endl; out << "(45 (2 fluid blood)())" << endl; int numberOfBoundaryTriangles = 0; entityId = entityOffset; for (n=0; nGetId(n); if (numberOfBoundaryTriangles == 0) { continue; } sprintf(str,"(45 (%x wall surface%d)())",entityId,entityId); entityId++; out << str << endl; } sprintf(str,"(45 (%x interior default-interior)())",entityId); out << str << endl; boundaryDataNumberOfTriangles->Delete(); triangleCellIdArray->Delete(); tetraCellIdArray->Delete(); tetraCellIdMap->Delete(); } void vtkvmtkFluentWriter::PrintSelf(ostream& os, vtkIndent indent) { vtkUnstructuredGridWriter::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/IO/vtkvmtkTetGenReader.cxx0000664000175000017500000002074311757446472017616 0ustar lucaluca/*========================================================================= Program: VMTK Module: vtkvmtkTetGenReader.cxx Language: C++ Date: Sat Feb 19 15:14:48 CET 2011 Version: Revision: 1.0 Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkTetGenReader.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkObjectFactory.h" #include "vtkPoints.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkvmtkConstants.h" #include vtkCxxRevisionMacro(vtkvmtkTetGenReader, "Revision: 1.0"); vtkStandardNewMacro(vtkvmtkTetGenReader); vtkvmtkTetGenReader::vtkvmtkTetGenReader() { this->BoundaryDataArrayName = NULL; } vtkvmtkTetGenReader::~vtkvmtkTetGenReader() { if (this->BoundaryDataArrayName) { delete[] this->BoundaryDataArrayName; this->BoundaryDataArrayName = NULL; } } void vtkvmtkTetGenReader::Tokenize(const std::string& str, std::vector& tokens, const std::string& delimiters) { if (tokens.size() > 0) { tokens.clear(); } std::string::size_type lastPos = str.find_first_not_of(delimiters,0); std::string::size_type pos = str.find_first_of(delimiters,lastPos); while (std::string::npos != pos || std::string::npos != lastPos) { tokens.push_back(str.substr(lastPos,pos-lastPos)); lastPos = str.find_first_not_of(delimiters, pos); pos = str.find_first_of(delimiters, lastPos); } } int vtkvmtkTetGenReader::RequestData( vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *outInfo = outputVector->GetInformationObject(0); vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) { return 1; } if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return 1; } std::string nodeFileName = this->FileName; nodeFileName += ".node"; std::string eleFileName = this->FileName; eleFileName += ".ele"; ifstream nodeStream(nodeFileName.c_str()); ifstream eleStream(eleFileName.c_str()); if (!nodeStream.good()) { vtkErrorMacro(<<"Could not open .node file for reading."); return 0; } if (!eleStream.good()) { vtkErrorMacro(<<"Could not open .ele file for reading."); return 0; } std::string line; std::string delimiter(" "); std::vector tokens; std::getline(nodeStream,line); this->Tokenize(line,tokens,delimiter); int nodeCount, dim, numberOfAttributes, boundaryMarkers; //TODO: check number of entries of each line. nodeCount = atoi(tokens[0].c_str()); dim = atoi(tokens[1].c_str()); numberOfAttributes = atoi(tokens[2].c_str()); boundaryMarkers = atoi(tokens[3].c_str()); vtkPoints* outputPoints = vtkPoints::New(); outputPoints->SetNumberOfPoints(nodeCount); int i, j; vtkDoubleArray** attributeArrays = new vtkDoubleArray*[numberOfAttributes]; for (j=0; jSetName(nameStream.str().c_str()); attributeArray->SetNumberOfComponents(1); attributeArray->SetNumberOfTuples(nodeCount); attributeArrays[j] = attributeArray; } vtkIdTypeArray* boundaryDataArray = vtkIdTypeArray::New(); if (boundaryMarkers) { boundaryDataArray->SetName(this->BoundaryDataArrayName); boundaryDataArray->SetNumberOfComponents(1); boundaryDataArray->SetNumberOfTuples(nodeCount); } double point[3], value; vtkIdType boundaryId; int firstIndex = 0; int index; for (i=0; iTokenize(line,tokens,delimiter); index = atoi(tokens[0].c_str()); if (i==0) { // Here we make the assumption that node 0 or 1 appear in the first line firstIndex = index; } point[0] = atof(tokens[1].c_str()); point[1] = atof(tokens[2].c_str()); point[2] = atof(tokens[3].c_str()); outputPoints->SetPoint(index-firstIndex,point); for (j=0; jSetValue(i,value); } if (boundaryMarkers) { boundaryId = atoi(tokens[4+numberOfAttributes].c_str()); boundaryDataArray->SetValue(i,boundaryId); } } output->SetPoints(outputPoints); outputPoints->Delete(); for (j=0; jGetPointData()->AddArray(attributeArrays[j]); attributeArrays[j]->Delete(); } delete[] attributeArrays; if (boundaryMarkers) { output->GetPointData()->AddArray(boundaryDataArray); } std::getline(eleStream,line); this->Tokenize(line,tokens,delimiter); int tetCount, nodesPerTet, numberOfCellAttributes; tetCount = atoi(tokens[0].c_str()); nodesPerTet = atoi(tokens[1].c_str()); numberOfCellAttributes = atoi(tokens[2].c_str()); vtkDoubleArray** cellAttributeArrays = new vtkDoubleArray*[numberOfCellAttributes]; for (j=0; jSetName(nameStream.str().c_str()); attributeArray->SetNumberOfComponents(1); attributeArray->SetNumberOfTuples(nodeCount); cellAttributeArrays[j] = attributeArray; } int* outputCellTypes = new int[tetCount]; vtkCellArray* outputCellArray = vtkCellArray::New(); int outputCellType = VTK_TETRA; if (nodesPerTet == 10) { outputCellType = VTK_QUADRATIC_TETRA; } vtkIdTypeArray* cellBoundaryDataArray = vtkIdTypeArray::New(); if (boundaryMarkers) { cellBoundaryDataArray->SetName(this->BoundaryDataArrayName); cellBoundaryDataArray->SetNumberOfComponents(1); cellBoundaryDataArray->SetNumberOfTuples(tetCount); } vtkIdType pointId, maxBoundaryId; for (i=0; iTokenize(line,tokens,delimiter); index = atoi(tokens[0].c_str()); outputCellArray->InsertNextCell(nodesPerTet); maxBoundaryId = 0; for (j=0; jInsertCellPoint(pointId-firstIndex); if (boundaryMarkers) { boundaryId = boundaryDataArray->GetValue(pointId-firstIndex); if (j>0 && boundaryId > maxBoundaryId) { maxBoundaryId = boundaryId; } } } if (boundaryMarkers) { cellBoundaryDataArray->SetValue(i,maxBoundaryId); } outputCellTypes[i] = outputCellType; for (j=0; jSetValue(i,value); } } for (j=0; jGetCellData()->AddArray(cellAttributeArrays[j]); cellAttributeArrays[j]->Delete(); } delete[] cellAttributeArrays; output->SetCells(outputCellTypes,outputCellArray); if (boundaryMarkers) { output->GetCellData()->AddArray(cellBoundaryDataArray); } cellBoundaryDataArray->Delete(); boundaryDataArray->Delete(); outputCellArray->Delete(); delete[] outputCellTypes; return 1; } void vtkvmtkTetGenReader::PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/IO/vtkvmtkDolfinWriter.cxx0000664000175000017500000002444311757446472017716 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDolfinWriter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 #include #include #include "vtkvmtkDolfinWriter.h" #include "vtkUnstructuredGrid.h" #include "vtkCellType.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkIdTypeArray.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkDolfinWriter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkDolfinWriter); vtkvmtkDolfinWriter::vtkvmtkDolfinWriter() { this->BoundaryDataArrayName = NULL; // TODO: Rename to CellEntityIdsArrayName this->BoundaryDataIdOffset = 0; this->StoreCellMarkers = 0; } vtkvmtkDolfinWriter::~vtkvmtkDolfinWriter() { if (this->BoundaryDataArrayName) { delete[] this->BoundaryDataArrayName; this->BoundaryDataArrayName = NULL; } } void vtkvmtkDolfinWriter::WriteData() { // Open output file if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return; } ofstream out (this->FileName); if (!out.good()) { vtkErrorMacro(<<"Could not open file for writing."); return; } // Get and prepare input mesh vtkUnstructuredGrid *input = vtkUnstructuredGrid::SafeDownCast(this->GetInput()); input->BuildLinks(); const int numberOfPoints = input->GetNumberOfPoints(); const int numberOfCells = input->GetNumberOfCells(); // Create copy of cell entity ids array vtkIdTypeArray* cellEntityIds = NULL; if (this->BoundaryDataArrayName) { vtkDataArray * array = input->GetCellData()->GetArray(this->BoundaryDataArrayName); if (array) { cellEntityIds = vtkIdTypeArray::New(); cellEntityIds->DeepCopy(array); } else { vtkErrorMacro(<<"Array with specified BoundaryDataArrayName does not exist"); } } // Build an array with the vtk cell ids of all tetrahedras vtkIdTypeArray* tetraCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TETRA, tetraCellIdArray); const int numberOfTetras = tetraCellIdArray->GetNumberOfTuples(); const int numberOfTetraPoints = 4; // Points in a tetrahedron(!) // Build the inverted array with mapping from contiguous tetrahedron numbering to vtk cell numbering vtkIdList* volumeCellIdMap = vtkIdList::New(); volumeCellIdMap->SetNumberOfIds(numberOfCells); for (int i=0; iGetValue(i); volumeCellIdMap->SetId(tetraCellId,i); } // Write out dolfin mesh header out << "" << endl; out << "" << endl; out << " " << endl; // Write out all vertices out << " " << endl; for (int i=0; iGetPoint(i,point); out << " " <" << endl; // Write out all cells out << " " << endl; for (int i=0; iGetValue(i); vtkIdList* cellPointIds = input->GetCell(tetraCellId)->GetPointIds(); // Sort point ids in cell, the way dolfin likes it (this works only for simplices!) vtkIdType dolfinCellPointIds[numberOfTetraPoints]; for (int k=0; kGetId(k); } std::sort(dolfinCellPointIds, dolfinCellPointIds+numberOfTetraPoints); // Write out vertex ids for a single tetrahedron out << " " << endl; } out << " " << endl; // Build and write subdomains if available if (cellEntityIds) { vtkIdTypeArray* triangleCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TRIANGLE,triangleCellIdArray); const int numberOfTriangles = triangleCellIdArray->GetNumberOfTuples(); vtkIdList* triangleToTetrahedron = vtkIdList::New(); triangleToTetrahedron->SetNumberOfIds(numberOfTriangles); vtkIdList* triangleToLocalFacetId = vtkIdList::New(); triangleToLocalFacetId->SetNumberOfIds(numberOfTriangles); int interiorFacetsFound = 0; int exteriorFacetsFound = 0; for (int i=0; iGetValue(i); vtkIdList* faceCellPoints = vtkIdList::New(); input->GetCellPoints(triangleCellId,faceCellPoints); vtkIdList* cellIds = vtkIdList::New(); input->GetCellNeighbors(triangleCellId,faceCellPoints,cellIds); if (cellIds->GetNumberOfIds() != 1) { interiorFacetsFound++; } else { exteriorFacetsFound++; } // Get neighbor cell to facet, pick the one with smallest index if two (interior facet) vtkIdType cellId = cellIds->GetId(0); if (cellIds->GetNumberOfIds() == 2 && cellIds->GetId(1) < cellId) { cellId = cellIds->GetId(1); } vtkCell* cell = input->GetCell(cellId); int cellType = cell->GetCellType(); vtkIdList* cellPointIds = cell->GetPointIds(); // Check that all neighbor cells are tets if (cellType != VTK_TETRA) { vtkErrorMacro(<<"Volume cell adjacent to triangle is not tetrahedron (volume cell id: "<Delete(); cellIds->Delete(); continue; } // Sort point ids in cell, the way dolfin likes it (this works only for simplices!) vtkIdType dolfinCellPointIds[numberOfTetraPoints]; for (int k=0; kGetId(k); } std::sort(dolfinCellPointIds, dolfinCellPointIds+numberOfTetraPoints); // Find local facet id in dolfin numbering, opposite of point in cell that is not part of facet vtkIdType dolfinFaceId = -1; for (int k=0; kGetId(j)) { found = true; break; } } if (!found) { dolfinFaceId = k; break; } } // Store tetrahedron number for vtk triangle i triangleToTetrahedron->SetId(i, volumeCellIdMap->GetId(cellId)); // Store local dolfin facet number for vtk triangle i triangleToLocalFacetId->SetId(i, dolfinFaceId); // Cleanup faceCellPoints->Delete(); cellIds->Delete(); } // Start subdomains section in file if (numberOfTriangles || this->StoreCellMarkers) { out << " " << endl; } // Write facet subdomains if (numberOfTriangles) { out << " " << endl; for (int i=0; iGetValue(i); const vtkIdType tetrahedronCellId = triangleToTetrahedron->GetId(i); const vtkIdType value = cellEntityIds->GetValue(triangleCellId) + this->BoundaryDataIdOffset; const vtkIdType localEntity = triangleToLocalFacetId->GetId(i); out << " " << endl; } out << " " << endl; } // Write cell subdomains if (this->StoreCellMarkers) { out << " " << endl; for (int i=0; iGetValue(i); const vtkIdType value = cellEntityIds->GetValue(cellId); out << " " << endl; } out << " " << endl; } // End subdomains section in file if (numberOfTriangles || this->StoreCellMarkers) { out << " " << endl; } if (interiorFacetsFound) { vtkWarningMacro("Found boundary cells not on boundary!"); } triangleCellIdArray->Delete(); triangleToTetrahedron->Delete(); triangleToLocalFacetId->Delete(); } out << " " << endl; out << "" << endl; tetraCellIdArray->Delete(); volumeCellIdMap->Delete(); if (cellEntityIds) { cellEntityIds->Delete(); } } void vtkvmtkDolfinWriter::PrintSelf(ostream& os, vtkIndent indent) { vtkUnstructuredGridWriter::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/IO/CMakeLists.txt0000664000175000017500000000736611757446472015700 0ustar lucalucaSET (VTK_VMTK_IO_SRCS vtkvmtkDICOMImageReader.cxx vtkvmtkDolfinWriter.cxx vtkvmtkFDNEUTReader.cxx vtkvmtkFDNEUTWriter.cxx vtkvmtkFluentWriter.cxx vtkvmtkTetGenReader.cxx vtkvmtkTetGenWriter.cxx vtkvmtkXdaReader.cxx vtkvmtkXdaWriter.cxx ) IF (EXISTS ${VTK_DIR}/bin) #this is a hack to make DICOMParser be included correctly - VTK source INCLUDE_DIRECTORIES(BEFORE ${VTK_SOURCE_DIR}/Utilities/DICOMParser) ELSE (EXISTS ${VTK_DIR}/bin) INCLUDE_DIRECTORIES(BEFORE ${VTK_INCLUDE_DIRS}) ENDIF (EXISTS ${VTK_DIR}/bin) ADD_LIBRARY (vtkvmtkIO ${VTK_VMTK_IO_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkIO PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkIO PROPERTIES LINKER_LANGUAGE CXX) TARGET_LINK_LIBRARIES(vtkvmtkIO vtkCommon vtkImaging vtkIO vtkDICOMParser) INSTALL(TARGETS vtkvmtkIO LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_IO_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/IO/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkIO) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkIOPython VTK_VMTK_IO_PYTHON_SRCS "${VTK_VMTK_IO_SRCS}") ADD_LIBRARY(vtkvmtkIOPythonD ${VTK_VMTK_IO_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkIOPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkIOPython MODULE vtkvmtkIOPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkIOPythonD vtkvmtkIO vtkCommon vtkCommonPythonD vtkImaging vtkImagingPythonD vtkIO vtkIOPythonD) TARGET_LINK_LIBRARIES(vtkvmtkIOPython vtkvmtkIOPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkIOPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkIOPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkIOPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkIOTCL VTK_VMTK_IO_TCL_SRCS "${VTK_VMTK_IO_SRCS}" "") ADD_LIBRARY(vtkvmtkIOTCL ${VTK_VMTK_IO_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkIOTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkIOTCL vtkvmtkIO vtkCommon vtkCommonTCL vtkImaging vtkImagingTCL vtkIO vtkIOTCL) INSTALL(TARGETS vtkvmtkIOTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkIOTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/IO/vtkvmtkXdaWriter.h0000664000175000017500000000421311757446472016635 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkXdaWriter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - // .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(); vtkTypeRevisionMacro(vtkvmtkXdaWriter,vtkUnstructuredGridWriter); void PrintSelf(ostream& os, vtkIndent indent); vtkSetStringMacro(BoundaryDataArrayName); vtkGetStringMacro(BoundaryDataArrayName); protected: vtkvmtkXdaWriter(); ~vtkvmtkXdaWriter(); void WriteData(); 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 vmtk-1.0.1/vtkVmtk/IO/vtkvmtkXdaReader.h0000664000175000017500000000420611757446472016565 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkXdaReader.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkXdaReader - // .SECTION Description // vtkvmtkXdaReader reads libmesh Xda files // .SECTION See Also #ifndef __vtkvmtkXdaReader_h #define __vtkvmtkXdaReader_h #include "vtkvmtkWin32Header.h" #include "vtkUnstructuredGridReader.h" class vtkCell; class vtkIdList; class VTK_VMTK_IO_EXPORT vtkvmtkXdaReader : public vtkUnstructuredGridReader { public: static vtkvmtkXdaReader *New(); vtkTypeRevisionMacro(vtkvmtkXdaReader,vtkUnstructuredGridReader); void PrintSelf(ostream& os, vtkIndent indent); vtkSetStringMacro(BoundaryDataArrayName); vtkGetStringMacro(BoundaryDataArrayName); protected: vtkvmtkXdaReader(); ~vtkvmtkXdaReader(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); static void GetLibmeshConnectivity(int cellType, vtkIdList* libmeshConnectivity); char* BoundaryDataArrayName; private: vtkvmtkXdaReader(const vtkvmtkXdaReader&); // Not implemented. void operator=(const vtkvmtkXdaReader&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/IO/vtkvmtkXdaWriter.cxx0000664000175000017500000004304611757446472017217 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkXdaWriter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 #include "vtkvmtkXdaWriter.h" #include "vtkUnstructuredGrid.h" #include "vtkCellType.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkIdTypeArray.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkXdaWriter, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkXdaWriter); vtkvmtkXdaWriter::vtkvmtkXdaWriter() { this->BoundaryDataArrayName = NULL; } vtkvmtkXdaWriter::~vtkvmtkXdaWriter() { if (this->BoundaryDataArrayName) { delete[] this->BoundaryDataArrayName; this->BoundaryDataArrayName = NULL; } } void vtkvmtkXdaWriter::WriteData() { vtkUnstructuredGrid *input= vtkUnstructuredGrid::SafeDownCast(this->GetInput()); if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return; } ofstream out (this->FileName); if (!out.good()) { vtkErrorMacro(<<"Could not open file for writing."); return; } input->BuildLinks(); int numberOfPoints = input->GetNumberOfPoints(); int numberOfCells = input->GetNumberOfCells(); vtkDataArray* boundaryDataArray = NULL; if (this->BoundaryDataArrayName) { boundaryDataArray = input->GetCellData()->GetArray(this->BoundaryDataArrayName); if (!boundaryDataArray) { vtkErrorMacro(<<"BoundaryDataArray with name specified does not exist"); } } int totalWeight = 0; enum { tetraType = 0, hexahedronType, wedgeType, pyramidType, quadraticTetraType, quadraticHexahedronType, quadraticWedgeType, biquadraticWedgeType, quadraticPyramidType }; const int numberOfVolumeCellTypes = 9; enum { tet4LibmeshType = 8, tet10LibmeshType, hex8LibmeshType, hex20LibmeshType, hex27LibmeshType, prism6LibmeshType, prism15LibmeshType, prism18LibmeshType, pyramid5LibmeshType }; int elementTypeLibmeshMap[numberOfVolumeCellTypes]; elementTypeLibmeshMap[tetraType] = tet4LibmeshType; elementTypeLibmeshMap[hexahedronType] = hex8LibmeshType; elementTypeLibmeshMap[wedgeType] = prism6LibmeshType; elementTypeLibmeshMap[pyramidType] = pyramid5LibmeshType; elementTypeLibmeshMap[quadraticTetraType] = tet10LibmeshType; elementTypeLibmeshMap[quadraticHexahedronType] = hex20LibmeshType; elementTypeLibmeshMap[quadraticWedgeType] = prism15LibmeshType; elementTypeLibmeshMap[biquadraticWedgeType] = prism18LibmeshType; elementTypeLibmeshMap[quadraticPyramidType] = -1; int numberOfElementsInBlock[numberOfVolumeCellTypes]; int i; for (i=0; i 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) blockVtkCellTypes[biquadraticWedgeType] = VTK_BIQUADRATIC_QUADRATIC_WEDGE; #else blockVtkCellTypes[biquadraticWedgeType] = VTK_EMPTY_CELL; #endif blockVtkCellTypes[quadraticPyramidType] = VTK_QUADRATIC_PYRAMID; int numberOfVolumeCells = 0; for (i=0; iGetCellType(i); switch (cellType) { case VTK_TETRA: ++numberOfElementsInBlock[tetraType]; break; case VTK_HEXAHEDRON: ++numberOfElementsInBlock[hexahedronType]; break; case VTK_WEDGE: ++numberOfElementsInBlock[wedgeType]; break; case VTK_PYRAMID: ++numberOfElementsInBlock[pyramidType]; break; case VTK_QUADRATIC_TETRA: ++numberOfElementsInBlock[quadraticTetraType]; break; case VTK_QUADRATIC_HEXAHEDRON: ++numberOfElementsInBlock[quadraticHexahedronType]; break; case VTK_QUADRATIC_WEDGE: ++numberOfElementsInBlock[quadraticWedgeType]; break; #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: ++numberOfElementsInBlock[biquadraticWedgeType]; break; #else vtkWarningMacro(<<"Biquadratic quadratic wedge not supported by the installed VTK version. Skipping element."); continue; #endif case VTK_QUADRATIC_PYRAMID: vtkWarningMacro(<<"Quadratic pyramid not currently supported in libmesh. Skipping element."); continue; default: continue; } ++numberOfVolumeCells; totalWeight += input->GetCell(i)->GetNumberOfPoints(); } int numberOfElementBlocks = 0; for (i=0; i 0) { ++numberOfElementBlocks; } } int numberOfBoundaryConditions = 0; if (boundaryDataArray) { for (i=0; iGetCellType(i); switch (cellType) { case VTK_TRIANGLE: case VTK_QUAD: case VTK_QUADRATIC_TRIANGLE: case VTK_QUADRATIC_QUAD: numberOfBoundaryConditions++; break; default: continue; } } } out << "DEAL 003:003" << endl; // out << "LIBM 0" << endl; out << numberOfVolumeCells << "\t# Num. Elements" << endl; out << numberOfPoints << "\t# Num. Nodes" << endl; out << totalWeight << "\t# Sum of Element Weights" << endl; out << numberOfBoundaryConditions << "\t# Num. Boundary Conds." << endl; int stringSize = 65536; out << stringSize << "\t# String Size (ignore)" << endl; // out << numberOfElementBlocks << "\t# Num. Element Blocks." << endl; out << numberOfElementBlocks << "\t# Num. Element Types." << endl; for (i=0; i 0) { out << elementTypeLibmeshMap[i] << " "; } } out << "\t# Element types in each block." << endl; for (i=0; i 0) { out << numberOfElementsInBlock[i] << " "; } } out << "\t# Num. of elements in each block at each refinement level." << endl; out << "Id String" << endl; out << "Title String" << endl; vtkIdList* volumeCellIdMap = vtkIdList::New(); volumeCellIdMap->SetNumberOfIds(numberOfCells); int volumeCellCounter = 0; for (i=0; iGetIdsOfCellsOfType(blockVtkCellTypes[i], typeCellIds); vtkIdList* libmeshConnectivity = vtkIdList::New(); this->GetLibmeshConnectivity(blockVtkCellTypes[i],libmeshConnectivity); int numberOfTypeCells = typeCellIds->GetNumberOfTuples(); int j; for (j=0; jGetValue(j); vtkIdList* cellPoints = vtkIdList::New(); input->GetCellPoints(id,cellPoints); //TODO: get individual connectivity, reversed if needed by positive Jacobian in libMesh int numberOfCellPoints = libmeshConnectivity->GetNumberOfIds(); for (int k=0; kGetId(libmeshConnectivity->GetId(k)) << " "; } // out << j << " " << "-1"; // TODO: change -1 into parent for AMR datasets out << endl; volumeCellIdMap->SetId(id,volumeCellCounter); volumeCellCounter++; cellPoints->Delete(); } typeCellIds->Delete(); libmeshConnectivity->Delete(); } double point[3]; for (i=0; iGetPoint(i,point); out << point[0] << " " << point[1] << " " << point[2] << endl; } if (boundaryDataArray) { for (i=0; iGetCellType(i); switch (faceCellType) { case VTK_TRIANGLE: case VTK_QUAD: case VTK_QUADRATIC_TRIANGLE: case VTK_QUADRATIC_QUAD: break; default: continue; } vtkIdList* faceCellPoints = vtkIdList::New(); input->GetCellPoints(i,faceCellPoints); vtkIdList* cellIds = vtkIdList::New(); input->GetCellNeighbors(i,faceCellPoints,cellIds); if (cellIds->GetNumberOfIds() != 1) { vtkWarningMacro("Boundary cell not on boundary!"); } vtkIdType cellId = cellIds->GetId(0); vtkCell* cell = input->GetCell(cellId); int cellType = cell->GetCellType(); int numberOfFaces = cell->GetNumberOfFaces(); vtkIdType faceId = -1; int j; for (j=0; jGetFace(j); vtkIdList* matchingPointIds = vtkIdList::New(); matchingPointIds->DeepCopy(face->GetPointIds()); matchingPointIds->IntersectWith(*faceCellPoints); int numberOfNonMatching = face->GetNumberOfPoints() - matchingPointIds->GetNumberOfIds(); matchingPointIds->Delete(); if (numberOfNonMatching==0) { faceId = j; break; } } vtkIdList* libmeshFaceOrder = vtkIdList::New(); this->GetLibmeshFaceOrder(cellType,libmeshFaceOrder); vtkIdType libmeshFaceId = libmeshFaceOrder->GetId(faceId); libmeshFaceOrder->Delete(); short int boundaryValue = static_cast(boundaryDataArray->GetComponent(i,0)); out << volumeCellIdMap->GetId(cellId) << " " << libmeshFaceId << " " << boundaryValue << endl; faceCellPoints->Delete(); } } volumeCellIdMap->Delete(); } void vtkvmtkXdaWriter::GetLibmeshConnectivity(int cellType, vtkIdList* libmeshConnectivity) { libmeshConnectivity->Initialize(); switch(cellType) { case VTK_TETRA: libmeshConnectivity->SetNumberOfIds(4); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,1); libmeshConnectivity->SetId(2,2); libmeshConnectivity->SetId(3,3); break; case VTK_HEXAHEDRON: libmeshConnectivity->SetNumberOfIds(8); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,1); libmeshConnectivity->SetId(2,2); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,4); libmeshConnectivity->SetId(5,5); libmeshConnectivity->SetId(6,6); libmeshConnectivity->SetId(7,7); break; case VTK_WEDGE: libmeshConnectivity->SetNumberOfIds(6); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,2); libmeshConnectivity->SetId(2,1); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,5); libmeshConnectivity->SetId(5,4); break; case VTK_PYRAMID: libmeshConnectivity->SetNumberOfIds(5); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,1); libmeshConnectivity->SetId(2,2); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,4); break; case VTK_QUADRATIC_TETRA: libmeshConnectivity->SetNumberOfIds(10); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,1); libmeshConnectivity->SetId(2,2); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,4); libmeshConnectivity->SetId(5,5); libmeshConnectivity->SetId(6,6); libmeshConnectivity->SetId(7,7); libmeshConnectivity->SetId(8,8); libmeshConnectivity->SetId(9,9); break; case VTK_QUADRATIC_HEXAHEDRON: libmeshConnectivity->SetNumberOfIds(20); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,1); libmeshConnectivity->SetId(2,2); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,4); libmeshConnectivity->SetId(5,5); libmeshConnectivity->SetId(6,6); libmeshConnectivity->SetId(7,7); libmeshConnectivity->SetId(8,8); libmeshConnectivity->SetId(9,9); libmeshConnectivity->SetId(10,10); libmeshConnectivity->SetId(11,11); libmeshConnectivity->SetId(12,16); libmeshConnectivity->SetId(13,17); libmeshConnectivity->SetId(14,18); libmeshConnectivity->SetId(15,19); libmeshConnectivity->SetId(16,12); libmeshConnectivity->SetId(17,13); libmeshConnectivity->SetId(18,14); libmeshConnectivity->SetId(19,15); break; case VTK_QUADRATIC_WEDGE: libmeshConnectivity->SetNumberOfIds(15); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,2); libmeshConnectivity->SetId(2,1); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,5); libmeshConnectivity->SetId(5,4); libmeshConnectivity->SetId(6,8); libmeshConnectivity->SetId(7,7); libmeshConnectivity->SetId(8,6); libmeshConnectivity->SetId(9,12); libmeshConnectivity->SetId(10,14); libmeshConnectivity->SetId(11,13); libmeshConnectivity->SetId(12,11); libmeshConnectivity->SetId(13,10); libmeshConnectivity->SetId(14,9); break; #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: libmeshConnectivity->SetNumberOfIds(18); libmeshConnectivity->SetId(0,0); libmeshConnectivity->SetId(1,2); libmeshConnectivity->SetId(2,1); libmeshConnectivity->SetId(3,3); libmeshConnectivity->SetId(4,5); libmeshConnectivity->SetId(5,4); libmeshConnectivity->SetId(6,8); libmeshConnectivity->SetId(7,7); libmeshConnectivity->SetId(8,6); libmeshConnectivity->SetId(9,12); libmeshConnectivity->SetId(10,14); libmeshConnectivity->SetId(11,13); libmeshConnectivity->SetId(12,11); libmeshConnectivity->SetId(13,10); libmeshConnectivity->SetId(14,9); libmeshConnectivity->SetId(15,17); libmeshConnectivity->SetId(16,16); libmeshConnectivity->SetId(17,15); break; #endif default: cerr<<"Element type not currently supported in libmesh. Skipping element."<Initialize(); switch(cellType) { case VTK_TETRA: libmeshFaceOrder->SetNumberOfIds(4); libmeshFaceOrder->SetId(0,1); libmeshFaceOrder->SetId(1,2); libmeshFaceOrder->SetId(2,3); libmeshFaceOrder->SetId(3,0); break; case VTK_HEXAHEDRON: libmeshFaceOrder->SetNumberOfIds(6); libmeshFaceOrder->SetId(0,4); libmeshFaceOrder->SetId(1,2); libmeshFaceOrder->SetId(2,1); libmeshFaceOrder->SetId(3,3); libmeshFaceOrder->SetId(4,0); libmeshFaceOrder->SetId(5,5); break; case VTK_WEDGE: libmeshFaceOrder->SetNumberOfIds(5); libmeshFaceOrder->SetId(0,0); libmeshFaceOrder->SetId(1,4); libmeshFaceOrder->SetId(2,3); libmeshFaceOrder->SetId(3,2); libmeshFaceOrder->SetId(4,1); break; case VTK_PYRAMID: libmeshFaceOrder->SetNumberOfIds(5); libmeshFaceOrder->SetId(0,4); libmeshFaceOrder->SetId(1,0); libmeshFaceOrder->SetId(2,1); libmeshFaceOrder->SetId(3,2); libmeshFaceOrder->SetId(4,3); break; case VTK_QUADRATIC_TETRA: libmeshFaceOrder->SetNumberOfIds(4); libmeshFaceOrder->SetId(0,1); libmeshFaceOrder->SetId(1,2); libmeshFaceOrder->SetId(2,3); libmeshFaceOrder->SetId(3,0); break; case VTK_QUADRATIC_HEXAHEDRON: libmeshFaceOrder->SetNumberOfIds(6); libmeshFaceOrder->SetId(0,4); libmeshFaceOrder->SetId(1,2); libmeshFaceOrder->SetId(2,1); libmeshFaceOrder->SetId(3,3); libmeshFaceOrder->SetId(4,0); libmeshFaceOrder->SetId(5,5); break; case VTK_QUADRATIC_WEDGE: #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: #endif libmeshFaceOrder->SetNumberOfIds(5); libmeshFaceOrder->SetId(0,0); libmeshFaceOrder->SetId(1,4); libmeshFaceOrder->SetId(2,3); libmeshFaceOrder->SetId(3,2); libmeshFaceOrder->SetId(4,1); break; default: cerr<<"Element type not currently supported in libmesh. Skipping element."< #include #include "DICOMParser.h" #include "DICOMAppHelper.h" vtkCxxRevisionMacro(vtkvmtkDICOMImageReader,"$Revision: 1.8 $"); vtkStandardNewMacro(vtkvmtkDICOMImageReader); vtkvmtkDICOMImageReader::vtkvmtkDICOMImageReader() { this->AutoOrientImage = 1; this->OrientationStringX = NULL; this->OrientationStringY = NULL; this->OrientationStringZ = NULL; } vtkvmtkDICOMImageReader::~vtkvmtkDICOMImageReader() { if (this->OrientationStringX) { delete[] this->OrientationStringX; } if (this->OrientationStringY) { delete[] this->OrientationStringY; } if (this->OrientationStringZ) { delete[] this->OrientationStringZ; } } void vtkvmtkDICOMImageReader::PrintSelf(ostream& os, vtkIndent indent) { vtkDICOMImageReader::PrintSelf(os,indent); } void vtkvmtkDICOMImageReader::ExecuteInformation() { Superclass::ExecuteInformation(); this->ComputeOutputVoxelSpacing(); } void vtkvmtkDICOMImageReader::ComputeOutputVoxelSpacing() { double voxelSpacing[3] = {0.0, 0.0, 0.0}; vtkstd::vector* dicomFileNames = (vtkstd::vector*)this->DICOMFileNames; if (this->FileName) { vtkDebugMacro( << "Single file : " << this->FileName); this->Parser->ClearAllDICOMTagCallbacks(); this->Parser->OpenFile(this->FileName); this->AppHelper->Clear(); this->AppHelper->RegisterCallbacks(this->Parser); this->Parser->ReadHeader(); float* pixelSpacing; pixelSpacing = this->AppHelper->GetPixelSpacing(); voxelSpacing[0] = pixelSpacing[0]; voxelSpacing[1] = pixelSpacing[1]; voxelSpacing[2] = 0.0; } else if (dicomFileNames->size() > 0) { vtkDebugMacro( << "Multiple files (" << static_cast(dicomFileNames->size()) << ")"); this->Parser->ClearAllDICOMTagCallbacks(); this->AppHelper->Clear(); this->AppHelper->RegisterCallbacks(this->Parser); vtkstd::vector::iterator fiter; double imagePositions[3][3]; int count; for (fiter = dicomFileNames->begin(), count=0; fiter != dicomFileNames->end(), count<3; fiter++, count++) { vtkDebugMacro( << "File : " << (*fiter).c_str()); this->Parser->OpenFile((char*)(*fiter).c_str()); this->Parser->ReadHeader(); float *pixelSpacing; pixelSpacing = this->AppHelper->GetPixelSpacing(); voxelSpacing[0] = pixelSpacing[0]; voxelSpacing[1] = pixelSpacing[1]; voxelSpacing[2] = 0.0; float *imagePositionPatient; imagePositionPatient = this->AppHelper->GetImagePositionPatient(); imagePositions[count][0] = imagePositionPatient[0]; imagePositions[count][1] = imagePositionPatient[1]; imagePositions[count][2] = imagePositionPatient[2]; } double voxelThickness = 0.0; int i; for (i=0; iDataSpacing[0] = voxelSpacing[0]; this->DataSpacing[1] = voxelSpacing[1]; this->DataSpacing[2] = voxelSpacing[2]; } void vtkvmtkDICOMImageReader::ExecuteData(vtkDataObject *output) { Superclass::ExecuteData(output); if (this->AutoOrientImage) { this->OrientImageData(); } } void vtkvmtkDICOMImageReader::GenerateOrientationString(float direction[3], char* orientationString) { char RL = direction[0]<0 ? 'R' : 'L'; char AP = direction[1]<0 ? 'A' : 'P'; char IS = direction[2]<0 ? 'I' : 'S'; float absDirection[3]; absDirection[0] = fabs(direction[0]); absDirection[1] = fabs(direction[1]); absDirection[2] = fabs(direction[2]); char* orientationStringPointer = orientationString; *orientationStringPointer = '\0'; for (int i=0; i<3; i++) { if ( absDirection[0] > 1E-4 && absDirection[0] > absDirection[1] && absDirection[0] > absDirection[2] ) { absDirection[0] = 0.0; *orientationStringPointer++=RL; } else if ( absDirection[1] > 1E-4 && absDirection[1] > absDirection[0] && absDirection[1] > absDirection[2] ) { absDirection[1] = 0.0; *orientationStringPointer++=AP; } else if ( absDirection[2] > 1E-4 && absDirection[2] > absDirection[0] && absDirection[2] > absDirection[1] ) { absDirection[2] = 0.0; *orientationStringPointer++=IS; } else { break; } *orientationStringPointer='\0'; } } void vtkvmtkDICOMImageReader::OrientImageData() { float* imageOrientation = this->AppHelper->GetImageOrientationPatient(); float directionX[3],directionY[3], directionZ[3]; directionX[0] = imageOrientation[0]; directionX[1] = imageOrientation[1]; directionX[2] = imageOrientation[2]; // negative because the reader already flips Y directionY[0] = -imageOrientation[3]; directionY[1] = -imageOrientation[4]; directionY[2] = -imageOrientation[5]; vtkMath::Cross(directionX,directionY,directionZ); vtkMath::Normalize(directionZ); this->OrientationStringX = new char[4]; this->OrientationStringY = new char[4]; this->OrientationStringZ = new char[4]; this->GenerateOrientationString(directionX,this->OrientationStringX); this->GenerateOrientationString(directionY,this->OrientationStringY); this->GenerateOrientationString(directionZ,this->OrientationStringZ); bool flipX = false; if (this->OrientationStringX[0] == 'L' || this->OrientationStringX[0] == 'P' || this->OrientationStringX[0] == 'I') { flipX = true; } bool flipY = false; if (this->OrientationStringY[0] == 'L' || this->OrientationStringY[0] == 'P' || this->OrientationStringY[0] == 'I') { flipY = true; } bool flipZ = false; if (this->OrientationStringZ[0] == 'L' || this->OrientationStringZ[0] == 'P' || this->OrientationStringZ[0] == 'I') { flipZ = true; } cout << "VTK Orientation: " << this->OrientationStringX << " " << this->OrientationStringY << " " << this->OrientationStringZ << " " << endl; cout << "Flipping: " << flipX << " " << flipY << " " << flipZ << endl; vtkImageData* output = this->GetOutput(); vtkImageData* temp = vtkImageData::New(); temp->DeepCopy(output); vtkImageData* temp0; vtkImageFlip* flipFilterX = NULL; if (flipX) { flipFilterX = vtkImageFlip::New(); flipFilterX->SetInput(temp); flipFilterX->SetFilteredAxis(0); flipFilterX->Update(); temp0 = flipFilterX->GetOutput(); } else { temp0 = temp; } vtkImageData* temp1; vtkImageFlip* flipFilterY = NULL; if (flipY) { flipFilterY = vtkImageFlip::New(); flipFilterY->SetInput(temp0); flipFilterY->SetFilteredAxis(1); flipFilterY->Update(); temp1 = flipFilterY->GetOutput(); } else { temp1 = temp0; } vtkImageData* temp2; vtkImageFlip* flipFilterZ = NULL; if (flipZ) { flipFilterZ = vtkImageFlip::New(); flipFilterZ->SetInput(temp1); flipFilterZ->SetFilteredAxis(2); flipFilterZ->Update(); temp2 = flipFilterZ->GetOutput(); } else { temp2 = temp1; } output->DeepCopy(temp2); if (flipX) { flipFilterX->Delete(); } if (flipY) { flipFilterY->Delete(); } if (flipZ) { flipFilterZ->Delete(); } temp->Delete(); } vmtk-1.0.1/vtkVmtk/IO/vtkvmtkFDNEUTReader.cxx0000664000175000017500000004014411757446472017412 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFDNEUTReader.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.8 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkFDNEUTReader.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkObjectFactory.h" #include "vtkPoints.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkUnsignedCharArray.h" #include "vtkUnstructuredGrid.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkFDNEUTReader, "$Revision: 1.8 $"); vtkStandardNewMacro(vtkvmtkFDNEUTReader); vtkvmtkFDNEUTReader::vtkvmtkFDNEUTReader() { this->GhostNodes = 1; this->VolumeElementsOnly = 0; this->SingleCellDataEntityArrayName = NULL; } vtkvmtkFDNEUTReader::~vtkvmtkFDNEUTReader() { if (this->SingleCellDataEntityArrayName) { delete[] this->SingleCellDataEntityArrayName; this->SingleCellDataEntityArrayName = NULL; } } int vtkvmtkFDNEUTReader::RequestData( vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *outInfo = outputVector->GetInformationObject(0); vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) { return 1; } if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return 1; } FILE* FDNEUTFile; FDNEUTFile = fopen(this->FileName,"r"); if (!FDNEUTFile) { vtkErrorMacro(<<"Could not open file."); return 1; } char buffer[1024]; do { fscanf(FDNEUTFile, "%s", buffer); while (fgetc(FDNEUTFile) != '\n'); } while (strncmp(buffer,"NODAL",5)!=0); // while (fgetc(FDNEUTFile) != '\n'); int pointId; float point[3], doublePoint[3]; vtkPoints* points = vtkPoints::New(); while(fscanf(FDNEUTFile, "%d", &pointId)) { fscanf(FDNEUTFile, "%f", &point[0]); fscanf(FDNEUTFile, "%f", &point[1]); fscanf(FDNEUTFile, "%f", &point[2]); while (fgetc(FDNEUTFile) != '\n'); doublePoint[0] = point[0]; doublePoint[1] = point[1]; doublePoint[2] = point[2]; points->InsertPoint(pointId-1,doublePoint); } int cellId, i; int nodesPerElement, geometry, fdneutType; vtkCellArray* gridCellArray = vtkCellArray::New(); int entityCounter = 0; vtkUnsignedCharArray* singleEntityArray; singleEntityArray = vtkUnsignedCharArray::New(); singleEntityArray->SetName(this->SingleCellDataEntityArrayName); output->GetCellData()->AddArray(singleEntityArray); vtkIntArray* typesArray = vtkIntArray::New(); while (fscanf(FDNEUTFile, "%s", buffer)!=EOF) { while (strncmp(buffer,"NODES:",6)!=0) fscanf(FDNEUTFile, "%s", buffer); fscanf(FDNEUTFile, "%d", &nodesPerElement); while (strncmp(buffer,"GEOMETRY:",9)!=0) fscanf(FDNEUTFile, "%s", buffer); fscanf(FDNEUTFile, "%d", &geometry); while (strncmp(buffer,"TYPE:",5)!=0) fscanf(FDNEUTFile, "%s", buffer); fscanf(FDNEUTFile, "%d", &fdneutType); while (fgetc(FDNEUTFile) != '\n'); fscanf(FDNEUTFile, "%s", buffer); fscanf(FDNEUTFile, "%s", buffer); char currentEntityName[256]; fscanf(FDNEUTFile, "%s", currentEntityName); while (fgetc(FDNEUTFile) != '\n'); int type = -1; int pointBuffer; vtkIdType numberOfCellPoints = 0; #if 0 vtkUnsignedCharArray* entityArray = NULL; entityArray = vtkUnsignedCharArray::New(); entityArray->SetName(currentEntityName); output->GetCellData()->AddArray(entityArray); #endif while(fscanf(FDNEUTFile, "%d", &cellId)>0) { int* cellPoints = NULL; bool invalid = false; switch (geometry) { case QUADRILATERAL: if (this->VolumeElementsOnly) { continue; } if (nodesPerElement==4) { type = VTK_QUAD; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 4; cellPoints = new int[numberOfCellPoints]; for (i=0; iGhostNodes ? nodesPerElement : 8; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[4]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[5]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[6]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); fscanf(FDNEUTFile, "%d", &cellPoints[7]); if (nodesPerElement==9) { if (this->GhostNodes) { fscanf(FDNEUTFile, "%d",&cellPoints[8]); } else { fscanf(FDNEUTFile, "%d",&pointBuffer); } } } break; case TRIANGLE: if (this->VolumeElementsOnly) { continue; } if (nodesPerElement==3) { type = VTK_TRIANGLE; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 3; cellPoints = new int[numberOfCellPoints]; for (i=0; iGhostNodes ? nodesPerElement : 6; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[4]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[5]); if (nodesPerElement==7) { if (this->GhostNodes) { fscanf(FDNEUTFile, "%d",&cellPoints[6]); } else { fscanf(FDNEUTFile, "%d",&pointBuffer); } } } break; case BRICK: if (nodesPerElement==8) { type = VTK_HEXAHEDRON; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 8; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[4]); fscanf(FDNEUTFile, "%d", &cellPoints[5]); fscanf(FDNEUTFile, "%d", &cellPoints[7]); fscanf(FDNEUTFile, "%d", &cellPoints[6]); } else if (nodesPerElement==27) { type = VTK_QUADRATIC_HEXAHEDRON; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 20; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[8]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[11]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[24]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d", &cellPoints[9]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); fscanf(FDNEUTFile, "%d", &cellPoints[10]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[16]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[20]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d", &cellPoints[17]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[23]); fscanf(FDNEUTFile, "%d", &cellPoints[26]); fscanf(FDNEUTFile, "%d", &cellPoints[21]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); fscanf(FDNEUTFile, "%d", &pointBuffer); fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d",&cellPoints[19]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[22]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d",&cellPoints[18]); fscanf(FDNEUTFile, "%d",&cellPoints[4]); fscanf(FDNEUTFile, "%d",&cellPoints[12]); fscanf(FDNEUTFile, "%d",&cellPoints[5]); fscanf(FDNEUTFile, "%d",&cellPoints[15]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[25]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d",&cellPoints[13]); fscanf(FDNEUTFile, "%d",&cellPoints[7]); fscanf(FDNEUTFile, "%d",&cellPoints[14]); fscanf(FDNEUTFile, "%d",&cellPoints[6]); } break; case TETRAHEDRON: if (nodesPerElement==4) { type = VTK_TETRA; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 4; cellPoints = new int[numberOfCellPoints]; for (i=0; iGhostNodes ? nodesPerElement : 10; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[4]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[6]); fscanf(FDNEUTFile, "%d", &cellPoints[5]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[7]); fscanf(FDNEUTFile, "%d", &cellPoints[8]); fscanf(FDNEUTFile, "%d", &cellPoints[9]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); } break; case WEDGE: if (nodesPerElement==6) { type = VTK_WEDGE; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 6; cellPoints = new int[numberOfCellPoints]; for (i=0; iGhostNodes ? nodesPerElement : 15; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[6]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[8]); fscanf(FDNEUTFile, "%d", &cellPoints[7]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[12]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[15]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d", &cellPoints[13]); if (this->GhostNodes) { fscanf(FDNEUTFile, "%d", &cellPoints[16]); fscanf(FDNEUTFile, "%d", &cellPoints[17]); } else { fscanf(FDNEUTFile, "%d", &pointBuffer); fscanf(FDNEUTFile, "%d", &pointBuffer); } fscanf(FDNEUTFile, "%d", &cellPoints[14]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); fscanf(FDNEUTFile, "%d", &cellPoints[9]); fscanf(FDNEUTFile, "%d", &cellPoints[4]); fscanf(FDNEUTFile, "%d",&cellPoints[11]); fscanf(FDNEUTFile, "%d",&cellPoints[10]); fscanf(FDNEUTFile, "%d",&cellPoints[5]); } else if (nodesPerElement==15) { type = VTK_QUADRATIC_WEDGE; numberOfCellPoints = this->GhostNodes ? nodesPerElement : 15; cellPoints = new int[numberOfCellPoints]; fscanf(FDNEUTFile, "%d", &cellPoints[0]); fscanf(FDNEUTFile, "%d", &cellPoints[6]); fscanf(FDNEUTFile, "%d", &cellPoints[1]); fscanf(FDNEUTFile, "%d", &cellPoints[8]); fscanf(FDNEUTFile, "%d", &cellPoints[7]); fscanf(FDNEUTFile, "%d", &cellPoints[2]); fscanf(FDNEUTFile, "%d", &cellPoints[12]); fscanf(FDNEUTFile, "%d", &cellPoints[13]); fscanf(FDNEUTFile, "%d", &cellPoints[14]); fscanf(FDNEUTFile, "%d", &cellPoints[3]); fscanf(FDNEUTFile, "%d", &cellPoints[9]); fscanf(FDNEUTFile, "%d", &cellPoints[4]); fscanf(FDNEUTFile, "%d",&cellPoints[11]); fscanf(FDNEUTFile, "%d",&cellPoints[10]); fscanf(FDNEUTFile, "%d",&cellPoints[5]); } break; default: invalid = true; } #if 0 entityArray->InsertValue(gridCellArray->GetNumberOfCells()-1,1); #endif if (!invalid) { typesArray->InsertNextValue(type); this->OneToZeroOffset(numberOfCellPoints,cellPoints); vtkIdType* cellPointsIdType = new vtkIdType[numberOfCellPoints]; for (int i=0; iInsertNextCell(numberOfCellPoints,cellPointsIdType); delete[] cellPointsIdType; singleEntityArray->InsertNextValue(entityCounter); delete[] cellPoints; } else { cout<<"foo"<Delete(); #endif ++entityCounter; } singleEntityArray->Delete(); fclose(FDNEUTFile); output->SetPoints(points); output->SetCells(typesArray->GetPointer(0),gridCellArray); points->Delete(); typesArray->Delete(); gridCellArray->Delete(); return 1; } void vtkvmtkFDNEUTReader::PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/IO/vtkvmtkDICOMImageReader.h0000664000175000017500000000405711757446472017653 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDICOMImageReader.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkDICOMImageReader - .. // .SECTION Description // .. #ifndef __vtkvmtkDICOMImageReader_h #define __vtkvmtkDICOMImageReader_h #include "vtkDICOMImageReader.h" #include "vtkvmtkWin32Header.h" //#include "DICOMParser/DICOMParser.h" //#include "DICOMParser/DICOMAppHelper.h" class VTK_VMTK_IO_EXPORT vtkvmtkDICOMImageReader : public vtkDICOMImageReader { public: vtkTypeRevisionMacro(vtkvmtkDICOMImageReader,vtkDICOMImageReader); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkDICOMImageReader *New(); vtkSetMacro(AutoOrientImage,int); vtkGetMacro(AutoOrientImage,int); vtkBooleanMacro(AutoOrientImage,int); vtkGetStringMacro(OrientationStringX); vtkGetStringMacro(OrientationStringY); vtkGetStringMacro(OrientationStringZ); protected: vtkvmtkDICOMImageReader(); ~vtkvmtkDICOMImageReader(); virtual void ExecuteInformation(); virtual void ExecuteData(vtkDataObject *out); void ComputeOutputVoxelSpacing(); void GenerateOrientationString(float direction[3], char* orientationString); void OrientImageData(); int AutoOrientImage; char* OrientationStringX; char* OrientationStringY; char* OrientationStringZ; private: vtkvmtkDICOMImageReader(const vtkvmtkDICOMImageReader&) {}; void operator=(const vtkvmtkDICOMImageReader&) {}; }; #endif vmtk-1.0.1/vtkVmtk/IO/vtkvmtkTetGenWriter.cxx0000664000175000017500000001367011757446472017671 0ustar lucaluca/*========================================================================= Program: VMTK Module: vtkvmtkTetGenWriter.cxx Language: C++ Date: Sat Feb 19 22:47:34 CET 2011 Version: Revision: 1.0 Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkTetGenWriter.h" #include "vtkUnstructuredGrid.h" #include "vtkTetra.h" #include "vtkCellType.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkIntArray.h" #include "vtkIdTypeArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkTetGenWriter, "$Revision: 1.0 $"); vtkStandardNewMacro(vtkvmtkTetGenWriter); vtkvmtkTetGenWriter::vtkvmtkTetGenWriter() { this->BoundaryDataArrayName = NULL; } vtkvmtkTetGenWriter::~vtkvmtkTetGenWriter() { if (this->BoundaryDataArrayName) { delete[] this->BoundaryDataArrayName; this->BoundaryDataArrayName = NULL; } } void vtkvmtkTetGenWriter::WriteData() { vtkUnstructuredGrid *input= vtkUnstructuredGrid::SafeDownCast(this->GetInput()); if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return; } std::string nodeFileName = this->FileName; nodeFileName += ".node"; std::string eleFileName = this->FileName; eleFileName += ".ele"; ofstream nodeStream(nodeFileName.c_str()); ofstream eleStream(eleFileName.c_str()); if (!nodeStream.good()) { vtkErrorMacro(<<"Could not open node file for writing."); return; } if (!eleStream.good()) { vtkErrorMacro(<<"Could not open ele file for writing."); return; } input->BuildLinks(); int numberOfPoints = input->GetNumberOfPoints(); int i, j; //TODO: add attributes and boundary markers nodeStream << numberOfPoints << " 3 0 0" << std::endl; double point[3]; for (i=0; iGetPoint(i,point); nodeStream << i+1 << " " << point[0] << " " << point[1] << " " << point[2] << std::endl; } #if 0 vtkIntArray* boundaryDataArray = vtkIntArray::New(); if (this->BoundaryDataArrayName) { if (input->GetCellData()->GetArray(this->BoundaryDataArrayName)) { boundaryDataArray->DeepCopy(input->GetCellData()->GetArray(this->BoundaryDataArrayName)); } else { vtkErrorMacro(<<"BoundaryDataArray with name specified does not exist"); boundaryDataArray->Delete(); return; } } else { boundaryDataArray->SetNumberOfValues(numberOfCells); boundaryDataArray->FillComponent(0,0.0); } #endif vtkIdTypeArray* tetraCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TETRA,tetraCellIdArray); int numberOfTetras = tetraCellIdArray->GetNumberOfTuples(); vtkIdTypeArray* quadraticTetraCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_QUADRATIC_TETRA,quadraticTetraCellIdArray); int numberOfQuadraticTetras = quadraticTetraCellIdArray->GetNumberOfTuples(); int pointsInTet = 4; vtkIdTypeArray* tetIdsArray = tetraCellIdArray; int numberOfOutputTetras = tetraCellIdArray->GetNumberOfTuples(); if (numberOfQuadraticTetras > numberOfTetras) { pointsInTet = 10; tetIdsArray = quadraticTetraCellIdArray; numberOfOutputTetras = quadraticTetraCellIdArray->GetNumberOfTuples(); } //TODO: add attributes eleStream << numberOfOutputTetras << " " << pointsInTet << " 0" << std::endl; double point0[3], point1[3], point2[3], point3[3]; double cross[3], vector01[3], vector21[3], vector31[3]; double dot; int tmp; int cellPointIds[10]; for (i=0; iGetValue(i); vtkCell* cell = input->GetCell(cellId); for (j=0; jGetPointId(j); } input->GetPoint(cellPointIds[0],point0); input->GetPoint(cellPointIds[1],point1); input->GetPoint(cellPointIds[2],point2); input->GetPoint(cellPointIds[3],point3); vector01[0] = point0[0] - point1[0]; vector01[1] = point0[1] - point1[1]; vector01[2] = point0[2] - point1[2]; vector21[0] = point2[0] - point1[0]; vector21[1] = point2[1] - point1[1]; vector21[2] = point2[2] - point1[2]; vector31[0] = point3[0] - point1[0]; vector31[1] = point3[1] - point1[1]; vector31[2] = point3[2] - point1[2]; vtkMath::Cross(vector21,vector31,cross); dot = vtkMath::Dot(cross,vector01); if (dot < 0.0) { tmp = cellPointIds[2]; cellPointIds[2] = cellPointIds[3]; cellPointIds[3] = tmp; if (pointsInTet == 10) { tmp = cellPointIds[6]; cellPointIds[6] = cellPointIds[7]; cellPointIds[7] = tmp; tmp = cellPointIds[5]; cellPointIds[5] = cellPointIds[8]; cellPointIds[8] = tmp; } } eleStream << i+1 << " "; for (j=0; jDelete(); quadraticTetraCellIdArray->Delete(); } void vtkvmtkTetGenWriter::PrintSelf(ostream& os, vtkIndent indent) { vtkUnstructuredGridWriter::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/IO/vtkvmtkXdaReader.cxx0000664000175000017500000000451111757446472017137 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkXdaReader.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 #include "vtkvmtkXdaReader.h" #include "vtkUnstructuredGrid.h" #include "vtkCellType.h" #include "vtkCell.h" #include "vtkIdTypeArray.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkXdaReader, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkXdaReader); vtkvmtkXdaReader::vtkvmtkXdaReader() { this->BoundaryDataArrayName = NULL; } vtkvmtkXdaReader::~vtkvmtkXdaReader() { if (this->BoundaryDataArrayName) { delete[] this->BoundaryDataArrayName; this->BoundaryDataArrayName = NULL; } } int vtkvmtkXdaReader::RequestData( vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *outInfo = outputVector->GetInformationObject(0); if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) { return 1; } if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return 1; } return 1; } void vtkvmtkXdaReader::PrintSelf(ostream& os, vtkIndent indent) { vtkUnstructuredGridReader::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Segmentation/0000775000175000017500000000000011757446472015252 5ustar lucalucavmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkUpwindGradientMagnitudeImageFilter.cxx0000664000175000017500000000220611757446472026320 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsUpwindGradientMagnitudeImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUpwindGradientMagnitudeImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUpwindGradientMagnitudeImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkUpwindGradientMagnitudeImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkFastMarchingDirectionalFreezeImageFilter.h0000664000175000017500000001437011757446472027055 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFastMarchingDirectionalFreezeImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkFastMarchingDirectionalFreezeImageFilter - Wrapper class around itk::FastMarchingDirectionalFreezeImageFilter // .SECTION Description // vtkvmtkFastMarchingDirectionalFreezeImageFilter #ifndef __vtkvmtkFastMarchingDirectionalFreezeImageFilter_h #define __vtkvmtkFastMarchingDirectionalFreezeImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkFastMarchingDirectionalFreezeImageFilter.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkFastMarchingDirectionalFreezeImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkFastMarchingDirectionalFreezeImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkFastMarchingDirectionalFreezeImageFilter, vtkvmtkITKImageToImageFilterFF); // void SetUseImageSpacing ( int value ) // { // DelegateITKInputMacro ( SetUseImageSpacing, (bool) value ); // } // void UseImageSpacingOn() // { // this->SetUseImageSpacing (true); // } // void UseImageSpacingOff() // { // this->SetUseImageSpacing (false); // } // int GetUseImageSpacing() // { DelegateITKOutputMacro ( GetUseImageSpacing ); } void SetGenerateGradientImage ( int value ) { DelegateITKInputMacro ( SetGenerateGradientImage, (bool) value ); } void GenerateGradientImageOn() { this->SetGenerateGradientImage (true); } void GenerateGradientImageOff() { this->SetGenerateGradientImage (false); } int GetGenerateGradientImage() { DelegateITKOutputMacro ( GetGenerateGradientImage ); } void SetTargetReachedMode ( int value ) { DelegateITKInputMacro ( SetTargetReachedMode, value ); } int GetTargetReachedMode() { DelegateITKOutputMacro ( GetTargetReachedMode ); } void SetTargetReachedModeToOneTarget() { this->SetTargetReachedMode ( ImageFilterType::OneTarget ); } void SetTargetReachedModeToAllTargets() { this->SetTargetReachedMode ( ImageFilterType::AllTargets ); } double GetTargetValue() { DelegateITKOutputMacro ( GetTargetValue ); } void SetTargetOffset ( double value ) { DelegateITKInputMacro ( SetTargetOffset, value ); } double GetTargetOffset() { DelegateITKOutputMacro ( GetTargetOffset ); } vtkSetObjectMacro(Seeds,vtkIdList); vtkGetObjectMacro(Seeds,vtkIdList); vtkSetObjectMacro(Targets,vtkIdList); vtkGetObjectMacro(Targets,vtkIdList); void Update() { //BTX this->itkImporter->Update(); if (this->vtkExporter->GetInput()) { ImageFilterType::NodeContainerPointer seeds = ImageFilterType::NodeContainer::New(); int i; for (i=0; iSeeds->GetNumberOfIds(); i++) { // TODO: here we get the point. We should get the cell center instead. Superclass::InputImageType::PointType seedPoint(this->vtkExporter->GetInput()->GetPoint(this->Seeds->GetId(i))); ImageFilterType::NodeType::IndexType seedIndex; this->itkImporter->GetOutput()->TransformPhysicalPointToIndex(seedPoint,seedIndex); ImageFilterType::PixelType seedValue = itk::NumericTraits::Zero; ImageFilterType::NodeType seed; seed.SetValue(seedValue); seed.SetIndex(seedIndex); seeds->InsertElement(i,seed); } this->GetImageFilterPointer()->SetTrialPoints(seeds); ImageFilterType::NodeContainerPointer targets = ImageFilterType::NodeContainer::New(); for (i=0; iTargets->GetNumberOfIds(); i++) { // TODO: here we get the point. We should get the cell center instead. Superclass::InputImageType::PointType seedPoint(this->vtkExporter->GetInput()->GetPoint(this->Targets->GetId(i))); ImageFilterType::NodeType::IndexType seedIndex; this->itkImporter->GetOutput()->TransformPhysicalPointToIndex(seedPoint,seedIndex); ImageFilterType::PixelType seedValue = itk::NumericTraits::Zero; ImageFilterType::NodeType seed; seed.SetValue(seedValue); seed.SetIndex(seedIndex); targets->InsertElement(i,seed); } this->GetImageFilterPointer()->SetTargetPoints(targets); } // Force the internal pipeline to update. if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } //ETX } protected: //BTX typedef itk::FastMarchingDirectionalFreezeImageFilter ImageFilterType; vtkvmtkFastMarchingDirectionalFreezeImageFilter() : Superclass ( ImageFilterType::New() ) { this->Seeds = NULL; this->Targets = NULL; } ~vtkvmtkFastMarchingDirectionalFreezeImageFilter() { if (this->Seeds) { this->Seeds->Delete(); } if (this->Targets) { this->Targets->Delete(); } } ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX vtkIdList* Seeds; vtkIdList* Targets; private: vtkvmtkFastMarchingDirectionalFreezeImageFilter(const vtkvmtkFastMarchingDirectionalFreezeImageFilter&); // Not implemented. void operator=(const vtkvmtkFastMarchingDirectionalFreezeImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkActiveTubeFilter.h0000664000175000017500000001032011757446472022247 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: .h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .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: vtkTypeRevisionMacro(vtkvmtkActiveTubeFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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[2]+border && ijk[1]=extent[4]+border && ijk[2]vtkFeatureExporter->SetInput(value); } vtkImageData *GetSpeedImage() { this->vtkSpeedImporter->Update(); return this->vtkSpeedImporter->GetOutput(); } void SetFeatureScaling ( float value ) { DelegateITKInputMacro ( SetFeatureScaling, value ); }; float GetRMSChange () { DelegateITKOutputMacro(GetRMSChange); }; int GetElapsedIterations() { DelegateITKOutputMacro(GetElapsedIterations); }; float GetPropagationScaling ( ) { DelegateITKOutputMacro ( GetPropagationScaling ); }; float GetCurvatureScaling ( ) { DelegateITKOutputMacro ( GetCurvatureScaling ); }; float GetAdvectionScaling ( ) { DelegateITKOutputMacro ( GetAdvectionScaling ); }; int GetAutoGenerateSpeedAdvection ( ) { DelegateITKOutputMacro( GetAutoGenerateSpeedAdvection ); } int GetInterpolateSurfaceLocation ( ) { DelegateITKOutputMacro( GetInterpolateSurfaceLocation ); } // Description: Override vtkSource's Update so that we can access this class's GetOutput(). vtkSource's GetOutput is not virtual. void Update() { if (this->vtkFeatureExporter->GetInput()) { this->itkFeatureImporter->Update(); if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } } protected: //BTX typedef itk::ThresholdSegmentationLevelSetImageFilter ImageFilterType; typedef itk::VTKImageImport FeatureImageImportType; typedef itk::VTKImageExport SpeedImageExportType; vtkvmtkThresholdSegmentationLevelSetImageFilter() : Superclass ( ImageFilterType::New() ) { this->vtkFeatureExporter = vtkImageExport::New(); this->itkFeatureImporter = FeatureImageImportType::New(); this->itkSpeedExporter = SpeedImageExportType::New(); this->vtkSpeedImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkSpeedImporter->SetScalarArrayName("Scalars_"); #endif ConnectPipelines(this->itkSpeedExporter, this->vtkSpeedImporter); ConnectPipelines(this->vtkFeatureExporter, this->itkFeatureImporter); (dynamic_cast(m_Filter.GetPointer()))->SetFeatureImage(this->itkFeatureImporter->GetOutput()); this->itkSpeedExporter->SetInput((dynamic_cast(m_Filter.GetPointer()))->GetSpeedImage()); }; ~vtkvmtkThresholdSegmentationLevelSetImageFilter() { this->vtkSpeedImporter->Delete(); this->vtkFeatureExporter->Delete(); }; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } FeatureImageImportType::Pointer itkFeatureImporter; SpeedImageExportType::Pointer itkSpeedExporter; //ETX vtkImageExport *vtkFeatureExporter; vtkImageImport *vtkSpeedImporter; private: vtkvmtkThresholdSegmentationLevelSetImageFilter(const vtkvmtkThresholdSegmentationLevelSetImageFilter&); // Not implemented. void operator=(const vtkvmtkThresholdSegmentationLevelSetImageFilter&); // // Not implemented }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkUpwindGradientMagnitudeImageFilter.txx0000664000175000017500000001721611757446472025431 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: itkUpwindGradientMagnitudeImageFilter.txx,v $ Language: C++ Date: $Date: 2005/10/06 11:03:26 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 _itkUpwindGradientMagnitudeImageFilter_txx #define _itkUpwindGradientMagnitudeImageFilter_txx #include "itkUpwindGradientMagnitudeImageFilter.h" #include "itkConstNeighborhoodIterator.h" #include "itkNeighborhoodInnerProduct.h" #include "itkImageRegionIterator.h" #include "itkForwardDifferenceOperator.h" #include "itkBackwardDifferenceOperator.h" #include "itkNeighborhoodAlgorithm.h" #include "itkZeroFluxNeumannBoundaryCondition.h" #include "itkOffset.h" #include "itkProgressReporter.h" namespace itk { template void UpwindGradientMagnitudeImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "UseImageSpacing = " << m_UseImageSpacing << std::endl; } template void UpwindGradientMagnitudeImageFilter ::GenerateInputRequestedRegion() throw(InvalidRequestedRegionError) { // call the superclass' implementation of this method Superclass::GenerateInputRequestedRegion(); // get pointers to the input and output InputImagePointer inputPtr = const_cast< InputImageType * >( this->GetInput()); OutputImagePointer outputPtr = this->GetOutput(); if ( !inputPtr || !outputPtr ) { return; } // Build an operator so that we can determine the kernel size ForwardDifferenceOperator oper; oper.SetDirection(0); oper.CreateDirectional(); unsigned long radius = oper.GetRadius()[0]; // get a copy of the input requested region (should equal the output // requested region) typename TInputImage::RegionType inputRequestedRegion; inputRequestedRegion = inputPtr->GetRequestedRegion(); // pad the input requested region by the operator radius inputRequestedRegion.PadByRadius( radius ); // crop the input requested region at the input's largest possible region if ( inputRequestedRegion.Crop(inputPtr->GetLargestPossibleRegion()) ) { inputPtr->SetRequestedRegion( inputRequestedRegion ); return; } else { // Couldn't crop the region (requested region is outside the largest // possible region). Throw an exception. // store what we tried to request (prior to trying to crop) inputPtr->SetRequestedRegion( inputRequestedRegion ); // build an exception InvalidRequestedRegionError e(__FILE__, __LINE__); std::ostringstream msg; msg << static_cast(this->GetNameOfClass()) << "::GenerateInputRequestedRegion()"; e.SetLocation(msg.str().c_str()); e.SetDescription("Requested region is (at least partially) outside the largest possible region."); e.SetDataObject(inputPtr); throw e; } } template< typename TInputImage, typename TOutputImage > void UpwindGradientMagnitudeImageFilter< TInputImage, TOutputImage > ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId) { unsigned int i; ZeroFluxNeumannBoundaryCondition nbc; ConstNeighborhoodIterator nit; ConstNeighborhoodIterator bit; ImageRegionIterator it; NeighborhoodInnerProduct SIP; // Allocate output typename OutputImageType::Pointer output = this->GetOutput(); typename InputImageType::ConstPointer input = this->GetInput(); // Set up operators BackwardDifferenceOperator fdop[ImageDimension]; ForwardDifferenceOperator bdop[ImageDimension]; for (i = 0; i< ImageDimension; i++) { bdop[i].SetDirection(0); bdop[i].CreateDirectional(); fdop[i].SetDirection(0); fdop[i].CreateDirectional(); if (m_UseImageSpacing == true) { if ( this->GetInput()->GetSpacing()[i] == 0.0 ) { itkExceptionMacro(<< "Image spacing cannot be zero."); } else { bdop[i].ScaleCoefficients( 1.0 / this->GetInput()->GetSpacing()[i] ); fdop[i].ScaleCoefficients( 1.0 / this->GetInput()->GetSpacing()[i] ); } } } // Calculate iterator radius Size radius; for (i = 0; i < ImageDimension; ++i) { radius[i] = fdop[0].GetRadius()[0]; radius[i] = bdop[0].GetRadius()[0]; } // Find the data-set boundary "faces" typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator:: FaceListType faceList; NeighborhoodAlgorithm::ImageBoundaryFacesCalculator bC; faceList = bC(input, outputRegionForThread, radius); typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator:: FaceListType::iterator fit; fit = faceList.begin(); // support progress methods/callbacks ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); // Process non-boundary face nit = ConstNeighborhoodIterator(radius, input, *fit); std::slice bd_x_slice[ImageDimension]; std::slice fd_x_slice[ImageDimension]; const unsigned long center = nit.Size() / 2; for (i = 0; i < ImageDimension; ++i) { bd_x_slice[i] = std::slice( center - nit.GetStride(i) * radius[i], bdop[i].GetSize()[0], nit.GetStride(i)); fd_x_slice[i] = std::slice( center - nit.GetStride(i) * radius[i], fdop[i].GetSize()[0], nit.GetStride(i)); } double weights[2]; weights[0] = (1.0 + fabs(m_UpwindFactor)) / 2.0; weights[1] = 1.0 - weights[0]; // Process each of the boundary faces. These are N-d regions which border // the edge of the buffer. for (fit=faceList.begin(); fit != faceList.end(); ++fit) { bit = ConstNeighborhoodIterator(radius, input, *fit); it = ImageRegionIterator(output, *fit); bit.OverrideBoundaryCondition(&nbc); bit.GoToBegin(); while ( ! bit.IsAtEnd() ) { RealType a = NumericTraits::Zero; for (i = 0; i < ImageDimension; ++i) { const RealType bdg = SIP(bd_x_slice[i], bit, bdop[i]); const RealType fdg = SIP(fd_x_slice[i], bit, fdop[i]); RealType g = NumericTraits::Zero; if (m_UpwindFactor > 0.0) { g = -fdg > bdg ? weights[0] * fdg + weights[1] * bdg : weights[1] * fdg + weights[0] * bdg; } else { g = -fdg < bdg ? weights[0] * fdg + weights[1] * bdg : weights[1] * fdg + weights[0] * bdg; } if (-fdg > 0.0 || bdg > 0.0) { a += g * g; } } it.Value() = static_cast(::sqrt(a)); ++bit; ++it; progress.CompletedPixel(); } } } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkVesselEnhancingDiffusion3DImageFilter.txx0000664000175000017500000006523511757446472025765 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkVesselEnhancingDiffusion3DImageFilter.txx,v $ Language: C++ Date: $Date: 2009/01/09 11:15:27 $ Version: $Revision: 1.2 $ =========================================================================*/ #ifndef __itkVesselEnhancingDiffusion3DImageFilter_txx #define __itkVesselEnhancingDiffusion3DImageFilter_txx #include "itkVesselEnhancingDiffusion3DImageFilter.h" #include "itkCastImageFilter.h" #include "itkConstShapedNeighborhoodIterator.h" #include "itkHessianRecursiveGaussianImageFilter.h" #include "itkImageRegionConstIterator.h" #include "itkImageRegionIterator.h" #include "itkMinimumMaximumImageFilter.h" #include "itkNeighborhoodAlgorithm.h" #include "itkNumericTraits.h" #include "itkZeroFluxNeumannBoundaryCondition.h" #include #include #include #include namespace itk { // constructor template VesselEnhancingDiffusion3DImageFilter ::VesselEnhancingDiffusion3DImageFilter(): m_TimeStep(NumericTraits::Zero), m_Iterations(0), m_RecalculateVesselness(0), m_Epsilon(0.0), m_Omega(0.0), m_Sensitivity(0.0), m_DarkObjectLightBackground(false) { this->SetNumberOfRequiredInputs(1); } // printself for debugging template void VesselEnhancingDiffusion3DImageFilter ::PrintSelf(std::ostream &os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "TimeStep : " << m_TimeStep << std::endl; os << indent << "Iterations : " << m_Iterations << std::endl; os << indent << "RecalculateVesselness : " << m_RecalculateVesselness << std::endl; os << indent << "Scales : "; for (unsigned int i=0; i void VesselEnhancingDiffusion3DImageFilter ::VED3DSingleIteration(typename ImageType::Pointer ci) { bool rec(false); if ( (m_CurrentIteration == 1) || (m_RecalculateVesselness == 0) || (m_CurrentIteration % m_RecalculateVesselness == 0) ) { rec = true; if (m_Verbose) { std::cout << "v "; std::cout.flush(); } MaxVesselResponse (ci); DiffusionTensor (); } if (m_Verbose) { if (!rec) { std::cout << ". "; std::cout.flush(); } } // calculate d = nonlineardiffusion(ci) // using 3x3x3 stencil, afterwards copy // result from d back to ci typename PrecisionImageType::Pointer d = PrecisionImageType::New(); d->SetOrigin(ci->GetOrigin()); d->SetSpacing(ci->GetSpacing()); d->SetDirection(ci->GetDirection()); d->SetRegions(ci->GetLargestPossibleRegion()); d->Allocate(); d->FillBuffer(NumericTraits::Zero); // shapedneighborhood iter, zeroflux boundary condition // division into faces and inner region typedef ZeroFluxNeumannBoundaryCondition BT; typedef ConstShapedNeighborhoodIterator NT; typedef typename NeighborhoodAlgorithm::ImageBoundaryFacesCalculator FT; BT b; typename NT::RadiusType r; r.Fill(1); // offsets const typename NT::OffsetType oxp = {{1,0,0}}; const typename NT::OffsetType oxm = {{-1,0,0}}; const typename NT::OffsetType oyp = {{0,1,0}}; const typename NT::OffsetType oym = {{0,-1,0}}; const typename NT::OffsetType ozp = {{0,0,1}}; const typename NT::OffsetType ozm = {{0,0,-1}}; const typename NT::OffsetType oxpyp = {{1,1,0}}; const typename NT::OffsetType oxmym = {{-1,-1,0}}; const typename NT::OffsetType oxpym = {{1,-1,0}}; const typename NT::OffsetType oxmyp = {{-1,1,0}}; const typename NT::OffsetType oxpzp = {{1,0,1}}; const typename NT::OffsetType oxmzm = {{-1,0,-1}}; const typename NT::OffsetType oxpzm = {{1,0,-1}}; const typename NT::OffsetType oxmzp = {{-1,0,1}}; const typename NT::OffsetType oypzp = {{0,1,1}}; const typename NT::OffsetType oymzm = {{0,-1,-1}}; const typename NT::OffsetType oypzm = {{0,1,-1}}; const typename NT::OffsetType oymzp = {{0,-1,1}}; // fixed weights (timers) const typename PrecisionImageType::SpacingType ispacing = ci->GetSpacing(); const Precision rxx = m_TimeStep / (2.0 * ispacing[0] * ispacing[0]); const Precision ryy = m_TimeStep / (2.0 * ispacing[1] * ispacing[1]); const Precision rzz = m_TimeStep / (2.0 * ispacing[2] * ispacing[2]); const Precision rxy = m_TimeStep / (4.0 * ispacing[0] * ispacing[1]); const Precision rxz = m_TimeStep / (4.0 * ispacing[0] * ispacing[2]); const Precision ryz = m_TimeStep / (4.0 * ispacing[1] * ispacing[2]); // faces FT fc; typename FT::FaceListType fci = fc(ci,d->GetLargestPossibleRegion(),r); typename FT::FaceListType fxx = fc(m_Dxx,d->GetLargestPossibleRegion(),r); typename FT::FaceListType fxy = fc(m_Dxy,d->GetLargestPossibleRegion(),r); typename FT::FaceListType fxz = fc(m_Dxz,d->GetLargestPossibleRegion(),r); typename FT::FaceListType fyy = fc(m_Dyy,d->GetLargestPossibleRegion(),r); typename FT::FaceListType fyz = fc(m_Dyz,d->GetLargestPossibleRegion(),r); typename FT::FaceListType fzz = fc(m_Dzz,d->GetLargestPossibleRegion(),r); typename FT::FaceListType::iterator fitci,fitxx,fitxy,fitxz,fityy,fityz,fitzz; for ( fitci = fci.begin(), fitxx = fxx.begin(), fitxy = fxy.begin(), fitxz = fxz.begin(), fityy = fyy.begin(), fityz = fyz.begin(), fitzz = fzz.begin(); fitci != fci.end(); ++fitci, ++fitxx, ++fitxy, ++fitxz, ++fityy, ++fityz, ++fitzz) { // output iter ImageRegionIterator dit(d,*fitci); // input iters NT itci (r,ci,*fitci); NT itxx (r,m_Dxx,*fitxx); NT itxy (r,m_Dxy,*fitxy); NT itxz (r,m_Dxz,*fitxz); NT ityy (r,m_Dyy,*fityy); NT ityz (r,m_Dyz,*fityz); NT itzz (r,m_Dzz,*fitzz); itci.OverrideBoundaryCondition(&b); itxx.OverrideBoundaryCondition(&b); itxy.OverrideBoundaryCondition(&b); itxz.OverrideBoundaryCondition(&b); ityy.OverrideBoundaryCondition(&b); ityz.OverrideBoundaryCondition(&b); itzz.OverrideBoundaryCondition(&b); // setting active offsets (yeah there must // be some smarter way of doing this) itci.ClearActiveList(); itxx.ClearActiveList(); itxy.ClearActiveList(); itxz.ClearActiveList(); ityy.ClearActiveList(); ityz.ClearActiveList(); itzz.ClearActiveList(); itci.ActivateOffset(oxp); itxx.ActivateOffset(oxp); itxy.ActivateOffset(oxp); itxz.ActivateOffset(oxp); ityy.ActivateOffset(oxp); ityz.ActivateOffset(oxp); itzz.ActivateOffset(oxp); itci.ActivateOffset(oxm); itxx.ActivateOffset(oxm); itxy.ActivateOffset(oxm); itxz.ActivateOffset(oxm); ityy.ActivateOffset(oxm); ityz.ActivateOffset(oxm); itzz.ActivateOffset(oxm); itci.ActivateOffset(oyp); itxx.ActivateOffset(oyp); itxy.ActivateOffset(oyp); itxz.ActivateOffset(oyp); ityy.ActivateOffset(oyp); ityz.ActivateOffset(oyp); itzz.ActivateOffset(oyp); itci.ActivateOffset(oym); itxx.ActivateOffset(oym); itxy.ActivateOffset(oym); itxz.ActivateOffset(oym); ityy.ActivateOffset(oym); ityz.ActivateOffset(oym); itzz.ActivateOffset(oym); itci.ActivateOffset(ozp); itxx.ActivateOffset(ozp); itxy.ActivateOffset(ozp); itxz.ActivateOffset(ozp); ityy.ActivateOffset(ozp); ityz.ActivateOffset(ozp); itzz.ActivateOffset(ozp); itci.ActivateOffset(ozm); itxx.ActivateOffset(ozm); itxy.ActivateOffset(ozm); itxz.ActivateOffset(ozm); ityy.ActivateOffset(ozm); ityz.ActivateOffset(ozm); itzz.ActivateOffset(ozm); itci.ActivateOffset(oxpyp); itxx.ActivateOffset(oxpyp); itxy.ActivateOffset(oxpyp); itxz.ActivateOffset(oxpyp); ityy.ActivateOffset(oxpyp); ityz.ActivateOffset(oxpyp); itzz.ActivateOffset(oxpyp); itci.ActivateOffset(oxmym); itxx.ActivateOffset(oxmym); itxy.ActivateOffset(oxmym); itxz.ActivateOffset(oxmym); ityy.ActivateOffset(oxmym); ityz.ActivateOffset(oxmym); itzz.ActivateOffset(oxmym); itci.ActivateOffset(oxpym); itxx.ActivateOffset(oxpym); itxy.ActivateOffset(oxpym); itxz.ActivateOffset(oxpym); ityy.ActivateOffset(oxpym); ityz.ActivateOffset(oxpym); itzz.ActivateOffset(oxpym); itci.ActivateOffset(oxmyp); itxx.ActivateOffset(oxmyp); itxy.ActivateOffset(oxmyp); itxz.ActivateOffset(oxmyp); ityy.ActivateOffset(oxmyp); ityz.ActivateOffset(oxmyp); itzz.ActivateOffset(oxmyp); itci.ActivateOffset(oxpzp); itxx.ActivateOffset(oxpzp); itxy.ActivateOffset(oxpzp); itxz.ActivateOffset(oxpzp); ityy.ActivateOffset(oxpzp); ityz.ActivateOffset(oxpzp); itzz.ActivateOffset(oxpzp); itci.ActivateOffset(oxmzm); itxx.ActivateOffset(oxmzm); itxy.ActivateOffset(oxmzm); itxz.ActivateOffset(oxmzm); ityy.ActivateOffset(oxmzm); ityz.ActivateOffset(oxmzm); itzz.ActivateOffset(oxmzm); itci.ActivateOffset(oxpzm); itxx.ActivateOffset(oxpzm); itxy.ActivateOffset(oxpzm); itxz.ActivateOffset(oxpzm); ityy.ActivateOffset(oxpzm); ityz.ActivateOffset(oxpzm); itzz.ActivateOffset(oxpzm); itci.ActivateOffset(oxmzp); itxx.ActivateOffset(oxmzp); itxy.ActivateOffset(oxmzp); itxz.ActivateOffset(oxmzp); ityy.ActivateOffset(oxmzp); ityz.ActivateOffset(oxmzp); itzz.ActivateOffset(oxmzp); itci.ActivateOffset(oypzp); itxx.ActivateOffset(oypzp); itxy.ActivateOffset(oypzp); itxz.ActivateOffset(oypzp); ityy.ActivateOffset(oypzp); ityz.ActivateOffset(oypzp); itzz.ActivateOffset(oypzp); itci.ActivateOffset(oymzm); itxx.ActivateOffset(oymzm); itxy.ActivateOffset(oymzm); itxz.ActivateOffset(oymzm); ityy.ActivateOffset(oymzm); ityz.ActivateOffset(oymzm); itzz.ActivateOffset(oymzm); itci.ActivateOffset(oypzm); itxx.ActivateOffset(oypzm); itxy.ActivateOffset(oypzm); itxz.ActivateOffset(oypzm); ityy.ActivateOffset(oypzm); ityz.ActivateOffset(oypzm); itzz.ActivateOffset(oypzm); itci.ActivateOffset(oymzp); itxx.ActivateOffset(oymzp); itxy.ActivateOffset(oymzp); itxz.ActivateOffset(oymzp); ityy.ActivateOffset(oymzp); ityz.ActivateOffset(oymzp); itzz.ActivateOffset(oymzp); // run for each face diffusion for (itci.GoToBegin(), dit.GoToBegin(), itxx.GoToBegin(),itxy.GoToBegin(), itxz.GoToBegin(), ityy.GoToBegin(),ityz.GoToBegin(), itzz.GoToBegin(); !itci.IsAtEnd(); ++itci, ++dit, ++itxx, ++itxy, ++itxz, ++ityy, ++ityz, ++itzz) { // weights const Precision xp = itxx.GetPixel(oxp) + itxx.GetCenterPixel(); const Precision xm = itxx.GetPixel(oxm) + itxx.GetCenterPixel(); const Precision yp = ityy.GetPixel(oyp) + ityy.GetCenterPixel(); const Precision ym = ityy.GetPixel(oym) + ityy.GetCenterPixel(); const Precision zp = itzz.GetPixel(ozp) + itzz.GetCenterPixel(); const Precision zm = itzz.GetPixel(ozm) + itzz.GetCenterPixel(); const Precision xpyp = itxy.GetPixel(oxpyp) + itxy.GetCenterPixel(); const Precision xmym = itxy.GetPixel(oxmym) + itxy.GetCenterPixel(); const Precision xpym = - itxy.GetPixel(oxpym) - itxy.GetCenterPixel(); const Precision xmyp = - itxy.GetPixel(oxmyp) - itxy.GetCenterPixel(); const Precision xpzp = itxz.GetPixel(oxpzp) + itxz.GetCenterPixel(); const Precision xmzm = itxz.GetPixel(oxmzm) + itxz.GetCenterPixel(); const Precision xpzm = - itxz.GetPixel(oxpzm) - itxz.GetCenterPixel(); const Precision xmzp = - itxz.GetPixel(oxmzp) - itxz.GetCenterPixel(); const Precision ypzp = ityz.GetPixel(oypzp) + ityz.GetCenterPixel(); const Precision ymzm = ityz.GetPixel(oymzm) + ityz.GetCenterPixel(); const Precision ypzm = - ityz.GetPixel(oypzm) - ityz.GetCenterPixel(); const Precision ymzp = - ityz.GetPixel(oymzp) - ityz.GetCenterPixel(); // evolution const Precision cv = itci.GetCenterPixel(); dit.Value() = cv + + rxx * ( xp * (itci.GetPixel(oxp) - cv) + xm * (itci.GetPixel(oxm) - cv) ) + ryy * ( yp * (itci.GetPixel(oyp) - cv) + ym * (itci.GetPixel(oym) - cv) ) + rzz * ( zp * (itci.GetPixel(ozp) - cv) + zm * (itci.GetPixel(ozm) - cv) ) + rxy * ( xpyp * (itci.GetPixel(oxpyp) - cv) + xmym * (itci.GetPixel(oxmym) - cv) + xpym * (itci.GetPixel(oxpym) - cv) + xmyp * (itci.GetPixel(oxmyp) - cv) ) + rxz * ( xpzp * (itci.GetPixel(oxpzp) - cv) + xmzm * (itci.GetPixel(oxmzm) - cv) + xpzm * (itci.GetPixel(oxpzm) - cv) + xmzp * (itci.GetPixel(oxmzp) - cv) ) + ryz * ( ypzp * (itci.GetPixel(oypzp) - cv) + ymzm * (itci.GetPixel(oymzm) - cv) + ypzm * (itci.GetPixel(oypzm) - cv) + ymzp * (itci.GetPixel(oymzp) - cv) ); } } // copying ImageRegionConstIterator iti (d,d->GetLargestPossibleRegion()); ImageRegionIterator ito (ci,ci->GetLargestPossibleRegion()); for (iti.GoToBegin(), ito.GoToBegin(); !iti.IsAtEnd(); ++iti,++ito) { ito.Value() = iti.Value(); } return; } // maxvesselresponse template void VesselEnhancingDiffusion3DImageFilter ::MaxVesselResponse(const typename ImageType::Pointer im) { // alloc memory for hessian/tensor m_Dxx = PrecisionImageType::New(); m_Dxx->SetOrigin(im->GetOrigin()); m_Dxx->SetSpacing(im->GetSpacing()); m_Dxx->SetDirection(im->GetDirection()); m_Dxx->SetRegions(im->GetLargestPossibleRegion()); m_Dxx->Allocate(); m_Dxx->FillBuffer(NumericTraits::One); m_Dxy = PrecisionImageType::New(); m_Dxy->SetOrigin(im->GetOrigin()); m_Dxy->SetSpacing(im->GetSpacing()); m_Dxy->SetDirection(im->GetDirection()); m_Dxy->SetRegions(im->GetLargestPossibleRegion()); m_Dxy->Allocate(); m_Dxy->FillBuffer(NumericTraits::Zero); m_Dxz = PrecisionImageType::New(); m_Dxz->SetOrigin(im->GetOrigin()); m_Dxz->SetSpacing(im->GetSpacing()); m_Dxz->SetDirection(im->GetDirection()); m_Dxz->SetRegions(im->GetLargestPossibleRegion()); m_Dxz->Allocate(); m_Dxz->FillBuffer(NumericTraits::Zero); m_Dyy = PrecisionImageType::New(); m_Dyy->SetOrigin(im->GetOrigin()); m_Dyy->SetSpacing(im->GetSpacing()); m_Dyy->SetDirection(im->GetDirection()); m_Dyy->SetRegions(im->GetLargestPossibleRegion()); m_Dyy->Allocate(); m_Dyy->FillBuffer(NumericTraits::One); m_Dyz = PrecisionImageType::New(); m_Dyz->SetOrigin(im->GetOrigin()); m_Dyz->SetSpacing(im->GetSpacing()); m_Dyz->SetDirection(im->GetDirection()); m_Dyz->SetRegions(im->GetLargestPossibleRegion()); m_Dyz->Allocate(); m_Dyz->FillBuffer(NumericTraits::Zero); m_Dzz = PrecisionImageType::New(); m_Dzz->SetOrigin(im->GetOrigin()); m_Dzz->SetSpacing(im->GetSpacing()); m_Dzz->SetDirection(im->GetDirection()); m_Dzz->SetRegions(im->GetLargestPossibleRegion()); m_Dzz->Allocate(); m_Dzz->FillBuffer(NumericTraits::One); // create temp vesselness image to store maxvessel typename PrecisionImageType::Pointer vi = PrecisionImageType::New(); vi->SetOrigin(im->GetOrigin()); vi->SetSpacing(im->GetSpacing()); vi->SetDirection(im->GetDirection()); vi->SetRegions(im->GetLargestPossibleRegion()); vi->Allocate(); vi->FillBuffer(NumericTraits::Zero); for (unsigned int i=0; i< m_Scales.size(); ++i) { typedef HessianRecursiveGaussianImageFilter HessianType; typename HessianType::Pointer hessian = HessianType::New(); hessian->SetInput(im); hessian->SetNormalizeAcrossScale(true); hessian->SetSigma(m_Scales[i]); hessian->Update(); ImageRegionIterator itxx (m_Dxx, m_Dxx->GetLargestPossibleRegion()); ImageRegionIterator itxy (m_Dxy, m_Dxy->GetLargestPossibleRegion()); ImageRegionIterator itxz (m_Dxz, m_Dxz->GetLargestPossibleRegion()); ImageRegionIterator ityy (m_Dyy, m_Dyy->GetLargestPossibleRegion()); ImageRegionIterator ityz (m_Dyz, m_Dyz->GetLargestPossibleRegion()); ImageRegionIterator itzz (m_Dzz, m_Dzz->GetLargestPossibleRegion()); ImageRegionIterator vit(vi, vi->GetLargestPossibleRegion()); ImageRegionConstIterator hit (hessian->GetOutput(), hessian->GetOutput()->GetLargestPossibleRegion()); for (itxx.GoToBegin(), itxy.GoToBegin(), itxz.GoToBegin(), ityy.GoToBegin(), ityz.GoToBegin(), itzz.GoToBegin(), vit.GoToBegin(), hit.GoToBegin(); !vit.IsAtEnd(); ++itxx, ++itxy, ++itxz, ++ityy, ++ityz, ++itzz, ++hit, ++vit) { vnl_matrix H(3,3); H(0,0) = hit.Value()(0,0); H(0,1) = H(1,0) = hit.Value()(0,1); H(0,2) = H(2,0) = hit.Value()(0,2); H(1,1) = hit.Value()(1,1); H(1,2) = H(2,1) = hit.Value()(1,2); H(2,2) = hit.Value()(2,2); vnl_symmetric_eigensystem ES(H); vnl_vector ev(3); ev[0] = ES.get_eigenvalue(0); ev[1] = ES.get_eigenvalue(1); ev[2] = ES.get_eigenvalue(2); if ( vcl_abs(ev[0]) > vcl_abs(ev[1]) ) std::swap(ev[0], ev[1]); if ( vcl_abs(ev[1]) > vcl_abs(ev[2]) ) std::swap(ev[1], ev[2]); if ( vcl_abs(ev[0]) > vcl_abs(ev[1]) ) std::swap(ev[0], ev[1]); const Precision vesselness = VesselnessFunction3D(ev[0],ev[1],ev[2]); if ( vesselness > 0 && vesselness > vit.Value() ) { vit.Value() = vesselness; itxx.Value() = hit.Value()(0,0); itxy.Value() = hit.Value()(0,1); itxz.Value() = hit.Value()(0,2); ityy.Value() = hit.Value()(1,1); ityz.Value() = hit.Value()(1,2); itzz.Value() = hit.Value()(2,2); } } } return; } // vesselnessfunction template typename VesselEnhancingDiffusion3DImageFilter::Precision VesselEnhancingDiffusion3DImageFilter::VesselnessFunction3D ( const Precision l1, const Precision l2, const Precision l3 ) { Precision vesselness; if ( (m_DarkObjectLightBackground && ((l2<=0) || (l3<=0))) || (!m_DarkObjectLightBackground && ( (l2>=0) || (l3 >=0))) ) { vesselness = NumericTraits::Zero; } else { const Precision smoothC=1E-5; const Precision va2= 2.0*m_Alpha*m_Alpha; const Precision vb2= 2.0*m_Beta*m_Beta; const Precision vc2= 2.0*m_Gamma*m_Gamma; const Precision Ra2 = (l2 * l2) / (l3 * l3); const Precision Rb2 = (l1 * l1) / vcl_abs(l2 * l3); const Precision S2 = (l1 * l1) + (l2 *l2) + (l3 * l3); const Precision T = vcl_exp(-(2*smoothC*smoothC)/(vcl_abs(l2)*l3*l3)); vesselness = T * (1.0 - vcl_exp( - Ra2/va2)) * vcl_exp(-Rb2/vb2) * (1.0 - vcl_exp(-S2/vc2)); } return vesselness; } // diffusiontensor template void VesselEnhancingDiffusion3DImageFilter ::DiffusionTensor() { ImageRegionIterator itxx (m_Dxx, m_Dxx->GetLargestPossibleRegion()); ImageRegionIterator itxy (m_Dxy, m_Dxy->GetLargestPossibleRegion()); ImageRegionIterator itxz (m_Dxz, m_Dxz->GetLargestPossibleRegion()); ImageRegionIterator ityy (m_Dyy, m_Dyy->GetLargestPossibleRegion()); ImageRegionIterator ityz (m_Dyz, m_Dyz->GetLargestPossibleRegion()); ImageRegionIterator itzz (m_Dzz, m_Dzz->GetLargestPossibleRegion()); for ( itxx.GoToBegin(), itxy.GoToBegin(), itxz.GoToBegin(), ityy.GoToBegin(), ityz.GoToBegin(), itzz.GoToBegin(); !itxx.IsAtEnd(); ++itxx, ++itxy, ++itxz, ++ityy, ++ityz, ++itzz) { vnl_matrix H(3,3); H(0,0) = itxx.Value(); H(0,1) = H(1,0) = itxy.Value(); H(0,2) = H(2,0) = itxz.Value(); H(1,1) = ityy.Value(); H(1,2) = H(2,1) = ityz.Value(); H(2,2) = itzz.Value(); vnl_symmetric_eigensystem ES(H); vnl_matrix EV(3,3); EV.set_column(0,ES.get_eigenvector(0)); EV.set_column(1,ES.get_eigenvector(1)); EV.set_column(2,ES.get_eigenvector(2)); vnl_vector ev(3); ev[0] = ES.get_eigenvalue(0); ev[1] = ES.get_eigenvalue(1); ev[2] = ES.get_eigenvalue(2); if ( vcl_abs(ev[0]) > vcl_abs(ev[1]) ) std::swap(ev[0], ev[1]); if ( vcl_abs(ev[1]) > vcl_abs(ev[2]) ) std::swap(ev[1], ev[2]); if ( vcl_abs(ev[0]) > vcl_abs(ev[1]) ) std::swap(ev[0], ev[1]); const Precision V=VesselnessFunction3D(ev[0],ev[1],ev[2]); vnl_vector evn(3); // adjusting eigenvalues // static_cast required to prevent error with gcc 4.1.2 evn[0] = 1.0 + (m_Epsilon - 1.0) * vcl_pow(V,static_cast(1.0/m_Sensitivity)); evn[1] = 1.0 + (m_Epsilon - 1.0) * vcl_pow(V,static_cast(1.0/m_Sensitivity)); evn[2] = 1.0 + (m_Omega - 1.0 ) * vcl_pow(V,static_cast(1.0/m_Sensitivity)); vnl_matrix LAM(3,3); LAM.fill(0); LAM(0,0) = evn[0]; LAM(1,1) = evn[1]; LAM(2,2) = evn[2]; const vnl_matrix HN = EV * LAM * EV.transpose(); itxx.Value() = HN(0,0); itxy.Value() = HN(0,1); itxz.Value() = HN(0,2); ityy.Value() = HN(1,1); ityz.Value() = HN(1,2); itzz.Value() = HN(2,2); } return; } // generatedata template void VesselEnhancingDiffusion3DImageFilter ::GenerateData() { if (m_Verbose) { std::cout << std::endl << "begin vesselenhancingdiffusion3Dimagefilter ... " << std::endl; } typedef MinimumMaximumImageFilter MinMaxType; typename MinMaxType::Pointer minmax = MinMaxType::New(); minmax->SetInput(this->GetInput()); minmax->Update(); const typename ImageType::SpacingType ispacing = this->GetInput()->GetSpacing(); const Precision htmax = 0.5 / ( 1.0 / (ispacing[0] * ispacing[0]) + 1.0 / (ispacing[1] * ispacing[1]) + 1.0 / (ispacing[2] * ispacing[2]) ); if (m_TimeStep == NumericTraits::Zero) { m_TimeStep = htmax; } if (m_TimeStep> htmax) { std::cerr << "the time step size is too large!" << std::endl; this->AllocateOutputs(); return; } if (m_Verbose) { std::cout << "min/max \t" << minmax->GetMinimum() << " " << minmax->GetMaximum() << std::endl; std::cout << "iterations/timestep \t" << m_Iterations << " " << m_TimeStep << std::endl; std::cout << "recalc v \t" << m_RecalculateVesselness << std::endl; std::cout << "scales \t"; for (unsigned int i=0; i CT; typename CT::Pointer cast = CT::New(); cast->SetInput(this->GetInput()); cast->Update(); typename PrecisionImageType::Pointer ci = cast->GetOutput(); if (m_Verbose) { std::cout << "start algorithm ... " << std::endl; } for (m_CurrentIteration=1; m_CurrentIteration<=m_Iterations; m_CurrentIteration++) { VED3DSingleIteration (ci); } typedef MinimumMaximumImageFilter MMT; typename MMT::Pointer mm = MMT::New(); mm->SetInput(ci); mm->Update(); if (m_Verbose) { std::cout << std::endl; std::cout << "min/max \t" << mm->GetMinimum() << " " << mm->GetMaximum() << std::endl; std::cout << "end vesselenhancingdiffusion3Dimagefilter" << std::endl; } // cast back to pixeltype this->AllocateOutputs(); typedef CastImageFilter CTI; typename CTI::Pointer casti = CTI::New(); casti->SetInput(ci); casti->GraftOutput(this->GetOutput()); casti->Update(); this->GraftOutput(casti->GetOutput()); } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter.cxx0000664000175000017500000000226211757446472030516 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsGradientMagnitudeRecursiveGaussianImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkHessianToObjectnessMeasureImageFilter.h0000664000175000017500000001447511757446472025516 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkHessianToObjectnessMeasureImageFilter.h,v $ Language: C++ Date: $Date: 2009-07-01 12:43:38 $ Version: $Revision: 1.6 $ 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 __itkHessianToObjectnessMeasureImageFilter_h #define __itkHessianToObjectnessMeasureImageFilter_h #include "itkSymmetricSecondRankTensor.h" #include "itkSymmetricEigenAnalysisImageFilter.h" namespace itk { /** \class HessianToObjectnessMeasureImageFilter * \brief A filter to enhance M-dimensional objects in N-dimensional images * * The objectness measure is a generalization of Frangi's vesselness measure, * which is based on the analysis of the the Hessian eigen system. The filter * can enhance blob-like structures (M=0), vessel-like structures (M=1), 2D * plate-like structures (M=2), hyper-plate-like structures (M=3) in N-dimensional * images, with M class ITK_EXPORT HessianToObjectnessMeasureImageFilter : public ImageToImageFilter< TInputImage,TOutputImage> { public: /** Standard class typedefs. */ typedef HessianToObjectnessMeasureImageFilter Self; typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef typename OutputImageType::PixelType OutputPixelType; typedef typename OutputImageType::RegionType OutputImageRegionType; /** Image dimension */ itkStaticConstMacro(ImageDimension, unsigned int, ::itk::GetImageDimension::ImageDimension); typedef double EigenValueType; typedef itk::FixedArray< EigenValueType, itkGetStaticConstMacro( ImageDimension ) > EigenValueArrayType; typedef itk::Image< EigenValueArrayType, itkGetStaticConstMacro( ImageDimension ) > EigenValueImageType; typedef SymmetricEigenAnalysisImageFilter< InputImageType, EigenValueImageType > EigenAnalysisFilterType; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Set/Get Alpha, the weight corresponding to R_A * (the ratio of the smallest eigenvalue that has to be large to the larger ones). * Smaller values lead to increased sensitivity to the object dimensionality. */ itkSetMacro(Alpha,double); itkGetConstMacro(Alpha,double); /** Set/Get Beta, the weight corresponding to R_B * (the ratio of the largest eigenvalue that has to be small to the larger ones). * Smaller values lead to increased sensitivity to the object dimensionality. */ itkSetMacro(Beta,double); itkGetConstMacro(Beta,double); /** Set/Get Gamma, the weight corresponding to S * (the Frobenius norm of the Hessian matrix, or second-order structureness) */ itkSetMacro(Gamma,double); itkGetConstMacro(Gamma,double); /** Toggle scaling the objectness measure with the magnitude of the largest absolute eigenvalue */ itkSetMacro(ScaleObjectnessMeasure,bool); itkGetConstMacro(ScaleObjectnessMeasure,bool); itkBooleanMacro(ScaleObjectnessMeasure); /** Set/Get the dimensionality of the object (0: points (blobs), * 1: lines (vessels), 2: planes (plate-like structures), 3: hyper-planes. * ObjectDimension must be smaller than ImageDimension. */ itkSetMacro(ObjectDimension,unsigned int); itkGetConstMacro(ObjectDimension,unsigned int); /** Enhance bright structures on a dark background if true, the opposite if false. */ itkSetMacro(BrightObject,bool); itkGetConstMacro(BrightObject,bool); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(DoubleConvertibleToOutputCheck,(Concept::Convertible)); /** End concept checking */ #endif protected: HessianToObjectnessMeasureImageFilter(); ~HessianToObjectnessMeasureImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; /** Threaded Generate Data */ void BeforeThreadedGenerateData (); void ThreadedGenerateData ( const OutputImageRegionType &outputRegionForThread, int threadId); private: HessianToObjectnessMeasureImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented typename EigenAnalysisFilterType::Pointer m_SymmetricEigenValueFilter; double m_Alpha; double m_Beta; double m_Gamma; unsigned int m_ObjectDimension; bool m_BrightObject; bool m_ScaleObjectnessMeasure; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkHessianToObjectnessMeasureImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkUpwindGradientMagnitudeImageFilter.h0000664000175000017500000000450111757446472025745 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUpwindGradientMagnitudeImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUpwindGradientMagnitudeImageFilter - Wrapper class around itk::UpwindGradientMagnitudeImageFilter // .SECTION Description // vtkvmtkUpwindGradientMagnitudeImageFilter #ifndef __vtkvmtkUpwindGradientMagnitudeImageFilter_h #define __vtkvmtkUpwindGradientMagnitudeImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkUpwindGradientMagnitudeImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkUpwindGradientMagnitudeImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkUpwindGradientMagnitudeImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkUpwindGradientMagnitudeImageFilter, vtkvmtkITKImageToImageFilterFF); void SetUpwindFactor ( float value ) { DelegateITKInputMacro ( SetUpwindFactor, value ); }; protected: //BTX typedef itk::UpwindGradientMagnitudeImageFilter ImageFilterType; vtkvmtkUpwindGradientMagnitudeImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkUpwindGradientMagnitudeImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkUpwindGradientMagnitudeImageFilter(const vtkvmtkUpwindGradientMagnitudeImageFilter&); // Not implemented. void operator=(const vtkvmtkUpwindGradientMagnitudeImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkCollidingFrontsImageFilter.cxx0000664000175000017500000000214711757446472024642 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCollidingFrontsImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCollidingFrontsImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCollidingFrontsImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkCollidingFrontsImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkFastMarchingDirectionalFreezeImageFilter.h0000664000175000017500000001133011757446472026127 0ustar lucaluca/*========================================================================= 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::ImageDimension> > class ITK_EXPORT FastMarchingDirectionalFreezeImageFilter : public FastMarchingUpwindGradientImageFilter { public: /** Standard class typdedefs. */ typedef FastMarchingDirectionalFreezeImageFilter Self; typedef FastMarchingUpwindGradientImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer 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 SpeedGradientPixelType; /** SpeedGradientImage typedef support. */ typedef Image 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; void GenerateData(); void AllocateSpeedGradientImage(); void ComputeSpeedGradientImage(); GradientPixelType ComputeGradientValue( const IndexType& index , const LevelSetImageType * output); virtual void UpdateNeighbors( const IndexType& index, const SpeedImageType *, LevelSetImageType * ); 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 vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkObjectnessMeasureImageFilter.cxx0000664000175000017500000000215611757446472025163 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsObjectnessMeasureImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkObjectnessMeasureImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkObjectnessMeasureImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkActiveTubeFilter.cxx0000664000175000017500000004007311757446472022632 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkActiveTubeFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkActiveTubeFilter.h" #include "vtkvmtkCardinalSpline.h" #include "vtkvmtkConstants.h" #include "vtkMath.h" #include "vtkPolyData.h" #include "vtkImageData.h" #include "vtkPointData.h" #include "vtkImageGradient.h" #include "vtkDoubleArray.h" #include "vtkPolyLine.h" #include "vtkVoxel.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkActiveTubeFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkActiveTubeFilter); vtkvmtkActiveTubeFilter::vtkvmtkActiveTubeFilter() { this->RadiusArrayName = NULL; this->PotentialImage = NULL; this->PotentialGradientImage = NULL; this->NumberOfIterations = VTK_VMTK_LARGE_INTEGER; this->NumberOfAngularEvaluations = 16; this->Convergence = 1E-1; this->PotentialWeight = 1.0; this->StiffnessWeight = 1.0; this->CFLCoefficient = 0.1; this->PotentialMaxNorm = 0.0; this->MinimumRadius = 0.0; this->FixedEndpointCoordinates = 0; this->FixedEndpointRadius = 0; this->SplineResamplingWhileIterating = 1; this->NegativeNormWarnings = 0; } vtkvmtkActiveTubeFilter::~vtkvmtkActiveTubeFilter() { if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->PotentialImage) { this->PotentialImage->Delete(); this->PotentialImage = NULL; } if (this->PotentialGradientImage) { this->PotentialGradientImage->Delete(); this->PotentialGradientImage = NULL; } } vtkCxxSetObjectMacro(vtkvmtkActiveTubeFilter,PotentialImage,vtkImageData); void vtkvmtkActiveTubeFilter::EvaluateForce(double point[3], double force[3], bool normalize) { int ijk[3]; double pcoords[3]; double weights[8]; int inBounds; int i; force[0] = force[1] = force[2] = 0.0; inBounds = this->PotentialGradientImage->ComputeStructuredCoordinates(point,ijk,pcoords); if (!inBounds) { //vtkWarningMacro("Point out of extent"); return; } vtkCell* cell = this->PotentialGradientImage->GetCell(this->PotentialGradientImage->ComputeCellId(ijk)); if (cell->GetCellType() == VTK_VOXEL) { vtkVoxel::InterpolationFunctions(pcoords,weights); } else { vtkErrorMacro("Non voxel cell found in PotentialImage"); } int numberOfCellPoints = cell->GetNumberOfPoints(); vtkDataArray* gradientVectorsArray = this->PotentialGradientImage->GetPointData()->GetScalars(); for (i=0; iGetTuple(cell->GetPointId(i),vectorValue); force[0] += weights[i] * vectorValue[0]; force[1] += weights[i] * vectorValue[1]; force[2] += weights[i] * vectorValue[2]; } if (normalize && this->PotentialMaxNorm > VTK_VMTK_DOUBLE_TOL) { force[0] /= this->PotentialMaxNorm; force[1] /= this->PotentialMaxNorm; force[2] /= this->PotentialMaxNorm; } force[0] *= -1.0; force[1] *= -1.0; force[2] *= -1.0; } double vtkvmtkActiveTubeFilter::EvaluatePotential(double point[3]) { int ijk[3]; double pcoords[3]; double weights[8]; int inBounds; int i; double potential = 0.0; inBounds = this->PotentialImage->ComputeStructuredCoordinates(point,ijk,pcoords); if (!inBounds) { //vtkWarningMacro("Point out of extent"); return 0.0; } vtkCell* cell = this->PotentialImage->GetCell(this->PotentialImage->ComputeCellId(ijk)); if (cell->GetCellType() == VTK_VOXEL) { vtkVoxel::InterpolationFunctions(pcoords,weights); } else { vtkErrorMacro("Non voxel cell found in PotentialImage"); return 0.0; } int numberOfCellPoints = cell->GetNumberOfPoints(); vtkDataArray* potentialArray = this->PotentialImage->GetPointData()->GetScalars(); for (i=0; iGetTuple1(cell->GetPointId(i)); potential += weights[i] * value; } return potential; } void vtkvmtkActiveTubeFilter::EvolveCellSpline(vtkPolyData* lines, vtkIdType cellId) { //TODO: whip strategy - from start to end of spline, create displacement field simulating //inertia (i.e. force on a point dependent on displacement on previous point) vtkDataArray* radiusArray = lines->GetPointData()->GetArray(this->RadiusArrayName); vtkPolyLine* polyLine = vtkPolyLine::SafeDownCast(lines->GetCell(cellId)); if (!polyLine) { return; } vtkPoints* polyLinePoints = polyLine->GetPoints(); vtkvmtkCardinalSpline* xSpline = vtkvmtkCardinalSpline::New(); vtkvmtkCardinalSpline* ySpline = vtkvmtkCardinalSpline::New(); vtkvmtkCardinalSpline* zSpline = vtkvmtkCardinalSpline::New(); vtkvmtkCardinalSpline* rSpline = vtkvmtkCardinalSpline::New(); int numberOfPoints = polyLine->GetNumberOfPoints(); int numberOfSubIds = numberOfPoints - 1; double cellLength = 0.0; double point0[3], point1[3]; int i; for (i=0; iGetPoint(i,point0); polyLinePoints->GetPoint(i+1,point1); cellLength += sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); } xSpline->SetParametricRange(0.0,cellLength); ySpline->SetParametricRange(0.0,cellLength); zSpline->SetParametricRange(0.0,cellLength); rSpline->SetParametricRange(0.0,cellLength); vtkDoubleArray* parametricCoordinates = vtkDoubleArray::New(); parametricCoordinates->SetNumberOfTuples(numberOfPoints); double currentLength = 0.0; polyLinePoints->GetPoint(0,point0); double radius = radiusArray->GetTuple1(polyLine->GetPointId(0)); double t = 0.0; xSpline->AddPoint(0.0,point0[0]); ySpline->AddPoint(0.0,point0[1]); zSpline->AddPoint(0.0,point0[2]); rSpline->AddPoint(0.0,radius); parametricCoordinates->SetValue(0,0.0); for (i=1; iGetPoint(i-1,point0); polyLinePoints->GetPoint(i,point1); radius = radiusArray->GetTuple1(polyLine->GetPointId(i)); currentLength += sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); t = currentLength; xSpline->AddPoint(t,point1[0]); ySpline->AddPoint(t,point1[1]); zSpline->AddPoint(t,point1[2]); rSpline->AddPoint(t,radius); parametricCoordinates->SetValue(i,t); } if (this->SplineResamplingWhileIterating) { double point[3]; for (i=0; iEvaluate(t); point[1] = ySpline->Evaluate(t); point[2] = zSpline->Evaluate(t); radius = rSpline->Evaluate(t); polyLinePoints->SetPoint(i,point); radiusArray->SetTuple1(i,radius); parametricCoordinates->SetValue(i,t); } } vtkDoubleArray* probedForces = vtkDoubleArray::New(); probedForces->SetNumberOfComponents(3); probedForces->SetNumberOfTuples(this->NumberOfAngularEvaluations); vtkDoubleArray* tubeNormals = vtkDoubleArray::New(); tubeNormals->SetNumberOfComponents(3); tubeNormals->SetNumberOfTuples(this->NumberOfAngularEvaluations); vtkDoubleArray* dxArray = vtkDoubleArray::New(); dxArray->SetNumberOfTuples(numberOfPoints); dxArray->FillComponent(0,0.0); vtkDoubleArray* dyArray = vtkDoubleArray::New(); dyArray->SetNumberOfTuples(numberOfPoints); dyArray->FillComponent(0,0.0); vtkDoubleArray* dzArray = vtkDoubleArray::New(); dzArray->SetNumberOfTuples(numberOfPoints); dzArray->FillComponent(0,0.0); vtkDoubleArray* drArray = vtkDoubleArray::New(); drArray->SetNumberOfTuples(numberOfPoints); drArray->FillComponent(0,0.0); //TODO: choose numberOfLongitudinalEvaluations with a strategy // (fixed number, based on length, adaptive - higher curve or radius derivatives, more points) int numberOfLongitudinalEvaluations = numberOfPoints * 3 / 2; for (i=0; iEvaluate(t); double y = ySpline->Evaluate(t); double z = zSpline->Evaluate(t); double r = rSpline->Evaluate(t); double xp = xSpline->EvaluateDerivative(t); double yp = ySpline->EvaluateDerivative(t); double zp = zSpline->EvaluateDerivative(t); double rp = rSpline->EvaluateDerivative(t); double xpp = xSpline->EvaluateSecondDerivative(t); double ypp = ySpline->EvaluateSecondDerivative(t); double zpp = zSpline->EvaluateSecondDerivative(t); double rpp = rSpline->EvaluateSecondDerivative(t); double tangent[3], normal[3]; tangent[0] = xp; tangent[1] = yp; tangent[2] = zp; double tubeNormSquared = xp * xp + yp * yp + zp * zp - rp * rp; //if (tubeNormSquared < 0.0) if (tubeNormSquared <= 0.0) { if (this->NegativeNormWarnings) { vtkWarningMacro("Negative tubeNormSquared. Skipping."); } continue; } double tubeNorm = sqrt(tubeNormSquared); double isotropicForce = 0.0; double anisotropicForce[3]; anisotropicForce[0] = anisotropicForce[1] = anisotropicForce[2] = 0.0; double tubeNormal[3], probePoint[3], probedForce[3]; double theta; int j; for (j=0; jNumberOfAngularEvaluations; j++) { theta = j * 2.0 * vtkMath::Pi() / this->NumberOfAngularEvaluations; vtkMath::Perpendiculars(tangent,normal,NULL,theta); tubeNormal[0] = - tangent[0] * rp + normal[0] * tubeNorm; tubeNormal[1] = - tangent[1] * rp + normal[1] * tubeNorm; tubeNormal[2] = - tangent[2] * rp + normal[2] * tubeNorm; //optional, but better be on the safe side vtkMath::Normalize(tubeNormal); probePoint[0] = x + tubeNormal[0] * r; probePoint[1] = y + tubeNormal[1] * r; probePoint[2] = z + tubeNormal[2] * r; //double probedPotential = this->EvaluatePotential(probePoint); this->EvaluateForce(probePoint,probedForce,false); probedForces->SetTuple(j,probedForce); tubeNormals->SetTuple(j,tubeNormal); isotropicForce += vtkMath::Dot(probedForce,tubeNormal); } isotropicForce /= this->NumberOfAngularEvaluations; for (j=0; jNumberOfAngularEvaluations; j++) { probedForces->GetTuple(j,probedForce); tubeNormals->GetTuple(j,tubeNormal); anisotropicForce[0] += probedForce[0] - tubeNormal[0] * isotropicForce; anisotropicForce[1] += probedForce[1] - tubeNormal[1] * isotropicForce; anisotropicForce[2] += probedForce[2] - tubeNormal[2] * isotropicForce; } anisotropicForce[0] /= this->NumberOfAngularEvaluations; anisotropicForce[1] /= this->NumberOfAngularEvaluations; anisotropicForce[2] /= this->NumberOfAngularEvaluations; //TODO: define influence (based on parametric distance? Or also consider derivatives?) // implement Gaussian RBF? for (j=0; jGetValue(j); double influence = 0.1 * cellLength; if (fabs(parametricCoordinate-t) > influence) { continue; } double weight = (influence - fabs(parametricCoordinate-t)) / influence; double dx, dy, dz, dr; dx = dxArray->GetValue(j); dy = dyArray->GetValue(j); dz = dzArray->GetValue(j); dr = drArray->GetValue(j); dx += anisotropicForce[0] * weight * this->PotentialWeight; dy += anisotropicForce[1] * weight * this->PotentialWeight; dz += anisotropicForce[2] * weight * this->PotentialWeight; dr += isotropicForce * weight * this->PotentialWeight; dx += xpp * weight * this->StiffnessWeight; dy += ypp * weight * this->StiffnessWeight; dz += zpp * weight * this->StiffnessWeight; dr += rpp * weight * this->StiffnessWeight; dxArray->SetValue(j,dx); dyArray->SetValue(j,dy); dzArray->SetValue(j,dz); drArray->SetValue(j,dr); } } double spacing[3]; #if 0 if (this->PotientialImage) { this->PotentialImage->GetSpacing(spacing); } else #endif { this->PotentialGradientImage->GetSpacing(spacing); } double minSpacing = VTK_VMTK_LARGE_DOUBLE; for (i=0; i<3; i++) { minSpacing = spacing[i] < minSpacing ? spacing[i] : minSpacing; } double maxChange = 0.0; for (i=0; iGetValue(i); double dy = dyArray->GetValue(i); double dz = dzArray->GetValue(i); double dr = drArray->GetValue(i); double change = sqrt(dx*dx + dy*dy + dz*dz) + dr; maxChange = change > maxChange ? change : maxChange; } double timeStep; if (maxChange > 0.0) { timeStep = minSpacing / maxChange * this->CFLCoefficient; } else { timeStep = 0.0; } vtkIdType pointId; double point[3]; for (i=0; iGetPointId(i); polyLinePoints->GetPoint(i,point); radius = radiusArray->GetTuple1(pointId); point[0] += dxArray->GetValue(i) * timeStep; point[1] += dyArray->GetValue(i) * timeStep; point[2] += dzArray->GetValue(i) * timeStep; radius += drArray->GetValue(i) * timeStep; if (radius < this->MinimumRadius) { radius = this->MinimumRadius; } if (!(this->FixedEndpointCoordinates && (i==0 || i==numberOfPoints-1))) { lines->GetPoints()->SetPoint(pointId,point); } if (!(this->FixedEndpointRadius && (i==0 || i==numberOfPoints-1))) { radiusArray->SetTuple1(pointId,radius); } } //TODO: longitudinal evolution xSpline->Delete(); ySpline->Delete(); zSpline->Delete(); rSpline->Delete(); parametricCoordinates->Delete(); probedForces->Delete(); tubeNormals->Delete(); dxArray->Delete(); dyArray->Delete(); dzArray->Delete(); drArray->Delete(); } int vtkvmtkActiveTubeFilter::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())); output->DeepCopy(input); if (!this->RadiusArrayName) { vtkErrorMacro("Error: RadiusArrayName not specified."); return 0; } vtkDataArray* radiusArray = output->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { vtkErrorMacro("Error: RadiusArray with name specified does not exist."); return 0; } vtkImageGradient* gradientFilter = vtkImageGradient::New(); gradientFilter->SetInput(this->PotentialImage); gradientFilter->SetDimensionality(3); gradientFilter->Update(); if (this->PotentialGradientImage) { this->PotentialGradientImage->Delete(); this->PotentialGradientImage = NULL; } this->PotentialGradientImage = vtkImageData::New(); this->PotentialGradientImage->DeepCopy(gradientFilter->GetOutput()); this->PotentialMaxNorm = this->PotentialGradientImage->GetPointData()->GetScalars()->GetMaxNorm(); int numberOfCells = output->GetNumberOfCells(); int i; for (i=0; iNumberOfIterations; i++) { int c; for (c=0; cEvolveCellSpline(output,c); } } gradientFilter->Delete(); return 1; } void vtkvmtkActiveTubeFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkVesselnessMeasureImageFilter.h0000664000175000017500000001367711757446472024655 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkVesselnessMeasureImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkVesselnessMeasureImageFilter - Wrapper class around itk::VesselnessMeasureImageFilter // .SECTION Description // vtkvmtkVesselnessMeasureImageFilter #ifndef __vtkvmtkVesselnessMeasureImageFilter_h #define __vtkvmtkVesselnessMeasureImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkMultiScaleHessianBasedMeasureImageFilter.h" #include "itkHessianToObjectnessMeasureImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkVesselnessMeasureImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkVesselnessMeasureImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkVesselnessMeasureImageFilter, vtkvmtkITKImageToImageFilterFF); void SetSigmaMin(double value) { DelegateITKInputMacro(SetSigmaMinimum,value); } double GetSigmaMin() { DelegateITKOutputMacro(GetSigmaMinimum); } void SetSigmaMax(double value) { DelegateITKInputMacro(SetSigmaMaximum,value); } double GetSigmaMax() { DelegateITKOutputMacro(GetSigmaMaximum); } void SetNumberOfSigmaSteps(int value) { DelegateITKInputMacro(SetNumberOfSigmaSteps,value); } int GetNumberOfSigmaSteps() { DelegateITKOutputMacro(GetNumberOfSigmaSteps); } void SetSigmaStepMethodToEquispaced() { this->GetImageFilterPointer()->SetSigmaStepMethodToEquispaced(); this->Modified(); } void SetSigmaStepMethodToLogarithmic() { this->GetImageFilterPointer()->SetSigmaStepMethodToLogarithmic(); this->Modified(); } void SetAlpha(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetAlpha(value); this->Modified(); } } double GetAlpha() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetAlpha(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetBeta(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetBeta(value); this->Modified(); } } double GetBeta() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetBeta(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetGamma(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetGamma(value); this->Modified(); } } double GetGamma() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetGamma(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } protected: //BTX typedef itk::SymmetricSecondRankTensor HessianPixelType; typedef itk::Image HessianImageType; typedef itk::HessianToObjectnessMeasureImageFilter ObjectnessFilterType; typedef itk::MultiScaleHessianBasedMeasureImageFilter ImageFilterType; //typedef itk::HessianToObjectnessMeasureImageFilter ObjectnessFilterType; //typedef itk::MultiScaleHessianBasedMeasureImageFilter ImageFilterType; vtkvmtkVesselnessMeasureImageFilter() : Superclass(ImageFilterType::New()) { ObjectnessFilterType::Pointer objectnessFilter = ObjectnessFilterType::New(); objectnessFilter->SetScaleObjectnessMeasure(false); objectnessFilter->SetBrightObject(true); objectnessFilter->SetObjectDimension(1); ImageFilterType* imageFilter = this->GetImageFilterPointer(); imageFilter->SetSigmaStepMethodToEquispaced(); imageFilter->GenerateScalesOutputOn(); imageFilter->SetHessianToMeasureFilter(objectnessFilter); } ~vtkvmtkVesselnessMeasureImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast(m_Filter.GetPointer()); } //ETX private: vtkvmtkVesselnessMeasureImageFilter(const vtkvmtkVesselnessMeasureImageFilter&); // Not implemented. void operator=(const vtkvmtkVesselnessMeasureImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkLaplacianSegmentationLevelSetImageFilter.cxx0000664000175000017500000000223711757446472027450 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsLaplacianSegmentationLevelSetImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkLaplacianSegmentationLevelSetImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkLaplacianSegmentationLevelSetImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkRecursiveGaussianImageFilter.cxx0000664000175000017500000000215611757446472025204 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsRecursiveGaussianImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkRecursiveGaussianImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkRecursiveGaussianImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkRecursiveGaussianImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkHessianSmoothed3DToVesselnessMeasureImageFilter.h0000664000175000017500000001254311757446472027435 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkHessianSmoothed3DToVesselnessMeasureImageFilter.h,v $ Language: C++ Date: $Date: 2007/06/12 22:59:15 $ 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 __itkHessianSmoothed3DToVesselnessMeasureImageFilter_h #define __itkHessianSmoothed3DToVesselnessMeasureImageFilter_h #include "itkSymmetricSecondRankTensor.h" #include "itkSymmetricEigenAnalysisImageFilter.h" namespace itk { /** \class HessianSmoothed3DToVesselnessMeasureImageFilter * \brief A filter to enhance 3D vascular structures * * The vesselness measure is based on the analysis of the the Hessian * eigen system. The vesseleness function is a smoothed (continuous) * version of the Frang's vesselness function. The filter takes an * image of a Hessian pixels ( SymmetricSecondRankTensor pixels ) and * produces an enhanced image. The Hessian input image can be produced using * itkHessianSmoothedRecursiveGaussianImageFilter. * * * \par References * Manniesing, R, Viergever, MA, & Niessen, WJ (2006). Vessel Enhancing * Diffusion: A Scale Space Representation of Vessel Structures. Medical * Image Analysis, 10(6), 815-825. * * \sa MultiScaleHessianSmoothed3DToVesselnessMeasureImageFilter * \sa Hessian3DToVesselnessMeasureImageFilter * \sa HessianSmoothedRecursiveGaussianImageFilter * \sa SymmetricEigenAnalysisImageFilter * \sa SymmetricSecondRankTensor * * \ingroup IntensityImageFilters TensorObjects * */ template < typename TPixel > class ITK_EXPORT HessianSmoothed3DToVesselnessMeasureImageFilter : public ImageToImageFilter< Image< SymmetricSecondRankTensor< double, 3 >, 3 >, Image< TPixel, 3 > > { public: /** Standard class typedefs. */ typedef HessianSmoothed3DToVesselnessMeasureImageFilter Self; typedef ImageToImageFilter< Image< SymmetricSecondRankTensor< double, 3 >, 3 >, Image< TPixel, 3 > > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename InputImageType::PixelType InputPixelType; typedef TPixel OutputPixelType; /** Image dimension = 3. */ itkStaticConstMacro(ImageDimension, unsigned int, ::itk::GetImageDimension::ImageDimension); itkStaticConstMacro(InputPixelDimension, unsigned int, InputPixelType::Dimension); typedef FixedArray< double, itkGetStaticConstMacro(InputPixelDimension) > EigenValueArrayType; typedef Image< EigenValueArrayType, itkGetStaticConstMacro(ImageDimension) > EigenValueImageType; typedef SymmetricEigenAnalysisImageFilter< InputImageType, EigenValueImageType > EigenAnalysisFilterType; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Set/Get macros for Alpha */ itkSetMacro(Alpha, double); itkGetMacro(Alpha, double); /** Set/Get macros for Beta */ itkSetMacro(Beta, double); itkGetMacro(Beta, double); /** Set/Get macros for Gamma */ itkSetMacro(Gamma, double); itkGetMacro(Gamma, double); /** Set/Get macros for C */ itkSetMacro(C, double); itkGetMacro(C, double); /** Macro to scale the vesselness measure with the largest eigenvalue or not */ itkSetMacro( ScaleVesselnessMeasure, bool ); itkGetMacro( ScaleVesselnessMeasure, bool ); itkBooleanMacro(ScaleVesselnessMeasure); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(DoubleConvertibleToOutputCheck, (Concept::Convertible)); /** End concept checking */ #endif protected: HessianSmoothed3DToVesselnessMeasureImageFilter(); ~HessianSmoothed3DToVesselnessMeasureImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; /** Generate Data */ void GenerateData( void ); private: //purposely not implemented HessianSmoothed3DToVesselnessMeasureImageFilter(const Self&); void operator=(const Self&); //purposely not implemented typename EigenAnalysisFilterType::Pointer m_SymmetricEigenValueFilter; double m_Alpha; double m_Beta; double m_Gamma; double m_C; bool m_ScaleVesselnessMeasure; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkHessianSmoothed3DToVesselnessMeasureImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkBoundedReciprocalImageFilter.cxx0000664000175000017500000000215611757446472025126 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundedReciprocalImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkBoundedReciprocalImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkBoundedReciprocalImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkBoundedReciprocalImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkVesselnessMeasureImageFilter.cxx0000664000175000017500000000215611757446472025216 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsVesselnessMeasureImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkVesselnessMeasureImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkVesselnessMeasureImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkVesselnessMeasureImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkUpwindGradientMagnitudeImageFilter.h0000664000175000017500000001246411757446472025035 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: itkUpwindGradientMagnitudeImageFilter.h,v $ Language: C++ Date: $Date: 2005/10/06 11:03:26 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 __itkUpwindGradientMagnitudeImageFilter_h #define __itkUpwindGradientMagnitudeImageFilter_h #include "itkImageToImageFilter.h" #include "itkImage.h" namespace itk { /** \class UpwindGradientMagnitudeImageFilter * \brief Computes the gradient magnitude of an image region at each pixel. * * * \ingroup GradientFilters * * \sa Image * \sa Neighborhood * \sa NeighborhoodOperator * \sa NeighborhoodIterator */ template class ITK_EXPORT UpwindGradientMagnitudeImageFilter : public ImageToImageFilter< TInputImage, TOutputImage > { public: /** Standard class typedefs. */ typedef UpwindGradientMagnitudeImageFilter Self; typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro(UpwindGradientMagnitudeImageFilter, 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::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; /** UpwindGradientMagnitudeImageFilter needs a larger input requested * region than the output requested region (larger by the kernel * size to calculate derivatives). As such, * UpwindGradientMagnitudeImageFilter needs to provide an implementation * for GenerateInputRequestedRegion() in order to inform the * pipeline execution model. * * \sa ImageToImageFilter::GenerateInputRequestedRegion() */ virtual void GenerateInputRequestedRegion() throw(InvalidRequestedRegionError); /** Use the image spacing information in calculations. Use this option if you * want derivatives in physical space. Default is UseImageSpacingOn. */ void SetUseImageSpacingOn() { this->SetUseImageSpacing(true); } /** Ignore the image spacing. Use this option if you want derivatives in 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 upwind factor: 1.0 full upwind, 0.0 centered finite differences, -1.0 full downwind */ itkSetMacro(UpwindFactor, double); itkGetMacro(UpwindFactor, double); protected: UpwindGradientMagnitudeImageFilter() { m_UseImageSpacing = true; m_UpwindFactor = 1.0; } virtual ~UpwindGradientMagnitudeImageFilter() {} /** UpwindGradientMagnitudeImageFilter can be implemented as a * multithreaded filter. Therefore, this implementation provides a * ThreadedGenerateData() routine which is called for each * processing thread. The output image data is allocated * automatically by the superclass prior to calling * ThreadedGenerateData(). ThreadedGenerateData can only write to * the portion of the output image specified by the parameter * "outputRegionForThread" * * \sa ImageToImageFilter::ThreadedGenerateData(), * ImageToImageFilter::GenerateData() */ void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId ); void PrintSelf(std::ostream&, Indent) const; private: UpwindGradientMagnitudeImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented double m_UpwindFactor; bool m_UseImageSpacing; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkUpwindGradientMagnitudeImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGeodesicActiveContourLevelSetImageFilter.cxx0000664000175000017500000000223711757446472027436 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsGeodesicActiveContourLevelSetImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkGeodesicActiveContourLevelSetImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkGeodesicActiveContourLevelSetImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkGeodesicActiveContourLevelSetImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkPolyDataPotentialFit.cxx0000664000175000017500000004424211757446472023473 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataPotentialFit.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataPotentialFit.h" #include "vtkvmtkNeighborhoods.h" #include "vtkvmtkConstants.h" #include "vtkMath.h" #include "vtkPolyData.h" #include "vtkImageData.h" #include "vtkImageGradient.h" #include "vtkDoubleArray.h" #include "vtkVoxel.h" #include "vtkPixel.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyDataNormals.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataPotentialFit, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataPotentialFit); vtkvmtkPolyDataPotentialFit::vtkvmtkPolyDataPotentialFit() { this->PotentialImage = NULL; this->InflationImage = NULL; this->PotentialGradientImage = NULL; this->NumberOfIterations = VTK_VMTK_LARGE_INTEGER; this->TimeStep = 0.0; this->MaxDisplacementNorm = 0.0; this->MinEdgeLength = 0.0; this->Relaxation = 1.0; this->Displacements = NULL; this->MinPotentialSpacing = 0.0; this->Convergence = 1E-1; this->PotentialWeight = 0.0; this->StiffnessWeight = 0.0; this->InflationWeight = 0.0; this->PotentialMaxNorm = 0.0; this->UsePotentialInInflation = 1; this->InflationThreshold = 0.0; this->MaxTimeStep = 1.0; // pixels per time step this->AdaptiveTimeStep = 1; this->FlipNormals = 0; this->Dimensionality = 3; this->NumberOfStiffnessSubIterations = 5; this->NumberOfInflationSubIterations = 0; this->Neighborhoods = NULL; } vtkvmtkPolyDataPotentialFit::~vtkvmtkPolyDataPotentialFit() { if (this->PotentialImage) { this->PotentialImage->Delete(); this->PotentialImage = NULL; } if (this->InflationImage) { this->InflationImage->Delete(); this->InflationImage = NULL; } if (this->PotentialGradientImage) { this->PotentialGradientImage->Delete(); this->PotentialGradientImage = NULL; } if (this->Displacements) { this->Displacements->Delete(); this->Displacements = NULL; } if (this->Neighborhoods) { this->Neighborhoods->Delete(); this->Neighborhoods = NULL; } } vtkCxxSetObjectMacro(vtkvmtkPolyDataPotentialFit,PotentialImage,vtkImageData); vtkCxxSetObjectMacro(vtkvmtkPolyDataPotentialFit,InflationImage,vtkImageData); void vtkvmtkPolyDataPotentialFit::EvaluateForce(double point[3], double force[3], bool normalize) { int ijk[3]; double pcoords[3]; double weights[8]; int inBounds; int i; force[0] = force[1] = force[2] = 0.0; inBounds = this->PotentialGradientImage->ComputeStructuredCoordinates(point,ijk,pcoords); if (!inBounds) // if (!inBounds || !this->IsCellInExtent(this->PotentialGradientImage->GetExtent(),ijk,0)) { vtkWarningMacro("Point out of extent."); return; } vtkCell* cell = this->PotentialGradientImage->GetCell(this->PotentialGradientImage->ComputeCellId(ijk)); if (cell->GetCellType() == VTK_VOXEL) { vtkVoxel::InterpolationFunctions(pcoords,weights); } else if (cell->GetCellType() == VTK_PIXEL) { vtkPixel::InterpolationFunctions(pcoords,weights); } else { vtkErrorMacro("Non voxel or pixel cell found in PotentialImage"); } int numberOfCellPoints = cell->GetNumberOfPoints(); vtkDataArray* gradientVectorsArray = this->PotentialGradientImage->GetPointData()->GetScalars(); for (i=0; iGetTuple(cell->GetPointId(i),vectorValue); force[0] += weights[i] * vectorValue[0]; force[1] += weights[i] * vectorValue[1]; force[2] += weights[i] * vectorValue[2]; } if (normalize && this->PotentialMaxNorm > VTK_VMTK_DOUBLE_TOL) { force[0] /= this->PotentialMaxNorm; force[1] /= this->PotentialMaxNorm; force[2] /= this->PotentialMaxNorm; } force[0] *= -1.0; force[1] *= -1.0; force[2] *= -1.0; } double vtkvmtkPolyDataPotentialFit::EvaluatePotential(double point[3]) { int ijk[3]; double pcoords[3]; double weights[8]; int inBounds; int i; double potential = 0.0; inBounds = this->PotentialImage->ComputeStructuredCoordinates(point,ijk,pcoords); if (!inBounds) // if (!inBounds || !this->IsCellInExtent(this->PotentialImage->GetExtent(),ijk,0)) { vtkWarningMacro("Point out of extent."); return 0.0; } vtkCell* cell = this->PotentialImage->GetCell(this->PotentialImage->ComputeCellId(ijk)); if (cell->GetCellType() == VTK_VOXEL) { vtkVoxel::InterpolationFunctions(pcoords,weights); } else if (cell->GetCellType() == VTK_PIXEL) { vtkPixel::InterpolationFunctions(pcoords,weights); } else { vtkErrorMacro("Non voxel or pixel cell found in PotentialImage"); return 0.0; } int numberOfCellPoints = cell->GetNumberOfPoints(); vtkDataArray* potentialArray = this->PotentialImage->GetPointData()->GetScalars(); for (i=0; iGetTuple1(cell->GetPointId(i)); potential += weights[i] * value; } return potential; } double vtkvmtkPolyDataPotentialFit::EvaluateInflation(double point[3]) { if (this->InflationImage == NULL) { return 1.0; } int ijk[3]; double pcoords[3]; double weights[8]; int inBounds; int i; double inflation = 0.0; inBounds = this->InflationImage->ComputeStructuredCoordinates(point,ijk,pcoords); if (!inBounds) // if (!inBounds || !this->IsCellInExtent(this->PotentialImage->GetExtent(),ijk,0)) { vtkWarningMacro("Point out of extent."); return 0.0; } vtkCell* cell = this->InflationImage->GetCell(this->InflationImage->ComputeCellId(ijk)); if (cell->GetCellType() == VTK_VOXEL) { vtkVoxel::InterpolationFunctions(pcoords,weights); } else if (cell->GetCellType() == VTK_PIXEL) { vtkPixel::InterpolationFunctions(pcoords,weights); } else { vtkErrorMacro("Non voxel or pixel cell found in PotentialImage"); return 0.0; } int numberOfCellPoints = cell->GetNumberOfPoints(); vtkDataArray* inflationArray = this->InflationImage->GetPointData()->GetScalars(); for (i=0; iGetTuple1(cell->GetPointId(i)); inflation += weights[i] * value; } return inflation - this->InflationThreshold; } void vtkvmtkPolyDataPotentialFit::ComputePotentialDisplacement(vtkIdType pointId, double potentialDisplacement[3]) { double point[3]; double force[3]; this->GetOutput()->GetPoint(pointId, point); this->EvaluateForce(point, force); potentialDisplacement[0] = force[0]; potentialDisplacement[1] = force[1]; potentialDisplacement[2] = force[2]; } void vtkvmtkPolyDataPotentialFit::ComputeStiffnessDisplacement(vtkIdType pointId, double stiffnessDisplacement[3]) { vtkIdType j; double point[3]; double laplacianPoint[3], neighborhoodPoint[3]; vtkIdType numberOfNeighborhoodPoints; vtkvmtkNeighborhood *neighborhood; vtkPolyData *output; output = this->GetOutput(); neighborhood = this->Neighborhoods->GetNeighborhood(pointId); output->GetPoint(pointId,point); stiffnessDisplacement[0] = stiffnessDisplacement[1] = stiffnessDisplacement[2] = 0.0; // double weight; // double weightSum; // weightSum = 0.0; laplacianPoint[0] = laplacianPoint[1] = laplacianPoint[2] = 0.0; numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); for (j=0; jGetPoint(neighborhood->GetPointId(j),neighborhoodPoint); laplacianPoint[0] += neighborhoodPoint[0]; laplacianPoint[1] += neighborhoodPoint[1]; laplacianPoint[2] += neighborhoodPoint[2]; // weight = fabs(neighborhoodPoint[2] - point[2]); // laplacianPoint[0] += weight * neighborhoodPoint[0]; // laplacianPoint[1] += weight * neighborhoodPoint[1]; // laplacianPoint[2] += weight * neighborhoodPoint[2]; // weightSum += weight; } laplacianPoint[0] /= (double)numberOfNeighborhoodPoints; laplacianPoint[1] /= (double)numberOfNeighborhoodPoints; laplacianPoint[2] /= (double)numberOfNeighborhoodPoints; // laplacianPoint[0] /= weightSum; // laplacianPoint[1] /= weightSum; // laplacianPoint[2] /= weightSum; stiffnessDisplacement[0] = laplacianPoint[0] - point[0]; stiffnessDisplacement[1] = laplacianPoint[1] - point[1]; stiffnessDisplacement[2] = laplacianPoint[2] - point[2]; } void vtkvmtkPolyDataPotentialFit::ComputeInflationDisplacement(vtkIdType pointId, double inflationDisplacement[3]) { vtkIdType j; double point[3], inputOutwardNormal[3]; double neighborhoodVector[3], firstNeighborhoodVector[3]; double cross[3], neighborhoodNormal[3]; double neighborhoodPoint[3]; double dot; vtkIdType numberOfNeighborhoodPoints; vtkvmtkNeighborhood *neighborhood; vtkPolyData *output; output = this->GetOutput(); neighborhood = this->Neighborhoods->GetNeighborhood(pointId); if (neighborhood->GetNumberOfPoints() == 0) { inflationDisplacement[0] = 0.0; inflationDisplacement[1] = 0.0; inflationDisplacement[2] = 0.0; return; } output->GetPoint(pointId,point); this->Normals->GetTuple(pointId,inputOutwardNormal); double inflation = this->EvaluateInflation(point); double potential = 1.0; if (this->UsePotentialInInflation) { potential = this->EvaluatePotential(point); } neighborhoodNormal[0] = 0.0; neighborhoodNormal[1] = 0.0; neighborhoodNormal[2] = 0.0; output->GetPoint(neighborhood->GetPointId(0),neighborhoodPoint); firstNeighborhoodVector[0] = neighborhoodPoint[0] - point[0]; firstNeighborhoodVector[1] = neighborhoodPoint[1] - point[1]; firstNeighborhoodVector[2] = neighborhoodPoint[2] - point[2]; numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); for (j=1; jGetPoint(neighborhood->GetPointId(j),neighborhoodPoint); neighborhoodVector[0] = neighborhoodPoint[0] - point[0]; neighborhoodVector[1] = neighborhoodPoint[1] - point[1]; neighborhoodVector[2] = neighborhoodPoint[2] - point[2]; vtkMath::Cross(firstNeighborhoodVector,neighborhoodVector,cross); neighborhoodNormal[0] += cross[0]; neighborhoodNormal[1] += cross[1]; neighborhoodNormal[2] += cross[2]; } vtkMath::Normalize(neighborhoodNormal); dot = vtkMath::Dot(inputOutwardNormal,neighborhoodNormal); if (dot < 0.0) { neighborhoodNormal[0] *= -1.0; neighborhoodNormal[1] *= -1.0; neighborhoodNormal[2] *= -1.0; } inflationDisplacement[0] = inflation * potential * neighborhoodNormal[0]; inflationDisplacement[1] = inflation * potential * neighborhoodNormal[1]; inflationDisplacement[2] = inflation * potential * neighborhoodNormal[2]; } void vtkvmtkPolyDataPotentialFit::ComputeDisplacements(bool potential, bool stiffness, bool inflation) { vtkIdType i; vtkIdType numberOfPoints; double displacement[3]; double potentialDisplacement[3]; double stiffnessDisplacement[3]; double inflationDisplacement[3]; double displacementNorm; numberOfPoints = this->GetOutput()->GetNumberOfPoints(); this->MaxDisplacementNorm = 0.0; for (i=0; iComputePotentialDisplacement(i, potentialDisplacement); displacement[0] += this->PotentialWeight * potentialDisplacement[0]; displacement[1] += this->PotentialWeight * potentialDisplacement[1]; displacement[2] += this->PotentialWeight * potentialDisplacement[2]; } if (stiffness) { this->ComputeStiffnessDisplacement(i, stiffnessDisplacement); displacement[0] += this->StiffnessWeight * stiffnessDisplacement[0]; displacement[1] += this->StiffnessWeight * stiffnessDisplacement[1]; displacement[2] += this->StiffnessWeight * stiffnessDisplacement[2]; } if (inflation) { this->ComputeInflationDisplacement(i, inflationDisplacement); displacement[0] += this->InflationWeight * inflationDisplacement[0]; displacement[1] += this->InflationWeight * inflationDisplacement[1]; displacement[2] += this->InflationWeight * inflationDisplacement[2]; } this->Displacements->SetTuple(i, displacement); displacementNorm = vtkMath::Norm(displacement); if (displacementNorm > this->MaxDisplacementNorm) { this->MaxDisplacementNorm = displacementNorm; } } } void vtkvmtkPolyDataPotentialFit::ComputeTimeStep() { if (!this->AdaptiveTimeStep) { return; } if (this->MaxDisplacementNorm > VTK_VMTK_DOUBLE_TOL) { this->TimeStep = this->MinPotentialSpacing / this->MaxDisplacementNorm; if (this->TimeStep > this->MaxTimeStep) { this->TimeStep = this->MaxTimeStep; } } else { this->TimeStep = this->MaxTimeStep; } } void vtkvmtkPolyDataPotentialFit::ApplyDisplacements() { vtkIdType i; vtkIdType numberOfPoints; double point[3], displacement[3], newPoint[3]; vtkPoints *points; points = this->GetOutput()->GetPoints(); numberOfPoints = points->GetNumberOfPoints(); for (i=0; iGetPoint(i,point); this->Displacements->GetTuple(i,displacement); newPoint[0] = point[0] + this->Relaxation * this->TimeStep * displacement[0]; newPoint[1] = point[1] + this->Relaxation * this->TimeStep * displacement[1]; newPoint[2] = point[2] + this->Relaxation * this->TimeStep * displacement[2]; points->SetPoint(i,newPoint); } } double vtkvmtkPolyDataPotentialFit::ComputeMinSpacing(double spacing[3]) { double minSpacing; minSpacing = (spacing[0] < spacing[1]) && (spacing[0] < spacing[2]) ? spacing[0] : (spacing[1] < spacing[2]) ? spacing[1] : spacing[2]; return minSpacing; } int vtkvmtkPolyDataPotentialFit::TestConvergence() { return this->TimeStep * this->MaxDisplacementNorm < this->Convergence ? 1 : 0; } int vtkvmtkPolyDataPotentialFit::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())); bool potential, stiffness, inflation; vtkIdType n, m; vtkIdType numberOfPoints; vtkPoints *newPoints; numberOfPoints = input->GetNumberOfPoints(); newPoints = vtkPoints::New(); newPoints->DeepCopy(input->GetPoints()); if (this->Displacements) { this->Displacements->Delete(); this->Displacements = NULL; } this->Displacements = vtkDoubleArray::New(); this->Displacements->SetNumberOfComponents(3); this->Displacements->SetNumberOfTuples(numberOfPoints); vtkImageGradient* gradientFilter = vtkImageGradient::New(); gradientFilter->SetInput(this->PotentialImage); gradientFilter->SetDimensionality(this->Dimensionality); gradientFilter->Update(); if (this->PotentialGradientImage) { this->PotentialGradientImage->Delete(); this->PotentialGradientImage = NULL; } this->PotentialGradientImage = vtkImageData::New(); this->PotentialGradientImage->DeepCopy(gradientFilter->GetOutput()); gradientFilter->Delete(); output->SetPoints(newPoints); output->SetVerts(input->GetVerts()); output->SetLines(input->GetLines()); output->SetPolys(input->GetPolys()); output->SetStrips(input->GetStrips()); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); newPoints->Delete(); if (this->Neighborhoods) { this->Neighborhoods->Delete(); this->Neighborhoods = NULL; } this->Neighborhoods = vtkvmtkNeighborhoods::New(); this->Neighborhoods->SetNeighborhoodTypeToPolyDataManifoldNeighborhood(); this->Neighborhoods->SetDataSet(input); this->Neighborhoods->Build(); vtkPolyDataNormals* surfaceNormals = vtkPolyDataNormals::New(); surfaceNormals->SetInput(input); surfaceNormals->SplittingOff(); surfaceNormals->AutoOrientNormalsOn(); surfaceNormals->SetFlipNormals(this->FlipNormals); surfaceNormals->ComputePointNormalsOn(); surfaceNormals->ConsistencyOn(); surfaceNormals->Update(); this->Normals = surfaceNormals->GetOutput()->GetPointData()->GetNormals(); this->MinPotentialSpacing = this->ComputeMinSpacing(this->PotentialImage->GetSpacing()); this->PotentialMaxNorm = this->PotentialGradientImage->GetPointData()->GetScalars()->GetMaxNorm(); for (n=0; nNumberOfIterations; n++) { for (m=0; mNumberOfStiffnessSubIterations; m++) { potential = false; stiffness = true; inflation = false; this->ComputeDisplacements(potential, stiffness, inflation); this->ComputeTimeStep(); this->ApplyDisplacements(); } for (m=0; mNumberOfInflationSubIterations; m++) { potential = false; stiffness = false; inflation = true; this->ComputeDisplacements(potential, stiffness, inflation); this->ComputeTimeStep(); this->ApplyDisplacements(); } potential = true; stiffness = true; inflation = true; this->ComputeDisplacements(potential, stiffness, inflation); this->ComputeTimeStep(); this->ApplyDisplacements(); if (this->TestConvergence()) { break; } } surfaceNormals->Delete(); this->Normals = NULL; return 1; } void vtkvmtkPolyDataPotentialFit::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Segmentation/itkFWHMFeatureImageFilter.h0000664000175000017500000001043111757446472022320 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: itkFWHMFeatureImageFilter.h,v $ Language: C++ Date: $Date: 2005/03/04 11:14:37 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 class FWHMFeatureImageFilter : public ImageToImageFilter< TInputImage, TOutputImage > { public: /** Standard class typedefs. */ typedef FWHMFeatureImageFilter Self; typedef ImageToImageFilter< TInputImage, TOutputImage > Superclass; typedef SmartPointer Pointer; typedef SmartPointer 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::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 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(); void PrintSelf(std::ostream&, Indent) const; 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 vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkRecursiveGaussianImageFilter.h0000664000175000017500000000463011757446472024630 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkRecursiveGaussianImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkRecursiveGaussianImageFilter - Wrapper class around itk::RecursiveGaussianImageFilter // .SECTION Description // vtkvmtkImageFilter #ifndef __vtkvmtkRecursiveGaussianImageFilter_h #define __vtkvmtkRecursiveGaussianImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkRecursiveGaussianImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkRecursiveGaussianImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkRecursiveGaussianImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkRecursiveGaussianImageFilter, vtkvmtkITKImageToImageFilterFF); void SetSigma ( float value ) { DelegateITKInputMacro ( SetSigma, value ); }; void SetNormalizeAcrossScale ( int value ) { DelegateITKInputMacro ( SetNormalizeAcrossScale, value ); }; int GetNormalizeAcrossScale() { DelegateITKOutputMacro( GetNormalizeAcrossScale ); }; protected: //BTX typedef itk::RecursiveGaussianImageFilter ImageFilterType; vtkvmtkRecursiveGaussianImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkRecursiveGaussianImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkRecursiveGaussianImageFilter(const vtkvmtkRecursiveGaussianImageFilter&); // Not implemented. void operator=(const vtkvmtkRecursiveGaussianImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkObjectnessMeasureImageFilter.h0000664000175000017500000001666211757446472024617 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkObjectnessMeasureImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkObjectnessMeasureImageFilter - Wrapper class around itk::ObjectnessMeasureImageFilter // .SECTION Description // vtkvmtkObjectnessMeasureImageFilter #ifndef __vtkvmtkObjectnessMeasureImageFilter_h #define __vtkvmtkObjectnessMeasureImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkMultiScaleHessianBasedMeasureImageFilter.h" #include "itkHessianToObjectnessMeasureImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkObjectnessMeasureImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkObjectnessMeasureImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkObjectnessMeasureImageFilter, vtkvmtkITKImageToImageFilterFF); void SetSigmaMin(double value) { DelegateITKInputMacro(SetSigmaMinimum,value); } double GetSigmaMin() { DelegateITKOutputMacro(GetSigmaMinimum); } void SetSigmaMax(double value) { DelegateITKInputMacro(SetSigmaMaximum,value); } double GetSigmaMax() { DelegateITKOutputMacro(GetSigmaMaximum); } void SetNumberOfSigmaSteps(int value) { DelegateITKInputMacro(SetNumberOfSigmaSteps,value); } int GetNumberOfSigmaSteps() { DelegateITKOutputMacro(GetNumberOfSigmaSteps); } void SetSigmaStepMethodToEquispaced() { this->GetImageFilterPointer()->SetSigmaStepMethodToEquispaced(); this->Modified(); } void SetSigmaStepMethodToLogarithmic() { this->GetImageFilterPointer()->SetSigmaStepMethodToLogarithmic(); this->Modified(); } void SetAlpha(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetAlpha(value); this->Modified(); } } double GetAlpha() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetAlpha(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetBeta(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetBeta(value); this->Modified(); } } double GetBeta() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetBeta(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetGamma(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetGamma(value); this->Modified(); } } double GetGamma() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetGamma(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetObjectDimension(int value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetHessianToMeasureFilter())->SetObjectDimension(value); this->Modified(); } } int GetObjectDimension() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetHessianToMeasureFilter())->GetObjectDimension(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0; } } unsigned long int GetMTime() { unsigned long int t1 = this->Superclass::GetMTime(); unsigned long int t2 = this->vtkScalesImporter->GetMTime(); if (t2 > t1) { t1 = t2; } return t1; } virtual vtkImageData *GetScalesOutput() { this->vtkScalesImporter->Update(); return this->vtkScalesImporter->GetOutput(); } protected: //BTX typedef itk::SymmetricSecondRankTensor HessianPixelType; typedef itk::Image HessianImageType; typedef itk::HessianToObjectnessMeasureImageFilter ObjectnessFilterType; typedef itk::MultiScaleHessianBasedMeasureImageFilter ImageFilterType; typedef ImageFilterType::ScalesImageType ScalesImageType; typedef itk::VTKImageExport ScalesImageExportType; vtkvmtkObjectnessMeasureImageFilter() : Superclass(ImageFilterType::New()) { this->itkScalesExporter = ScalesImageExportType::New(); this->vtkScalesImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkScalesImporter->SetScalarArrayName("Scalars_"); #endif ConnectPipelines(this->itkScalesExporter, this->vtkScalesImporter); ObjectnessFilterType::Pointer objectnessFilter = ObjectnessFilterType::New(); objectnessFilter->SetScaleObjectnessMeasure(false); objectnessFilter->SetBrightObject(true); ImageFilterType* imageFilter = this->GetImageFilterPointer(); imageFilter->SetSigmaStepMethodToEquispaced(); imageFilter->GenerateScalesOutputOn(); imageFilter->SetHessianToMeasureFilter(objectnessFilter); this->itkScalesExporter->SetInput(imageFilter->GetScalesOutput()); } ~vtkvmtkObjectnessMeasureImageFilter() { this->vtkScalesImporter->Delete(); } ImageFilterType* GetImageFilterPointer() { return dynamic_cast(m_Filter.GetPointer()); } ScalesImageExportType::Pointer itkScalesExporter; vtkImageImport* vtkScalesImporter; //ETX private: vtkvmtkObjectnessMeasureImageFilter(const vtkvmtkObjectnessMeasureImageFilter&); // Not implemented. void operator=(const vtkvmtkObjectnessMeasureImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkRecursiveGaussian2DImageFilter.h0000664000175000017500000000467011757446472025022 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkRecursiveGaussian2DImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkRecursiveGaussian2DImageFilter - Wrapper class around itk::RecursiveGaussian2DImageFilter // .SECTION Description // vtkvmtkImageFilter #ifndef __vtkvmtkRecursiveGaussian2DImageFilter_h #define __vtkvmtkRecursiveGaussian2DImageFilter_h #include "vtkvmtkITKImageToImageFilter2DFF.h" #include "itkRecursiveGaussianImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkRecursiveGaussian2DImageFilter : public vtkvmtkITKImageToImageFilter2DFF { public: static vtkvmtkRecursiveGaussian2DImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkRecursiveGaussian2DImageFilter, vtkvmtkITKImageToImageFilter2DFF); void SetSigma ( float value ) { DelegateITKInputMacro ( SetSigma, value ); }; void SetNormalizeAcrossScale ( int value ) { DelegateITKInputMacro ( SetNormalizeAcrossScale, value ); }; int GetNormalizeAcrossScale() { DelegateITKOutputMacro( GetNormalizeAcrossScale ); }; protected: //BTX typedef itk::RecursiveGaussianImageFilter ImageFilterType; vtkvmtkRecursiveGaussian2DImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkRecursiveGaussian2DImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkRecursiveGaussian2DImageFilter(const vtkvmtkRecursiveGaussian2DImageFilter&); // Not implemented. void operator=(const vtkvmtkRecursiveGaussian2DImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkFWHMFeatureImageFilter.cxx0000664000175000017500000000212711757446472023615 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsFWHMFeatureImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkFWHMFeatureImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkFWHMFeatureImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkFWHMFeatureImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGeodesicActiveContourLevelSet2DImageFilter.cxx0000664000175000017500000000224611757446472027624 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsGeodesicActiveContourLevelSet2DImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkGeodesicActiveContourLevelSet2DImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkGeodesicActiveContourLevelSet2DImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkGeodesicActiveContourLevelSet2DImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkAnisotropicDiffusionVesselEnhancementImageFilter.h0000664000175000017500000002524511757446472027745 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkAnisotropicDiffusionVesselEnhancementImageFilter.h,v $ Language: C++ Date: $Date: 2007/06/20 16:03:23 $ Version: $Revision: 1.15 $ 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 __itkAnisotropicDiffusionVesselEnhancementImageFilter_h #define __itkAnisotropicDiffusionVesselEnhancementImageFilter_h #include "itkFiniteDifferenceImageFilter.h" #include "itkHessianSmoothed3DToVesselnessMeasureImageFilter.h" #include "itkMultiScaleHessianBasedMeasureImageFilter.h" #include "itkAnisotropicDiffusionVesselEnhancementFunction.h" #include "itkMultiThreader.h" #include "itkSymmetricSecondRankTensor.h" #include "itkSymmetricEigenVectorAnalysisImageFilter.h" namespace itk { /** \class AnisotropicDiffusionVesselEnhancementFunction * \brief This class iteratively enhances vessels in an image by solving * non-linear diffusion equation developed by Manniesing et al. * * \par References * Manniesing, R, Viergever, MA, & Niessen, WJ (2006). Vessel Enhancing * Diffusion: A Scale Space Representation of Vessel Structures. Medical * Image Analysis, 10(6), 815-825. * * \sa AnisotropicDiffusionVesselEnhancementImageFilter * \ingroup FiniteDifferenceFunctions * \ingroup Functions */ template > class ITK_EXPORT AnisotropicDiffusionVesselEnhancementImageFilter : public FiniteDifferenceImageFilter { public: /** Standard class typedefs */ typedef AnisotropicDiffusionVesselEnhancementImageFilter Self; typedef FiniteDifferenceImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory */ itkNewMacro( Self ); /** Run-time type information (and related methods) */ itkTypeMacro(AnisotropicDiffusionVesselEnhancementImageFilter, ImageToImageFilter ); /** Convenient typedefs */ typedef typename Superclass::InputImageType InputImageType; typedef typename Superclass::OutputImageType OutputImageType; typedef typename Superclass::PixelType PixelType; /** Dimensionality of input and output data is assumed to be the same. * It is inherited from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int,Superclass::ImageDimension); typedef itk::Image< SymmetricSecondRankTensor< double, itkGetStaticConstMacro(ImageDimension) >, itkGetStaticConstMacro(ImageDimension) > DiffusionTensorImageType; typedef AnisotropicDiffusionVesselEnhancementFunction FiniteDifferenceFunctionType; typedef TVesselnessFilter VesselnessFilterType; typedef typename VesselnessFilterType::InputImageType HessianImageType; typedef typename VesselnessFilterType::OutputImageType VesselnessImageType; typedef itk::MultiScaleHessianBasedMeasureImageFilter MultiScaleVesselnessFilterType; typedef itk::Matrix MatrixType; // Define image of matrix pixel type typedef itk::Image< MatrixType, ImageDimension> OutputMatrixImageType; // Define the symmetric tensor pixel type typedef itk::SymmetricSecondRankTensor< double, ImageDimension> TensorPixelType; typedef itk::Image< TensorPixelType, ImageDimension> TensorImageType; // Define the type for storing the eigen-value typedef itk::FixedArray< double, ImageDimension > EigenValueArrayType; // Declare the types of the output images typedef itk::Image< EigenValueArrayType, ImageDimension > EigenAnalysisOutputImageType; // Declare the type for the filter typedef itk::SymmetricEigenVectorAnalysisImageFilter< TensorImageType, EigenAnalysisOutputImageType, OutputMatrixImageType > EigenVectorMatrixAnalysisFilterType; /** The value type of a time step. Inherited from the superclass. */ typedef typename Superclass::TimeStepType TimeStepType; /** The container type for the update buffer. */ typedef OutputImageType UpdateBufferType; /** Define diffusion image nbd type */ typedef typename FiniteDifferenceFunctionType::DiffusionTensorNeighborhoodType DiffusionTensorNeighborhoodType; /** Get the filter used to compute the Hessian based measure */ MultiScaleVesselnessFilterType* GetMultiScaleVesselnessFilter() { return m_MultiScaleVesselnessFilter; } /** Set/Get Macro for VED parameters */ itkSetMacro( TimeStep, double ); itkSetMacro( Epsilon, double ); itkSetMacro( WStrength, double ); itkSetMacro( Sensitivity, double ); itkGetMacro( TimeStep, double ); itkGetMacro( Epsilon, double ); itkGetMacro( WStrength, double ); itkGetMacro( Sensitivity, double ); itkSetMacro( NumberOfDiffusionSubIterations, unsigned int ); itkGetMacro( NumberOfDiffusionSubIterations, unsigned int ); #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(OutputTimesDoubleCheck, (Concept::MultiplyOperator)); itkConceptMacro(OutputAdditiveOperatorsCheck, (Concept::AdditiveOperators)); itkConceptMacro(InputConvertibleToOutputCheck, (Concept::Convertible)); /** End concept checking */ #endif protected: AnisotropicDiffusionVesselEnhancementImageFilter(); ~AnisotropicDiffusionVesselEnhancementImageFilter() {} void PrintSelf(std::ostream& os, Indent indent) const; /* overloaded GenerateData method */ virtual void GenerateData(); /** A simple method to copy the data from the input to the output. ( Supports * "read-only" image adaptors in the case where the input image type converts * to a different output image type. ) */ virtual void CopyInputToOutput(); /** This method applies changes from the m_UpdateBuffer to the output using * the ThreadedApplyUpdate() method and a multithreading mechanism. "dt" is * the time step to use for the update of each pixel. */ virtual void ApplyUpdate(TimeStepType dt); /** Method to allow subclasses to get direct access to the update * buffer */ virtual UpdateBufferType* GetUpdateBuffer() { return m_UpdateBuffer; } /** This method populates an update buffer with changes for each pixel in the * output using the ThreadedCalculateChange() method and a multithreading * mechanism. Returns value is a time step to be used for the update. */ virtual TimeStepType CalculateChange(); /** This method allocates storage in m_UpdateBuffer. It is called from * Superclass::GenerateData(). */ virtual void AllocateUpdateBuffer(); /** This method allocates storage for the diffusion tensor image */ void AllocateDiffusionTensorImage(); /** Update diffusion tensor image */ void UpdateDiffusionTensorImage(); /** The type of region used for multithreading */ typedef typename UpdateBufferType::RegionType ThreadRegionType; /** The type of region used for multithreading */ typedef typename DiffusionTensorImageType::RegionType ThreadDiffusionImageRegionType; /** Does the actual work of updating the output from the UpdateContainer * over an output region supplied by the multithreading mechanism. * \sa ApplyUpdate * \sa ApplyUpdateThreaderCallback */ virtual void ThreadedApplyUpdate( TimeStepType dt, const ThreadRegionType ®ionToProcess, const ThreadDiffusionImageRegionType &diffusionRegionToProcess, int threadId); /** Does the actual work of calculating change over a region supplied by * the multithreading mechanism. * \sa CalculateChange * \sa CalculateChangeThreaderCallback */ virtual TimeStepType ThreadedCalculateChange( const ThreadRegionType ®ionToProcess, const ThreadDiffusionImageRegionType &diffusionRegionToProcess, int threadId); /** Prepare for the iteration process. */ virtual void InitializeIteration(); private: //purposely not implemented AnisotropicDiffusionVesselEnhancementImageFilter(const Self&); void operator=(const Self&); //purposely not implemented /** Structure for passing information into static callback methods. Used in * the subclasses' threading mechanisms. */ struct DenseFDThreadStruct { AnisotropicDiffusionVesselEnhancementImageFilter *Filter; TimeStepType TimeStep; TimeStepType *TimeStepList; bool *ValidTimeStepList; }; /** This callback method uses ImageSource::SplitRequestedRegion to acquire an * output region that it passes to ThreadedApplyUpdate for processing. */ static ITK_THREAD_RETURN_TYPE ApplyUpdateThreaderCallback( void *arg ); /** This callback method uses SplitUpdateContainer to acquire a region * which it then passes to ThreadedCalculateChange for processing. */ static ITK_THREAD_RETURN_TYPE CalculateChangeThreaderCallback( void *arg ); /** The buffer that holds the updates for an iteration of the algorithm. */ typename UpdateBufferType::Pointer m_UpdateBuffer; TimeStepType m_TimeStep; typename DiffusionTensorImageType::Pointer m_DiffusionTensorImage; typename MultiScaleVesselnessFilterType::Pointer m_MultiScaleVesselnessFilter; typename EigenVectorMatrixAnalysisFilterType::Pointer m_EigenVectorMatrixAnalysisFilter; // Vesselness guided diffusion parameters double m_Epsilon; double m_WStrength; double m_Sensitivity; unsigned int m_NumberOfDiffusionSubIterations; }; }// end namespace itk #if ITK_TEMPLATE_TXX # include "itkAnisotropicDiffusionVesselEnhancementImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkFastMarchingUpwindGradientImageFilter.cxx0000664000175000017500000000222311757446472026750 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFastMarchingUpwindGradientImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkFastMarchingUpwindGradientImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkFastMarchingUpwindGradientImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkFastMarchingUpwindGradientImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkPolyDataPotentialFit.h0000664000175000017500000001231711757446472023116 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataPotentialFit.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataPotentialFit - ... // .SECTION Description // . #ifndef __vtkvmtkPolyDataPotentialFit_h #define __vtkvmtkPolyDataPotentialFit_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class vtkImageData; class vtkDoubleArray; class vtkvmtkNeighborhoods; class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkPolyDataPotentialFit : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataPotentialFit,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataPotentialFit *New(); virtual void SetPotentialImage(vtkImageData *); vtkGetObjectMacro(PotentialImage, vtkImageData); virtual void SetInflationImage(vtkImageData *); vtkGetObjectMacro(InflationImage, vtkImageData); vtkSetMacro(InflationThreshold, double); vtkGetMacro(InflationThreshold, double); vtkSetMacro(NumberOfIterations, int); vtkGetMacro(NumberOfIterations, int); vtkSetMacro(NumberOfStiffnessSubIterations, int); vtkGetMacro(NumberOfStiffnessSubIterations, int); vtkSetMacro(NumberOfInflationSubIterations, int); vtkGetMacro(NumberOfInflationSubIterations, int); vtkSetMacro(Relaxation, double); vtkGetMacro(Relaxation, double); vtkSetMacro(PotentialWeight, double); vtkGetMacro(PotentialWeight, double); vtkSetMacro(StiffnessWeight, double); vtkGetMacro(StiffnessWeight, double); vtkSetMacro(InflationWeight, double); vtkGetMacro(InflationWeight, double); vtkSetMacro(Convergence, double); vtkGetMacro(Convergence, double); vtkSetMacro(MaxTimeStep, double); vtkGetMacro(MaxTimeStep, double); vtkSetMacro(TimeStep, double); vtkGetMacro(TimeStep, double); vtkSetMacro(AdaptiveTimeStep, int); vtkGetMacro(AdaptiveTimeStep, int); vtkBooleanMacro(AdaptiveTimeStep, int); vtkSetMacro(FlipNormals, int); vtkGetMacro(FlipNormals, int); vtkBooleanMacro(FlipNormals, int); vtkSetMacro(UsePotentialInInflation, int); vtkGetMacro(UsePotentialInInflation, int); vtkBooleanMacro(UsePotentialInInflation, int); vtkSetMacro(Dimensionality, int); vtkGetMacro(Dimensionality, int); protected: vtkvmtkPolyDataPotentialFit(); ~vtkvmtkPolyDataPotentialFit(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void EvaluateForce(double point[3], double force[3], bool normalize = true); double EvaluatePotential(double point[3]); double EvaluateInflation(double point[3]); void ComputeDisplacements(bool potential, bool stiffness, bool inflation); void ComputePotentialDisplacement(vtkIdType pointId, double potentialDisplacement[3]); void ComputeStiffnessDisplacement(vtkIdType pointId, double stiffnessDisplacement[3]); void ComputeInflationDisplacement(vtkIdType pointId, double inflationDisplacement[3]); void ComputeTimeStep(); void ApplyDisplacements(); int TestConvergence(); static double ComputeMinSpacing(double spacing[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[2]+border && ijk[1]=extent[4]+border && ijk[2]vtkFeatureExporter->SetInput(value); } vtkImageData *GetSpeedImage() { this->vtkSpeedImporter->Update(); return this->vtkSpeedImporter->GetOutput(); } void SetFeatureScaling ( float value ) { DelegateITKInputMacro ( SetFeatureScaling, value ); }; float GetRMSChange () { DelegateITKOutputMacro(GetRMSChange); }; int GetElapsedIterations() { DelegateITKOutputMacro(GetElapsedIterations); }; float GetPropagationScaling ( ) { DelegateITKOutputMacro ( GetPropagationScaling ); }; float GetCurvatureScaling ( ) { DelegateITKOutputMacro ( GetCurvatureScaling ); }; float GetAdvectionScaling ( ) { DelegateITKOutputMacro ( GetAdvectionScaling ); }; int GetAutoGenerateSpeedAdvection ( ) { DelegateITKOutputMacro( GetAutoGenerateSpeedAdvection ); } int GetInterpolateSurfaceLocation ( ) { DelegateITKOutputMacro( GetInterpolateSurfaceLocation ); } float GetDerivativeSigma ( float value ) { DelegateITKOutputMacro ( GetDerivativeSigma ); }; // Description: Override vtkSource's Update so that we can access this class's GetOutput(). vtkSource's GetOutput is not virtual. void Update() { if (this->vtkFeatureExporter->GetInput()) { this->itkFeatureImporter->Update(); if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } } protected: //BTX typedef itk::GeodesicActiveContourLevelSetImageFilter ImageFilterType; typedef itk::VTKImageImport FeatureImageImportType; typedef itk::VTKImageExport SpeedImageExportType; vtkvmtkGeodesicActiveContourLevelSet2DImageFilter() : Superclass ( ImageFilterType::New() ) { this->vtkFeatureExporter = vtkImageExport::New(); this->itkFeatureImporter = FeatureImageImportType::New(); this->itkSpeedExporter = SpeedImageExportType::New(); this->vtkSpeedImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkSpeedImporter->SetScalarArrayName("Scalars_"); #endif ConnectPipelines(this->itkSpeedExporter, this->vtkSpeedImporter); ConnectPipelines(this->vtkFeatureExporter, this->itkFeatureImporter); (dynamic_cast(m_Filter.GetPointer()))->SetFeatureImage(this->itkFeatureImporter->GetOutput()); this->itkSpeedExporter->SetInput((dynamic_cast(m_Filter.GetPointer()))->GetSpeedImage()); }; ~vtkvmtkGeodesicActiveContourLevelSet2DImageFilter() { this->vtkFeatureExporter->Delete(); this->vtkSpeedImporter->Delete(); }; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } FeatureImageImportType::Pointer itkFeatureImporter; SpeedImageExportType::Pointer itkSpeedExporter; //ETX vtkImageExport *vtkFeatureExporter; vtkImageImport *vtkSpeedImporter; private: vtkvmtkGeodesicActiveContourLevelSet2DImageFilter(const vtkvmtkGeodesicActiveContourLevelSet2DImageFilter&); // Not implemented. void operator=(const vtkvmtkGeodesicActiveContourLevelSet2DImageFilter&); // // Not implemented }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkFWHMFeatureImageFilter.txx0000664000175000017500000000754211757446472022725 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: itkFWHMFeatureImageFilter.txx,v $ Language: C++ Date: $Date: 2005/03/04 11:14:37 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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_txx #define _itkFWHMFeatureImageFilter_txx #include "itkFWHMFeatureImageFilter.h" #include "itkGrayscaleDilateImageFilter.h" #include "itkSigmoidImageFilter.h" namespace itk { template FWHMFeatureImageFilter ::FWHMFeatureImageFilter() : m_UseImageSpacing( true ) { m_Radius.Fill(1); m_BackgroundValue = NumericTraits::Zero; } template< typename TInputImage, typename TOutputImage > void FWHMFeatureImageFilter< TInputImage, TOutputImage > ::GenerateData() { this->AllocateOutputs(); StructuringElementRadiusType radius = m_Radius; typedef itk::GrayscaleDilateImageFilter GrayscaleDilateFilterType; typename InputImageType::ConstPointer inputImage = this->GetInput(); StructuringElementType dilateStructuringElement; dilateStructuringElement.SetRadius(radius); dilateStructuringElement.CreateStructuringElement(); typename GrayscaleDilateFilterType::Pointer grayscaleDilateFilter = GrayscaleDilateFilterType::New(); grayscaleDilateFilter->SetInput(inputImage); grayscaleDilateFilter->SetKernel(dilateStructuringElement); grayscaleDilateFilter->Update(); typename OutputImageType::Pointer outputImage = this->GetOutput(); // build output image as sigmoid-filtered difference between pixel and half-maximum // using Sigmoid functor Function::Sigmoid sigmoid; sigmoid.SetAlpha(1.0/6.0); sigmoid.SetBeta(0.0); sigmoid.SetOutputMinimum(-1.0); sigmoid.SetOutputMaximum(1.0); ImageRegionConstIterator inputIt(inputImage, inputImage->GetBufferedRegion()); ImageRegionConstIterator dilateIt(grayscaleDilateFilter->GetOutput(), grayscaleDilateFilter->GetOutput()->GetBufferedRegion()); ImageRegionIterator outputIt(outputImage, outputImage->GetBufferedRegion()); inputIt.GoToBegin(); dilateIt.GoToBegin(); outputIt.GoToBegin(); while( !inputIt.IsAtEnd() || !dilateIt.IsAtEnd() || !outputIt.IsAtEnd()) { InputPixelType inputPixel = inputIt.Get(); InputPixelType inputPixelToBackgroundValue = inputPixel - m_BackgroundValue; InputPixelType dilatePixel = dilateIt.Get(); InputPixelType halfMaximumToBackgroundValue = (dilatePixel - m_BackgroundValue) / 2.0; InputPixelType featureValue = sigmoid(inputPixelToBackgroundValue-halfMaximumToBackgroundValue); outputIt.Set(featureValue); ++inputIt; ++dilateIt; ++outputIt; } } template void FWHMFeatureImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "UseImageSpacing = " << m_UseImageSpacing << std::endl; os << indent << "Radius = " << m_Radius << std::endl; os << indent << "BackgroundValue = " << m_BackgroundValue << std::endl; } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkAnisotropicDiffusionVesselEnhancementFunction.h0000664000175000017500000001555611757446472027346 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkAnisotropicDiffusionVesselEnhancementFunction.h,v $ Language: C++ Date: $Date: 2007/06/12 20:59:44 $ Version: $Revision: 1.10 $ 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 __itkAnisotropicDiffusionVesselEnhancementFunction_h #define __itkAnisotropicDiffusionVesselEnhancementFunction_h #include "itkFiniteDifferenceFunction.h" #include "vnl/vnl_matrix_fixed.h" #include "itkSymmetricSecondRankTensor.h" namespace itk { /** \class AnisotropicDiffusionVesselEnhancementFunction * \brief This class is a function object that is used * to create a solver filter for vessel enhancment diffuion equation * developed by Manniesing et al. * * \par References * Manniesing, R, Viergever, MA, & Niessen, WJ (2006). Vessel Enhancing * Diffusion: A Scale Space Representation of Vessel Structures. Medical * Image Analysis, 10(6), 815-825. * * \sa MultiScaleHessianSmoothed3DToVesselnessMeasureImageFilter * \sa AnisotropicDiffusionVesselEnhancementImageFilter * \ingroup FiniteDifferenceFunctions * \ingroup Functions */ template class ITK_EXPORT AnisotropicDiffusionVesselEnhancementFunction : public FiniteDifferenceFunction { public: /** Standard class typedefs. */ typedef AnisotropicDiffusionVesselEnhancementFunction Self; typedef FiniteDifferenceFunction Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods) */ itkTypeMacro( AnisotropicDiffusionVesselEnhancementFunction, FiniteDifferenceFunction ); /** Extract some parameters from the superclass. */ itkStaticConstMacro(ImageDimension, unsigned int,Superclass::ImageDimension); /** Convenient typedefs. */ typedef double TimeStepType; typedef typename Superclass::ImageType ImageType; typedef typename Superclass::PixelType PixelType; typedef double ScalarValueType; typedef typename Superclass::RadiusType RadiusType; typedef typename Superclass::NeighborhoodType NeighborhoodType; typedef typename Superclass::FloatOffsetType FloatOffsetType; typedef itk::Image< SymmetricSecondRankTensor, itkGetStaticConstMacro(ImageDimension)> DiffusionTensorImageType; /** The default boundary condition for finite difference * functions that is used unless overridden in the Evaluate() method. */ typedef ZeroFluxNeumannBoundaryCondition DefaultBoundaryConditionType; /** Define diffusion image nbd type */ typedef ConstNeighborhoodIterator DiffusionTensorNeighborhoodType; /** Tensor pixel type */ typedef itk::SymmetricSecondRankTensor< double > TensorPixelType; /** A global data type for this class of equations. Used to store * values that are needed in calculating the time step and other intermediate * products such as derivatives that may be used by virtual functions called * from ComputeUpdate. Caching these values here allows the ComputeUpdate * function to be const and thread safe.*/ struct GlobalDataStruct { /** Hessian matrix */ vnl_matrix_fixed m_dxy; /** diffusion tensor first derivative matrix */ vnl_matrix_fixed m_DT_dxy; /** Array of first derivatives*/ ScalarValueType m_dx[itkGetStaticConstMacro(ImageDimension)]; ScalarValueType m_GradMagSqr; }; /** Compute the equation value. */ virtual PixelType ComputeUpdate(const NeighborhoodType &neighborhood, void *globalData, const FloatOffsetType& = FloatOffsetType(0.0)); /** Compute the equation value. */ virtual PixelType ComputeUpdate( const NeighborhoodType &neighborhood, const DiffusionTensorNeighborhoodType &neighborhoodTensor, void *globalData, const FloatOffsetType& = FloatOffsetType(0.0)); /** Computes the time step for an update given a global data structure. */ virtual TimeStepType ComputeGlobalTimeStep(void *GlobalData) const; /** Returns a pointer to a global data structure that is passed to this * object from the solver at each calculation.*/ virtual void *GetGlobalDataPointer() const { GlobalDataStruct *ans = new GlobalDataStruct(); return ans; } virtual void ReleaseGlobalDataPointer(void *GlobalData) const { delete (GlobalDataStruct *) GlobalData; } /** Set/Get the time step. For this class of anisotropic diffusion filters, the time-step is supplied by the user and remains fixed for all updates. */ void SetTimeStep(const TimeStepType &t) { m_TimeStep = t; } const TimeStepType &GetTimeStep() const { return m_TimeStep; } protected: AnisotropicDiffusionVesselEnhancementFunction(); virtual ~AnisotropicDiffusionVesselEnhancementFunction() {} void PrintSelf(std::ostream &s, Indent indent) const; /** Slices for the ND neighborhood. */ std::slice x_slice[itkGetStaticConstMacro(ImageDimension)]; /** The offset of the center pixel in the neighborhood. */ ::size_t m_Center; /** Stride length along the y-dimension. */ ::size_t m_xStride[itkGetStaticConstMacro(ImageDimension)]; private: //purposely not implemented AnisotropicDiffusionVesselEnhancementFunction(const Self&); void operator=(const Self&); //purposely not implemented TimeStepType m_TimeStep; }; } // namespace itk #if ITK_TEMPLATE_EXPLICIT # include "Templates/itkAnisotropicDiffusionVesselEnhancementFunction+-.h" #endif #if ITK_TEMPLATE_TXX # include "itkAnisotropicDiffusionVesselEnhancementFunction.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkSatoVesselnessMeasureImageFilter.h0000664000175000017500000000524311757446472025472 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSatoVesselnessMeasureImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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(); vtkTypeRevisionMacro(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); 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 vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkVesselEnhancingDiffusion3DImageFilter.cxx0000664000175000017500000000222211757446472026646 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsVesselEnhancingDiffusion3DImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkVesselEnhancingDiffusion3DImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkVesselEnhancingDiffusion3DImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkVesselEnhancingDiffusion3DImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkVesselEnhancingDiffusionImageFilter.cxx0000664000175000017500000000221211757446472026456 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsVesselEnhancingDiffusionImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkVesselEnhancingDiffusionImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkVesselEnhancingDiffusionImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkConstrainedLaplacianPolyDataFilter.h0000664000175000017500000000471411757446472025742 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkConstrainedLaplacianPolyDataFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkConstrainedLaplacianPolyDataFilter - ... // .SECTION Description // . #ifndef __vtkvmtkConstrainedLaplacianPolyDataFilter_h #define __vtkvmtkConstrainedLaplacianPolyDataFilter_h #include "vtkPolyDataToPolyDataFilter.h" #include "vtkvmtkWin32Header.h" class vtkIdList; class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkConstrainedLaplacianPolyDataFilter : public vtkPolyDataToPolyDataFilter { public: vtkTypeRevisionMacro(vtkvmtkConstrainedLaplacianPolyDataFilter,vtkPolyDataToPolyDataFilter); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkConstrainedLaplacianPolyDataFilter *New(); vtkSetMacro(Convergence, double); vtkGetMacro(Convergence, double); vtkSetMacro(RelaxationFactor, double); vtkGetMacro(RelaxationFactor, double); vtkSetMacro(NumberOfIterations, int); vtkGetMacro(NumberOfIterations, int); vtkSetMacro(BoundarySmoothing, int); vtkGetMacro(BoundarySmoothing, int); vtkBooleanMacro(BoundarySmoothing, int); virtual void SetConstrainedPointIds(vtkIdList *); vtkGetObjectMacro(ConstrainedPointIds, vtkIdList); protected: vtkvmtkConstrainedLaplacianPolyDataFilter(); ~vtkvmtkConstrainedLaplacianPolyDataFilter(); void Execute(); vtkIdList *ConstrainedPointIds; double Convergence; double RelaxationFactor; int NumberOfIterations; int BoundarySmoothing; private: vtkvmtkConstrainedLaplacianPolyDataFilter(const vtkvmtkConstrainedLaplacianPolyDataFilter&); // Not implemented. void operator=(const vtkvmtkConstrainedLaplacianPolyDataFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkDanielssonDistanceMapImageFilter.h0000664000175000017500000000552311757446472025400 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDanielssonDistanceMapImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkDanielssonDistanceMapImageFilter - Wrapper class around itk::DanielssonDistanceMapImageFilter // .SECTION Description // vtkvmtkDanielssonDistanceMapImageFilter #ifndef __vtkvmtkDanielssonDistanceMapImageFilter_h #define __vtkvmtkDanielssonDistanceMapImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkDanielssonDistanceMapImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkDanielssonDistanceMapImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkDanielssonDistanceMapImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkDanielssonDistanceMapImageFilter, vtkvmtkITKImageToImageFilterFF); void SetSquaredDistance ( int value ) { DelegateITKInputMacro ( SetSquaredDistance, (bool) value ); } void SquaredDistanceOn() { this->SetSquaredDistance (true); } void SquaredDistanceOff() { this->SetSquaredDistance (false); } int GetSquaredDistance() { DelegateITKOutputMacro ( GetSquaredDistance ); } void SetInputIsBinary ( int value ) { DelegateITKInputMacro ( SetInputIsBinary, (bool) value ); } void InputIsBinaryOn() { this->SetInputIsBinary (true); } void InputIsBinaryOff() { this->SetInputIsBinary (false); } int GetInputIsBinary() { DelegateITKOutputMacro ( GetInputIsBinary ); }; protected: //BTX typedef itk::DanielssonDistanceMapImageFilter ImageFilterType; vtkvmtkDanielssonDistanceMapImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkDanielssonDistanceMapImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkDanielssonDistanceMapImageFilter(const vtkvmtkDanielssonDistanceMapImageFilter&); // Not implemented. void operator=(const vtkvmtkDanielssonDistanceMapImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkCardinalSpline.cxx0000664000175000017500000001013111757446472022311 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCardinalSpline.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.0 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCardinalSpline.h" #include "vtkPiecewiseFunction.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCardinalSpline, "$Revision: 1.00 $"); vtkStandardNewMacro(vtkvmtkCardinalSpline); vtkvmtkCardinalSpline::vtkvmtkCardinalSpline() { } double vtkvmtkCardinalSpline::EvaluateDerivative(double t) { int index; double *intervals; double *coefficients; if (this->ComputeTime < this->GetMTime()) { this->Compute(); } int size = this->PiecewiseFunction->GetSize(); if (size < 2) { return 0.0; } intervals = this->Intervals; coefficients = this->Coefficients; if (this->Closed) { size = size + 1; } if (t < intervals[0]) { t = intervals[0]; } if (t > intervals[size - 1]) { t = intervals[size - 1]; } index = this->FindIndex(size,t); t = (t - intervals[index]); return 3 * t * t * *(coefficients + index * 4 + 3) + 2 * t * *(coefficients + index * 4 + 2) + + *(coefficients + index * 4 + 1); } double vtkvmtkCardinalSpline::EvaluateSecondDerivative(double t) { int index; double *intervals; double *coefficients; if (this->ComputeTime < this->GetMTime()) { this->Compute(); } int size = this->PiecewiseFunction->GetSize(); if (size < 2) { return 0.0; } intervals = this->Intervals; coefficients = this->Coefficients; if (this->Closed) { size = size + 1; } if (t < intervals[0]) { t = intervals[0]; } if (t > intervals[size - 1]) { t = intervals[size - 1]; } index = this->FindIndex(size,t); t = (t - intervals[index]); return 6 * t * *(coefficients + index * 4 + 3) + 2 * *(coefficients + index * 4 + 2); } void vtkvmtkCardinalSpline::EvaluateValueAndDerivatives(double t, double valueAndDerivatives[3]) { int index; double *intervals; double *coefficients; if (this->ComputeTime < this->GetMTime()) { this->Compute(); } int size = this->PiecewiseFunction->GetSize(); if (size < 2) { valueAndDerivatives[0] = 0.0; valueAndDerivatives[1] = 0.0; valueAndDerivatives[2] = 0.0; return; } intervals = this->Intervals; coefficients = this->Coefficients; if (this->Closed) { size = size + 1; } if (t < intervals[0]) { t = intervals[0]; } if (t > intervals[size - 1]) { t = intervals[size - 1]; } index = this->FindIndex(size,t); t = (t - intervals[index]); valueAndDerivatives[0] = (t * (t * (t * *(coefficients + index * 4 + 3) + *(coefficients + index * 4 + 2)) + *(coefficients + index * 4 + 1)) + *(coefficients + index * 4)); valueAndDerivatives[1] = 3 * t * t * *(coefficients + index * 4 + 3) + 2 * t * *(coefficients + index * 4 + 2) + + *(coefficients + index * 4 + 1); valueAndDerivatives[2] = 6 * t * *(coefficients + index * 4 + 3) + 2 * *(coefficients + index * 4 + 2); } void vtkvmtkCardinalSpline::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkFastMarchingUpwindGradientImageFilter.h0000664000175000017500000001447111757446472026405 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFastMarchingUpwindGradientImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkFastMarchingUpwindGradientImageFilter - Wrapper class around itk::FastMarchingUpwindGradientImageFilter // .SECTION Description // vtkvmtkFastMarchingUpwindGradientImageFilter #ifndef __vtkvmtkFastMarchingUpwindGradientImageFilter_h #define __vtkvmtkFastMarchingUpwindGradientImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkFastMarchingUpwindGradientImageFilter.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkFastMarchingUpwindGradientImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkFastMarchingUpwindGradientImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkFastMarchingUpwindGradientImageFilter, vtkvmtkITKImageToImageFilterFF); // void SetUseImageSpacing ( int value ) // { // DelegateITKInputMacro ( SetUseImageSpacing, (bool) value ); // } // void UseImageSpacingOn() // { // this->SetUseImageSpacing (true); // } // void UseImageSpacingOff() // { // this->SetUseImageSpacing (false); // } // int GetUseImageSpacing() // { DelegateITKOutputMacro ( GetUseImageSpacing ); } void SetGenerateGradientImage ( int value ) { DelegateITKInputMacro ( SetGenerateGradientImage, (bool) value ); } void GenerateGradientImageOn() { this->SetGenerateGradientImage (true); } void GenerateGradientImageOff() { this->SetGenerateGradientImage (false); } int GetGenerateGradientImage() { DelegateITKOutputMacro ( GetGenerateGradientImage ); } void SetTargetReachedMode ( int value ) { DelegateITKInputMacro ( SetTargetReachedMode, value ); } int GetTargetReachedMode() { DelegateITKOutputMacro ( GetTargetReachedMode ); } void SetTargetReachedModeToOneTarget() { this->SetTargetReachedMode ( ImageFilterType::OneTarget ); } void SetTargetReachedModeToNoTargets() { this->SetTargetReachedMode ( ImageFilterType::NoTargets ); } void SetTargetReachedModeToAllTargets() { this->SetTargetReachedMode ( ImageFilterType::AllTargets ); } double GetTargetValue() { DelegateITKOutputMacro ( GetTargetValue ); } void SetTargetOffset ( double value ) { DelegateITKInputMacro ( SetTargetOffset, value ); } double GetTargetOffset() { DelegateITKOutputMacro ( GetTargetOffset ); } vtkSetObjectMacro(Seeds,vtkIdList); vtkGetObjectMacro(Seeds,vtkIdList); vtkSetObjectMacro(Targets,vtkIdList); vtkGetObjectMacro(Targets,vtkIdList); void Update() { //BTX this->itkImporter->Update(); if (this->vtkExporter->GetInput()) { ImageFilterType::NodeContainerPointer seeds = ImageFilterType::NodeContainer::New(); int i; for (i=0; iSeeds->GetNumberOfIds(); i++) { // TODO: here we get the point. We should get the cell center instead. Superclass::InputImageType::PointType seedPoint(this->vtkExporter->GetInput()->GetPoint(this->Seeds->GetId(i))); ImageFilterType::NodeType::IndexType seedIndex; this->itkImporter->GetOutput()->TransformPhysicalPointToIndex(seedPoint,seedIndex); ImageFilterType::PixelType seedValue = itk::NumericTraits::Zero; ImageFilterType::NodeType seed; seed.SetValue(seedValue); seed.SetIndex(seedIndex); seeds->InsertElement(i,seed); } this->GetImageFilterPointer()->SetTrialPoints(seeds); ImageFilterType::NodeContainerPointer targets = ImageFilterType::NodeContainer::New(); for (i=0; iTargets->GetNumberOfIds(); i++) { // TODO: here we get the point. We should get the cell center instead. Superclass::InputImageType::PointType seedPoint(this->vtkExporter->GetInput()->GetPoint(this->Targets->GetId(i))); ImageFilterType::NodeType::IndexType seedIndex; this->itkImporter->GetOutput()->TransformPhysicalPointToIndex(seedPoint,seedIndex); ImageFilterType::PixelType seedValue = itk::NumericTraits::Zero; ImageFilterType::NodeType seed; seed.SetValue(seedValue); seed.SetIndex(seedIndex); targets->InsertElement(i,seed); } this->GetImageFilterPointer()->SetTargetPoints(targets); } // Force the internal pipeline to update. if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } //ETX } protected: //BTX typedef itk::FastMarchingUpwindGradientImageFilter ImageFilterType; vtkvmtkFastMarchingUpwindGradientImageFilter() : Superclass ( ImageFilterType::New() ) { this->Seeds = NULL; this->Targets = NULL; } ~vtkvmtkFastMarchingUpwindGradientImageFilter() { if (this->Seeds) { this->Seeds->Delete(); } if (this->Targets) { this->Targets->Delete(); } } ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX vtkIdList* Seeds; vtkIdList* Targets; private: vtkvmtkFastMarchingUpwindGradientImageFilter(const vtkvmtkFastMarchingUpwindGradientImageFilter&); // Not implemented. void operator=(const vtkvmtkFastMarchingUpwindGradientImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkFastMarchingDirectionalFreezeImageFilter.cxx0000664000175000017500000000223711757446472027427 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFastMarchingDirectionalFreezeImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkFastMarchingDirectionalFreezeImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkFastMarchingDirectionalFreezeImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkFastMarchingDirectionalFreezeImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/CMakeLists.txt0000664000175000017500000001407411757446472020020 0ustar lucalucaSET (VTK_VMTK_SEGMENTATION_SRCS vtkvmtkActiveTubeFilter.cxx vtkvmtkBoundedReciprocalImageFilter.cxx vtkvmtkCardinalSpline.cxx vtkvmtkCollidingFrontsImageFilter.cxx # vtkvmtkConstrainedLaplacianPolyDataFilter.cxx vtkvmtkCurvesLevelSetImageFilter.cxx vtkvmtkDanielssonDistanceMapImageFilter.cxx vtkvmtkFastMarchingDirectionalFreezeImageFilter.cxx vtkvmtkFastMarchingUpwindGradientImageFilter.cxx vtkvmtkFWHMFeatureImageFilter.cxx vtkvmtkGeodesicActiveContourLevelSetImageFilter.cxx vtkvmtkGeodesicActiveContourLevelSet2DImageFilter.cxx vtkvmtkGradientMagnitudeImageFilter.cxx vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter.cxx vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.cxx vtkvmtkLaplacianSegmentationLevelSetImageFilter.cxx vtkvmtkObjectnessMeasureImageFilter.cxx vtkvmtkPolyDataPotentialFit.cxx vtkvmtkRecursiveGaussianImageFilter.cxx vtkvmtkRecursiveGaussian2DImageFilter.cxx vtkvmtkSatoVesselnessMeasureImageFilter.cxx vtkvmtkSigmoidImageFilter.cxx vtkvmtkThresholdSegmentationLevelSetImageFilter.cxx vtkvmtkUpwindGradientMagnitudeImageFilter.cxx vtkvmtkVesselEnhancingDiffusionImageFilter.cxx vtkvmtkVesselEnhancingDiffusion3DImageFilter.cxx vtkvmtkVesselnessMeasureImageFilter.cxx ) SET (VTK_VMTK_SEGMENTATION_ITK_HEADERS vtkvmtkITKFilterUtilities.h itkFWHMFeatureImageFilter.h itkFWHMFeatureImageFilter.txx itkFastMarchingDirectionalFreezeImageFilter.h itkFastMarchingDirectionalFreezeImageFilter.txx itkFastMarchingUpwindGradientImageFilter.h itkFastMarchingUpwindGradientImageFilter.txx itkHessianToObjectnessMeasureImageFilter.h itkHessianToObjectnessMeasureImageFilter.txx itkMultiScaleHessianBasedMeasureImageFilter.h itkMultiScaleHessianBasedMeasureImageFilter.txx itkUpwindGradientMagnitudeImageFilter.h itkUpwindGradientMagnitudeImageFilter.txx itkVesselEnhancingDiffusion3DImageFilter.h itkVesselEnhancingDiffusion3DImageFilter.txx ) SET (VTK_VMTK_SEGMENTATION_SRCS ${VTK_VMTK_SEGMENTATION_SRCS} ) INCLUDE_DIRECTORIES (${vtkvmtkITK_SOURCE_DIR}) INCLUDE_DIRECTORIES (${vtkvmtkITK_BINARY_DIR}) ADD_LIBRARY (vtkvmtkSegmentation ${VTK_VMTK_SEGMENTATION_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkSegmentation PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkSegmentation PROPERTIES LINKER_LANGUAGE CXX) TARGET_LINK_LIBRARIES(vtkvmtkSegmentation vtkvmtkDifferentialGeometry vtkCommon vtkFiltering vtkGraphics vtkImaging vtkvmtkITK ITKCommon ITKBasicFilters) INSTALL(TARGETS vtkvmtkSegmentation LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_SEGMENTATION_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/Segmentation/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) INSTALL(FILES ${VTK_VMTK_SEGMENTATION_ITK_HEADERS} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkSegmentation) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkSegmentationPython VTK_VMTK_SEGMENTATION_PYTHON_SRCS "${VTK_VMTK_SEGMENTATION_SRCS}") ADD_LIBRARY(vtkvmtkSegmentationPythonD ${VTK_VMTK_SEGMENTATION_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkSegmentationPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkSegmentationPython MODULE vtkvmtkSegmentationPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkSegmentationPythonD vtkvmtkSegmentation vtkvmtkDifferentialGeometryPythonD vtkvmtkDifferentialGeometry vtkCommon vtkCommonPythonD vtkFiltering vtkFilteringPythonD vtkGraphics vtkGraphicsPythonD vtkImaging vtkImagingPythonD vtkvmtkITKPythonD vtkvmtkITK) TARGET_LINK_LIBRARIES (vtkvmtkSegmentationPython vtkvmtkSegmentationPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkSegmentationPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkSegmentationPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkSegmentationPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkSegmentationTCL VTK_VMTK_SEGMENTATION_TCL_SRCS "${VTK_VMTK_SEGMENTATION_SRCS}" "") ADD_LIBRARY(vtkvmtkSegmentationTCL ${VTK_VMTK_SEGMENTATION_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkSegmentationTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkSegmentationTCL vtkvmtkSegmentation vtkvmtkDifferentialGeometryTCL vtkvmtkDifferentialGeometry vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkGraphics vtkGraphicsTCL vtkImaging vtkImagingTCL vtkvmtkITK vtkvmtkITKTCL) INSTALL(TARGETS vtkvmtkSegmentationTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkSegmentationTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/Segmentation/itkMultiScaleHessianBasedMeasureImageFilter.h0000664000175000017500000002045711757446472026112 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkMultiScaleHessianBasedMeasureImageFilter.h,v $ Language: C++ Date: $Date: 2009-04-23 03:43:42 $ Version: $Revision: 1.9 $ 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 __itkMultiScaleHessianBasedMeasureImageFilter_h #define __itkMultiScaleHessianBasedMeasureImageFilter_h #include "itkImageToImageFilter.h" #include "itkImage.h" #include "itkHessianRecursiveGaussianImageFilter.h" namespace itk { /**\class MultiScaleHessianBasedMeasureImageFilter * \brief A filter to enhance structures using Hessian eigensystem-based * measures in a multiscale framework * * The filter evaluates a Hessian-based enhancement measure, such as vesselness * or objectness, at different scale levels. The Hessian-based measure is computed * from the Hessian image at each scale level and the best response is selected. * * Minimum and maximum sigma value can be set using SetMinSigma and SetMaxSigma * methods respectively. The number of scale levels is set using * SetNumberOfSigmaSteps method. Exponentially distributed scale levels are * computed within the bound set by the minimum and maximum sigma values * * The filter computes a second output image (accessed by the GetScalesOutput method) * containing the scales at which each pixel gave the best reponse. * * \author Luca Antiga Ph.D. Medical Imaging Unit, * Bioengineering Deparment, Mario Negri Institute, Italy. * * \sa HessianToObjectnessMeasureImageFilter * \sa Hessian3DToVesselnessMeasureImageFilter * \sa HessianSmoothed3DToVesselnessMeasureImageFilter * \sa HessianRecursiveGaussianImageFilter * \sa SymmetricEigenAnalysisImageFilter * \sa SymmetricSecondRankTensor * * \ingroup IntensityImageFilters TensorObjects * */ template class ITK_EXPORT MultiScaleHessianBasedMeasureImageFilter : public ImageToImageFilter< TInputImage,TOutputImage > { public: /** Standard class typedefs. */ typedef MultiScaleHessianBasedMeasureImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; typedef TInputImage InputImageType; typedef TOutputImage OutputImageType; typedef THessianImage HessianImageType; typedef ImageToImageFilter< HessianImageType, OutputImageType > HessianToMeasureFilterType; typedef typename TInputImage::PixelType InputPixelType; typedef typename TOutputImage::PixelType OutputPixelType; typedef typename TOutputImage::RegionType OutputRegionType; /** Image dimension. */ itkStaticConstMacro(ImageDimension, unsigned int, ::itk::GetImageDimension::ImageDimension); /** Types for Scales image */ typedef float ScalesPixelType; typedef Image ScalesImageType; /** Hessian computation filter. */ typedef HessianRecursiveGaussianImageFilter< InputImageType, HessianImageType> HessianFilterType; /** Update image buffer that holds the best objectness response. This is not redundant from the output image because the latter may not be of float type, which is required for the comparisons between responses at different scales. */ typedef Image< double, itkGetStaticConstMacro(ImageDimension) > UpdateBufferType; typedef typename UpdateBufferType::ValueType BufferValueType; typedef typename Superclass::DataObjectPointer DataObjectPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Set/Get macros for SigmaMin */ itkSetMacro(SigmaMinimum, double); itkGetConstMacro(SigmaMinimum, double); /** Set/Get macros for SigmaMax */ itkSetMacro(SigmaMaximum, double); itkGetConstMacro(SigmaMaximum, double); /** Set/Get macros for Number of Scales */ itkSetMacro(NumberOfSigmaSteps, unsigned int); itkGetConstMacro(NumberOfSigmaSteps, unsigned int); /** Set/Get HessianToMeasureFilter. This will be a filter that takes Hessian input image and produces enhanced output scalar image. The filter must derive from itk::ImageToImage filter */ itkSetObjectMacro( HessianToMeasureFilter, HessianToMeasureFilterType); itkGetObjectMacro( HessianToMeasureFilter, HessianToMeasureFilterType); /** Methods to turn on/off flag to inform the filter that the Hessian-based measure is non-negative (classical measures like Sato's and Frangi's are), hence it has a minimum at zero. In this case, the update buffer is initialized at zero, and the output scale and Hessian are zero in case the Hessian-based measure returns zero for all scales. Otherwise, the minimum output scale and Hessian are the ones obtained at scale SigmaMinimum. On by default. */ itkSetMacro(NonNegativeHessianBasedMeasure,bool); itkGetConstMacro(NonNegativeHessianBasedMeasure,bool); itkBooleanMacro(NonNegativeHessianBasedMeasure); typedef enum { EquispacedSigmaSteps = 0, LogarithmicSigmaSteps = 1 } SigmaStepMethodType; /** Set/Get the method used to generate scale sequence (Equispaced * or Logarithmic) */ itkSetMacro(SigmaStepMethod, SigmaStepMethodType); itkGetConstMacro(SigmaStepMethod, SigmaStepMethodType); /**Set equispaced sigma step method */ void SetSigmaStepMethodToEquispaced(); /**Set logartihmic sigma step method */ void SetSigmaStepMethodToLogarithmic(); /** Get the image containing the Hessian computed at the best * response scale */ const HessianImageType* GetHessianOutput() const; /** Get the image containing the scales at which each pixel gave the * best response */ const ScalesImageType* GetScalesOutput() const; void EnlargeOutputRequestedRegion (DataObject *); /** Methods to turn on/off flag to generate an image with scale values at * each pixel for the best vesselness response */ itkSetMacro(GenerateScalesOutput,bool); itkGetConstMacro(GenerateScalesOutput,bool); itkBooleanMacro(GenerateScalesOutput); /** Methods to turn on/off flag to generate an image with hessian values at * each pixel for the best vesselness response */ itkSetMacro(GenerateHessianOutput,bool); itkGetConstMacro(GenerateHessianOutput,bool); itkBooleanMacro(GenerateHessianOutput); /** This is overloaded to create the Scales and Hessian output images */ virtual DataObjectPointer MakeOutput(unsigned int idx); protected: MultiScaleHessianBasedMeasureImageFilter(); ~MultiScaleHessianBasedMeasureImageFilter() {}; void PrintSelf(std::ostream& os, Indent indent) const; /** Generate Data */ void GenerateData( void ); private: void UpdateMaximumResponse(double sigma); double ComputeSigmaValue(int scaleLevel); void AllocateUpdateBuffer(); //purposely not implemented MultiScaleHessianBasedMeasureImageFilter(const Self&); void operator=(const Self&); //purposely not implemented bool m_NonNegativeHessianBasedMeasure; double m_SigmaMinimum; double m_SigmaMaximum; unsigned int m_NumberOfSigmaSteps; SigmaStepMethodType m_SigmaStepMethod; typename HessianToMeasureFilterType::Pointer m_HessianToMeasureFilter; typename HessianFilterType::Pointer m_HessianFilter; typename UpdateBufferType::Pointer m_UpdateBuffer; bool m_GenerateScalesOutput; bool m_GenerateHessianOutput; }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkMultiScaleHessianBasedMeasureImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkITKFilterUtilities.h0000664000175000017500000001177011757446472022551 0ustar lucaluca/*========================================================================= Program: VMTK Module: vtkvmtkITKFilterUtilities.h Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkITKFilterUtilities { public: template 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); output->GetPixelContainer()->SetImportPointer(static_cast(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]; region.SetIndex(index); region.SetSize(size); output->SetLargestPossibleRegion(region); output->SetBufferedRegion(region); output->SetSpacing(spacing); } template static void ITKToVTKImage(typename TImage::Pointer input, vtkImageData* output) { typedef TImage ImageType; typedef typename ImageType::Pointer ImagePointer; typedef typename ImageType::PixelType PixelType; //TODO: make sure output has the right number of pixels memcpy(static_cast(output->GetScalarPointer()),input->GetBufferPointer(),input->GetBufferedRegion().GetNumberOfPixels()*sizeof(PixelType)); } protected: vtkvmtkITKFilterUtilities() {}; ~vtkvmtkITKFilterUtilities() {}; private: vtkvmtkITKFilterUtilities(const vtkvmtkITKFilterUtilities&); // Not implemented. void operator=(const vtkvmtkITKFilterUtilities&); // Not implemented. }; #if 0 template< class TInputPixel, class TOutputPixel> void vtkvmtkSimpleImageToImageITKFilter:: 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(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(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(output->GetScalarPointer()),outImage->GetBufferPointer(),outImage->GetBufferedRegion().GetNumberOfPixels()*sizeof(OutputPixelType)); } typedef vtkvmtkSimpleImageToImageITKFilter vtkvmtkSimpleImageToImageITKFilterFF; #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkCollidingFrontsImageFilter.h0000664000175000017500000001265511757446472024274 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCollidingFrontsImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCollidingFrontsImageFilter - Wrapper class around itk::CollidingFrontsImageFilter // .SECTION Description // vtkvmtkCollidingFrontsImageFilter #ifndef __vtkvmtkCollidingFrontsImageFilter_h #define __vtkvmtkCollidingFrontsImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkCollidingFrontsImageFilter.h" #include "vtkIdList.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkCollidingFrontsImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkCollidingFrontsImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkCollidingFrontsImageFilter, vtkvmtkITKImageToImageFilterFF); void SetApplyConnectivity ( int value ) { DelegateITKInputMacro ( SetApplyConnectivity, (bool) value ); } void ApplyConnectivityOn() { this->SetApplyConnectivity (true); } void ApplyConnectivityOff() { this->SetApplyConnectivity (false); } int GetApplyConnectivity() { DelegateITKOutputMacro ( GetApplyConnectivity ); } void SetNegativeEpsilon( double value ) { DelegateITKInputMacro ( SetNegativeEpsilon, value ); } double GetNegativeEpsilon() { DelegateITKOutputMacro ( GetNegativeEpsilon ); } void SetStopOnTargets ( int value ) { DelegateITKInputMacro ( SetStopOnTargets, (bool) value ); } void StopOnTargetsOn() { this->SetStopOnTargets (true); } void StopOnTargetsOff() { this->SetStopOnTargets (false); } int GetStopOnTargets() { DelegateITKOutputMacro ( GetStopOnTargets ); } vtkSetObjectMacro(Seeds1,vtkIdList); vtkGetObjectMacro(Seeds1,vtkIdList); vtkSetObjectMacro(Seeds2,vtkIdList); vtkGetObjectMacro(Seeds2,vtkIdList); void Update() { //BTX this->itkImporter->Update(); if (this->vtkExporter->GetInput()) { ImageFilterType::NodeContainerPointer seeds1 = ImageFilterType::NodeContainer::New(); int i; for (i=0; iSeeds1->GetNumberOfIds(); i++) { // TODO: here we get the point. We should get the cell center instead. Superclass::InputImageType::PointType seedPoint(this->vtkExporter->GetInput()->GetPoint(this->Seeds1->GetId(i))); ImageFilterType::NodeType::IndexType seedIndex; this->itkImporter->GetOutput()->TransformPhysicalPointToIndex(seedPoint,seedIndex); ImageFilterType::PixelType seedValue = itk::NumericTraits::Zero; ImageFilterType::NodeType seed; seed.SetValue(seedValue); seed.SetIndex(seedIndex); seeds1->InsertElement(i,seed); } this->GetImageFilterPointer()->SetSeedPoints1(seeds1); ImageFilterType::NodeContainerPointer seeds2 = ImageFilterType::NodeContainer::New(); for (i=0; iSeeds2->GetNumberOfIds(); i++) { // TODO: here we get the point. We should get the cell center instead. Superclass::InputImageType::PointType seedPoint(this->vtkExporter->GetInput()->GetPoint(this->Seeds2->GetId(i))); ImageFilterType::NodeType::IndexType seedIndex; this->itkImporter->GetOutput()->TransformPhysicalPointToIndex(seedPoint,seedIndex); ImageFilterType::PixelType seedValue = itk::NumericTraits::Zero; ImageFilterType::NodeType seed; seed.SetValue(seedValue); seed.SetIndex(seedIndex); seeds2->InsertElement(i,seed); } this->GetImageFilterPointer()->SetSeedPoints2(seeds2); } // Force the internal pipeline to update. if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } //ETX } protected: //BTX typedef itk::CollidingFrontsImageFilter ImageFilterType; vtkvmtkCollidingFrontsImageFilter() : Superclass ( ImageFilterType::New() ) { this->Seeds1 = NULL; this->Seeds2 = NULL; } ~vtkvmtkCollidingFrontsImageFilter() { if (this->Seeds1) { this->Seeds1->Delete(); } if (this->Seeds2) { this->Seeds2->Delete(); } } ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX vtkIdList* Seeds1; vtkIdList* Seeds2; private: vtkvmtkCollidingFrontsImageFilter(const vtkvmtkCollidingFrontsImageFilter&); // Not implemented. void operator=(const vtkvmtkCollidingFrontsImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkDanielssonDistanceMapImageFilter.cxx0000664000175000017500000000217711757446472025755 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDanielssonDistanceMapImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkDanielssonDistanceMapImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkDanielssonDistanceMapImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkBoundedReciprocalImageFilter.h0000664000175000017500000000417311757446472024554 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundedReciprocalImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkBoundedReciprocalImageFilter - Wrapper class around itk::BoundedReciprocalImageFilter // .SECTION Description // vtkvmtkBoundedReciprocalImageFilter #ifndef __vtkvmtkBoundedReciprocalImageFilter_h #define __vtkvmtkBoundedReciprocalImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkBoundedReciprocalImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkBoundedReciprocalImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkBoundedReciprocalImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkBoundedReciprocalImageFilter, vtkvmtkITKImageToImageFilterFF); protected: //BTX typedef itk::BoundedReciprocalImageFilter ImageFilterType; vtkvmtkBoundedReciprocalImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkBoundedReciprocalImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkBoundedReciprocalImageFilter(const vtkvmtkBoundedReciprocalImageFilter&); // Not implemented. void operator=(const vtkvmtkBoundedReciprocalImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeImageFilter.h0000664000175000017500000000420511757446472024557 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkGradientMagnitudeImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkGradientMagnitudeImageFilter - Wrapper class around itk::GradientMagnitudeImageFilterImageFilter // .SECTION Description // vtkvmtkGradientMagnitudeImageFilter #ifndef __vtkvmtkGradientMagnitudeImageFilter_h #define __vtkvmtkGradientMagnitudeImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkGradientMagnitudeImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkGradientMagnitudeImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkGradientMagnitudeImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkGradientMagnitudeImageFilter, vtkvmtkITKImageToImageFilterFF); protected: //BTX typedef itk::GradientMagnitudeImageFilter ImageFilterType; vtkvmtkGradientMagnitudeImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkGradientMagnitudeImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkGradientMagnitudeImageFilter(const vtkvmtkGradientMagnitudeImageFilter&); // Not implemented. void operator=(const vtkvmtkGradientMagnitudeImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkHessianSmoothed3DToVesselnessMeasureImageFilter.txx0000664000175000017500000001371011757446472030026 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkHessianSmoothed3DToVesselnessMeasureImageFilter.txx,v $ Language: C++ Date: $Date: 2007/06/12 20:59:44 $ Version: $Revision: 1.12 $ 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 __itkHessianSmoothed3DToVesselnessMeasureImageFilter_txx #define __itkHessianSmoothed3DToVesselnessMeasureImageFilter_txx #include "itkHessianSmoothed3DToVesselnessMeasureImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "vnl/vnl_math.h" #define EPSILON 1e-03 namespace itk { /** * Constructor */ template < typename TPixel > HessianSmoothed3DToVesselnessMeasureImageFilter< TPixel > ::HessianSmoothed3DToVesselnessMeasureImageFilter() { m_Alpha = 0.5; m_Beta = 0.5; m_Gamma = 5.0; m_C = 1e-5; m_SymmetricEigenValueFilter = EigenAnalysisFilterType::New(); m_SymmetricEigenValueFilter->SetDimension( ImageDimension ); m_SymmetricEigenValueFilter->OrderEigenValuesBy( EigenAnalysisFilterType::FunctorType::OrderByValue ); // By default, *do not* scale the vesselness measure by the largest // eigen value m_ScaleVesselnessMeasure = false; } template < typename TPixel > void HessianSmoothed3DToVesselnessMeasureImageFilter< TPixel > ::GenerateData() { itkDebugMacro( << "HessianSmoothed3DToVesselnessMeasureImageFilter generating data "); m_SymmetricEigenValueFilter->SetInput( this->GetInput() ); typename OutputImageType::Pointer output = this->GetOutput(); typedef typename EigenAnalysisFilterType::OutputImageType EigenValueImageType; m_SymmetricEigenValueFilter->Update(); const typename EigenValueImageType::ConstPointer eigenImage = m_SymmetricEigenValueFilter->GetOutput(); // walk the region of eigen values and get the vesselness measure EigenValueArrayType eigenValue; ImageRegionConstIterator it; it = ImageRegionConstIterator( eigenImage, eigenImage->GetRequestedRegion()); ImageRegionIterator oit; this->AllocateOutputs(); oit = ImageRegionIterator(output, output->GetRequestedRegion()); oit.GoToBegin(); it.GoToBegin(); while (!it.IsAtEnd()) { // Get the eigen value eigenValue = it.Get(); // Find the smallest eigenvalue double smallest = vnl_math_abs( eigenValue[0] ); double Lambda1 = eigenValue[0]; for ( unsigned int i=1; i <=2; i++ ) { if ( vnl_math_abs( eigenValue[i] ) < smallest ) { Lambda1 = eigenValue[i]; smallest = vnl_math_abs( eigenValue[i] ); } } // Find the largest eigenvalue double largest = vnl_math_abs( eigenValue[0] ); double Lambda3 = eigenValue[0]; for ( unsigned int i=1; i <=2; i++ ) { if ( vnl_math_abs( eigenValue[i] > largest ) ) { Lambda3 = eigenValue[i]; largest = vnl_math_abs( eigenValue[i] ); } } // find Lambda2 so that |Lambda1| < |Lambda2| < |Lambda3| double Lambda2 = eigenValue[0]; for ( unsigned int i=0; i <=2; i++ ) { if ( eigenValue[i] != Lambda1 && eigenValue[i] != Lambda3 ) { Lambda2 = eigenValue[i]; break; } } if ( Lambda2 >= 0.0 || Lambda3 >= 0.0 || vnl_math_abs( Lambda2) < EPSILON || vnl_math_abs( Lambda3 ) < EPSILON ) { oit.Set( NumericTraits< OutputPixelType >::Zero ); } else { double Lambda1Abs = vnl_math_abs( Lambda1 ); double Lambda2Abs = vnl_math_abs( Lambda2 ); double Lambda3Abs = vnl_math_abs( Lambda3 ); double Lambda1Sqr = vnl_math_sqr( Lambda1 ); double Lambda2Sqr = vnl_math_sqr( Lambda2 ); double Lambda3Sqr = vnl_math_sqr( Lambda3 ); double AlphaSqr = vnl_math_sqr( m_Alpha ); double BetaSqr = vnl_math_sqr( m_Beta ); double GammaSqr = vnl_math_sqr( m_Gamma ); double A = Lambda2Abs / Lambda3Abs; double B = Lambda1Abs / vcl_sqrt ( vnl_math_abs( Lambda2 * Lambda3 )); double S = vcl_sqrt( Lambda1Sqr + Lambda2Sqr + Lambda3Sqr ); double vesMeasure_1 = ( 1 - vcl_exp(-1.0*(( vnl_math_sqr(A) ) / ( 2.0 * ( AlphaSqr))))); double vesMeasure_2 = vcl_exp ( -1.0 * ((vnl_math_sqr( B )) / ( 2.0 * (BetaSqr)))); double vesMeasure_3 = ( 1 - vcl_exp( -1.0 * (( vnl_math_sqr( S )) / ( 2.0 * ( GammaSqr))))); double vesMeasure_4 = vcl_exp ( -1.0 * ( 2.0 * vnl_math_sqr( m_C )) / ( Lambda2Abs * (Lambda3Sqr))); double vesselnessMeasure = vesMeasure_1 * vesMeasure_2 * vesMeasure_3 * vesMeasure_4; if( m_ScaleVesselnessMeasure ) { oit.Set( static_cast< OutputPixelType >( Lambda3Abs*vesselnessMeasure ) ); } else { oit.Set( static_cast< OutputPixelType >( vesselnessMeasure ) ); } } ++it; ++oit; } } template < typename TPixel > void HessianSmoothed3DToVesselnessMeasureImageFilter< TPixel > ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Alpha: " << m_Alpha << std::endl; os << indent << "Beta: " << m_Beta << std::endl; os << indent << "Gamma: " << m_Gamma << std::endl; os << indent << "C: " << m_C << std::endl; } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.h0000664000175000017500000000531011757446472030326 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkITKImageToImageFilter2DFF.h" #include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter : public vtkvmtkITKImageToImageFilter2DFF { public: static vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter, vtkvmtkITKImageToImageFilter2DFF); void SetSigma ( float value ) { DelegateITKInputMacro ( SetSigma, value ); }; void SetNormalizeAcrossScale ( int value ) { DelegateITKInputMacro ( SetNormalizeAcrossScale, value ); }; int GetNormalizeAcrossScale() { DelegateITKOutputMacro( GetNormalizeAcrossScale ); }; protected: //BTX typedef itk::GradientMagnitudeRecursiveGaussianImageFilter ImageFilterType; vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter(const vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter&); // Not implemented. void operator=(const vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkSigmoidImageFilter.cxx0000664000175000017500000000210611757446472023130 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsSigmoidImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSigmoidImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkSigmoidImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkFastMarchingDirectionalFreezeImageFilter.txx0000664000175000017500000001473111757446472026533 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkFastMarchingDirectionalFreezeImageFilter.txx,v $ Language: C++ Date: $Date: 2007/02/09 15:06:19 $ Version: $Revision: 1.7 $ 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_txx #define _itkFastMarchingDirectionalFreezeImageFilter_txx #include "itkFastMarchingDirectionalFreezeImageFilter.h" #include "itkGradientImageFilter.h" namespace itk { /* * */ template FastMarchingDirectionalFreezeImageFilter ::FastMarchingDirectionalFreezeImageFilter() { m_SpeedGradientImage = SpeedGradientImageType::New(); } /* * */ template void FastMarchingDirectionalFreezeImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "Speed gradient image: " << m_SpeedGradientImage.GetPointer() << std::endl; } /* * */ template void FastMarchingDirectionalFreezeImageFilter ::AllocateSpeedGradientImage() { SpeedImageConstPointer speedImage = this->GetInput(); m_SpeedGradientImage->SetRequestedRegion(speedImage->GetRequestedRegion()); m_SpeedGradientImage->SetBufferedRegion(speedImage->GetBufferedRegion()); m_SpeedGradientImage->SetLargestPossibleRegion(speedImage->GetLargestPossibleRegion()); m_SpeedGradientImage->Allocate(); } /* * */ template void FastMarchingDirectionalFreezeImageFilter ::ComputeSpeedGradientImage() { if (this->GetInput() == NULL) { ExceptionObject err(__FILE__, __LINE__); err.SetLocation( ITK_LOCATION ); err.SetDescription("Input image must be set"); throw err; } SpeedImageConstPointer speedImage = this->GetInput(); typedef GradientImageFilter DerivativeFilterType; typename DerivativeFilterType::Pointer derivative = DerivativeFilterType::New(); derivative->SetInput(speedImage); derivative->SetUseImageSpacingOn(); derivative->Update(); typedef typename DerivativeFilterType::OutputImageType DerivativeOutputImageType; ImageRegionIterator dit(derivative->GetOutput(),speedImage->GetRequestedRegion()); ImageRegionIterator sgit(m_SpeedGradientImage,speedImage->GetRequestedRegion()); for(dit.GoToBegin(),sgit.GoToBegin(); !dit.IsAtEnd(); ++dit,++sgit) { //TODO: cast sgit.Set(dit.Get()); } } /* * */ template void FastMarchingDirectionalFreezeImageFilter ::GenerateData() { this->AllocateSpeedGradientImage(); this->ComputeSpeedGradientImage(); // run the GenerateData() method of the superclass try { Superclass::GenerateData(); } catch (ProcessAborted &exc) { // process was aborted, clean up the state of the filter // (most of the cleanup will have already been done by the // superclass) throw exc; } } template void FastMarchingDirectionalFreezeImageFilter ::UpdateNeighbors( const IndexType& index, const SpeedImageType * speedImage, LevelSetImageType * output ) { GradientPixelType gradientValue = this->ComputeGradientValue(index, output); SpeedGradientPixelType speedGradientValue = m_SpeedGradientImage->GetPixel(index); //TODO: set threshold to speedGradientNorm // normalizing is probably not an excellent idea, but it's the only way to threshold by angle gradientValue.Normalize(); speedGradientValue.Normalize(); //TODO: cast here if (gradientValue * speedGradientValue < -0.6) { return; } Superclass::UpdateNeighbors(index,speedImage,output); } /* * */ template typename FastMarchingDirectionalFreezeImageFilter::GradientPixelType FastMarchingDirectionalFreezeImageFilter ::ComputeGradientValue( const IndexType& index, const LevelSetImageType * output) { IndexType neighIndex = index; typedef typename TLevelSet::PixelType LevelSetPixelType; LevelSetPixelType centerPixel; LevelSetPixelType dx_forward; LevelSetPixelType dx_backward; GradientPixelType gradientPixel; const LevelSetIndexType & lastIndex = this->GetLastIndex(); const LevelSetIndexType & startIndex = this->GetStartIndex(); const LevelSetPixelType ZERO = NumericTraits< LevelSetPixelType >::Zero; OutputSpacingType spacing = this->GetOutput()->GetSpacing(); unsigned int xStride[itkGetStaticConstMacro(SetDimension)]; for ( unsigned int j = 0; j < SetDimension; j++ ) { centerPixel = output->GetPixel(index); neighIndex = index; // Set stride of one in each direction xStride[j] = 1; // Compute one-sided finite differences with alive neighbors // (the front can only come from there) dx_backward = 0.0; neighIndex[j] = index[j] - xStride[j]; if(! (neighIndex[j] > lastIndex[j] || neighIndex[j] < startIndex[j]) ) { if ( this->GetLabelImage()->GetPixel( neighIndex ) == Superclass::AlivePoint ) { dx_backward = centerPixel - output->GetPixel( neighIndex ); } } dx_forward = 0.0; neighIndex[j] = index[j] + xStride[j]; if(! (neighIndex[j] > lastIndex[j] || neighIndex[j] < startIndex[j]) ) { if ( this->GetLabelImage()->GetPixel( neighIndex ) == Superclass::AlivePoint ) { dx_forward = output->GetPixel( neighIndex ) - centerPixel; } } // Compute upwind finite differences if (vnl_math_max(dx_backward,-dx_forward) < ZERO) { gradientPixel[j] = ZERO; } else if (dx_backward > -dx_forward) { gradientPixel[j] = dx_backward; } else { gradientPixel[j] = dx_forward; } gradientPixel[j] /= spacing[j]; } return gradientPixel; } } // namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkCurvesLevelSetImageFilter.cxx0000664000175000017500000000214311757446472024451 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCurvesLevelSetImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkCurvesLevelSetImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkCurvesLevelSetImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkConstrainedLaplacianPolyDataFilter.cxx0000664000175000017500000001545611757446472026322 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkConstrainedLaplacianPolyDataFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkConstrainedLaplacianPolyDataFilter.h" #include "vtkvmtkConstants.h" #include "vtkbvgNeighborhoods.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCharArray.h" #include "vtkIdList.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkConstrainedLaplacianPolyDataFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkConstrainedLaplacianPolyDataFilter); vtkvmtkConstrainedLaplacianPolyDataFilter::vtkvmtkConstrainedLaplacianPolyDataFilter() { this->Convergence = 0.0; this->RelaxationFactor = 0.0; this->NumberOfIterations = VTK_VMTK_LARGE_INTEGER; this->BoundarySmoothing = 0; this->ConstrainedPointIds = NULL; } vtkvmtkConstrainedLaplacianPolyDataFilter::~vtkvmtkConstrainedLaplacianPolyDataFilter() { if (this->ConstrainedPointIds) { this->ConstrainedPointIds->Delete(); this->ConstrainedPointIds = NULL; } } vtkCxxSetObjectMacro(vtkvmtkConstrainedLaplacianPolyDataFilter,ConstrainedPointIds,vtkIdList); void vtkvmtkConstrainedLaplacianPolyDataFilter::Execute() { vtkPolyData *input; vtkPolyData *output; vtkPoints *newPoints; vtkbvgNeighborhoods* neighborhoods; vtkbvgNeighborhood *neighborhood; vtkIdType n, i, j, step; vtkIdType neighborhoodPointId; double point[3], newPoint[3]; double neighborhoodPoint[3]; double laplacianPoint[3]; double displacement[3], displacementNorm; double maxDisplacementNorm; vtkIdType numberOfPoints; vtkIdType numberOfNeighborhoodPoints; vtkIdType numberOfConstrainedPoints; vtkIdType constrainedStatus; vtkIdType constrainedPointId; vtkCharArray *constrainedStatusArray; newPoints = vtkPoints::New(); constrainedStatusArray = vtkCharArray::New(); constrainedStatusArray->SetNumberOfComponents(1); input = this->GetInput(); output = this->GetOutput(); newPoints->DeepCopy(input->GetPoints()); numberOfPoints = input->GetNumberOfPoints(); constrainedStatusArray->SetNumberOfTuples(numberOfPoints); constrainedStatusArray->FillComponent(0,0.0); if (this->ConstrainedPointIds) { numberOfConstrainedPoints = this->ConstrainedPointIds->GetNumberOfIds(); for (i=0; iConstrainedPointIds->GetId(i); constrainedStatusArray->SetValue(constrainedPointId,1); } } output->SetPoints(newPoints); output->SetVerts(input->GetVerts()); output->SetLines(input->GetLines()); output->SetPolys(input->GetPolys()); output->SetStrips(input->GetStrips()); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); neighborhoods = vtkbvgNeighborhoods::New(); neighborhoods->SetDataSet(input); neighborhoods->SetNeighborhoodTypeToPolyDataManifoldNeighborhood(); neighborhoods->Build(); for (n=0; nNumberOfIterations; n++) { maxDisplacementNorm = 0.0; for (step=0; step<2; step++) { for (i=0; iGetValue(i); if (constrainedStatus == 1) { continue; } neighborhood = neighborhoods->GetNeighborhood(i); if (neighborhood->GetIsBoundary() && !this->BoundarySmoothing) { continue; } newPoints->GetPoint(i,point); laplacianPoint[0] = laplacianPoint[1] = laplacianPoint[2] = 0.0; numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); for (j=0; jGetPoint(neighborhood->GetPointId(j),neighborhoodPoint); laplacianPoint[0] += neighborhoodPoint[0]; laplacianPoint[1] += neighborhoodPoint[1]; laplacianPoint[2] += neighborhoodPoint[2]; } laplacianPoint[0] /= (double)numberOfNeighborhoodPoints; laplacianPoint[1] /= (double)numberOfNeighborhoodPoints; laplacianPoint[2] /= (double)numberOfNeighborhoodPoints; displacement[0] = laplacianPoint[0] - point[0]; displacement[1] = laplacianPoint[1] - point[1]; displacement[2] = laplacianPoint[2] - point[2]; displacementNorm = vtkMath::Norm(displacement); if (displacementNorm > maxDisplacementNorm) { maxDisplacementNorm = displacementNorm; } if (step == 0) { newPoint[0] = point[0] + this->RelaxationFactor * displacement[0]; newPoint[1] = point[1] + this->RelaxationFactor * displacement[1]; newPoint[2] = point[2] + this->RelaxationFactor * displacement[2]; newPoints->SetPoint(i,newPoint); } else if (step == 1) { for (j=0; jGetPointId(j); if ((constrainedStatusArray->GetValue(neighborhoodPointId) == 1) || neighborhoods->GetNeighborhood(neighborhoodPointId)->GetIsBoundary()) { continue; } newPoints->GetPoint(neighborhoodPointId,neighborhoodPoint); newPoint[0] = neighborhoodPoint[0] - this->RelaxationFactor * displacement[0] / (double)numberOfNeighborhoodPoints; newPoint[1] = neighborhoodPoint[1] - this->RelaxationFactor * displacement[1] / (double)numberOfNeighborhoodPoints; newPoint[2] = neighborhoodPoint[2] - this->RelaxationFactor * displacement[2] / (double)numberOfNeighborhoodPoints; newPoints->SetPoint(neighborhoodPointId,newPoint); } } } } if (maxDisplacementNorm < this->Convergence) { break; } } neighborhoods->Delete(); newPoints->Delete(); constrainedStatusArray->Delete(); } void vtkvmtkConstrainedLaplacianPolyDataFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Segmentation/itkAnisotropicDiffusionVesselEnhancementImageFilter.txx0000664000175000017500000005342111757446472030336 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkAnisotropicDiffusionVesselEnhancementImageFilter.txx,v $ Language: C++ Date: $Date: 2007/06/20 16:03:23 $ Version: $Revision: 1.26 $ 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 __itkAnisotropicDiffusionVesselEnhancementImageFilter_txx_ #define __itkAnisotropicDiffusionVesselEnhancementImageFilter_txx_ #include "itkAnisotropicDiffusionVesselEnhancementImageFilter.h" #include "itkAnisotropicDiffusionVesselEnhancementFunction.h" #include #include "itkImageRegionConstIterator.h" #include "itkImageRegionIterator.h" #include "itkNumericTraits.h" #include "itkNeighborhoodAlgorithm.h" #include "itkImageFileWriter.h" #include "itkVector.h" namespace itk { /** * Constructor */ template AnisotropicDiffusionVesselEnhancementImageFilter ::AnisotropicDiffusionVesselEnhancementImageFilter() { m_UpdateBuffer = UpdateBufferType::New(); m_DiffusionTensorImage = DiffusionTensorImageType::New(); this->SetNumberOfIterations(1); m_TimeStep = 1e-2; //set the function typename AnisotropicDiffusionVesselEnhancementFunction::Pointer q = AnisotropicDiffusionVesselEnhancementFunction::New(); this->SetDifferenceFunction(q); //instantiate the SymmetricEigenVectorAnalysis filter m_EigenVectorMatrixAnalysisFilter = EigenVectorMatrixAnalysisFilterType::New(); m_EigenVectorMatrixAnalysisFilter->SetDimension( TensorPixelType::Dimension ); //instantiate the vesselness filter typename VesselnessFilterType::Pointer vesselnessFilter = VesselnessFilterType::New(); m_MultiScaleVesselnessFilter = MultiScaleVesselnessFilterType::New(); m_MultiScaleVesselnessFilter->GenerateHessianOutputOn(); m_MultiScaleVesselnessFilter->SetHessianToMeasureFilter(vesselnessFilter); // Vesselness guided vesselness function algorithm parameter m_WStrength = 25.0; m_Sensitivity = 5.0; m_Epsilon = 1e-1; m_NumberOfDiffusionSubIterations = 1; } /** Prepare for the iteration process. */ template void AnisotropicDiffusionVesselEnhancementImageFilter ::InitializeIteration() { itkDebugMacro( << "InitializeIteration() called " ); AnisotropicDiffusionVesselEnhancementFunction *f = dynamic_cast *> (this->GetDifferenceFunction().GetPointer()); if (! f) { throw ExceptionObject(__FILE__, __LINE__, "Anisotropic diffusion Vessel Enhancement function is not set.", ITK_LOCATION); } f->SetTimeStep(m_TimeStep); // Check the timestep for stability double minSpacing; if (this->GetUseImageSpacing()) { minSpacing = this->GetInput()->GetSpacing()[0]; for (unsigned int i = 1; i < ImageDimension; i++) { if (this->GetInput()->GetSpacing()[i] < minSpacing) { minSpacing = this->GetInput()->GetSpacing()[i]; } } } else { minSpacing = 1.0; } double ratio = minSpacing /vcl_pow(2.0, static_cast(ImageDimension) + 1); if ( m_TimeStep > ratio ) { itkWarningMacro(<< std::endl << "Anisotropic diffusion unstable time step:" << m_TimeStep << std::endl << "Minimum stable time step" << "for this image is " << ratio ); } f->InitializeIteration(); if (this->GetNumberOfIterations() != 0) { this->UpdateProgress(((float)(this->GetElapsedIterations())) /((float)(this->GetNumberOfIterations()))); } else { this->UpdateProgress(0); } if (m_NumberOfDiffusionSubIterations == 0) { m_NumberOfDiffusionSubIterations = 1; } if (this->GetElapsedIterations() % m_NumberOfDiffusionSubIterations == 0) { //Update the Diffusion tensor image this->UpdateDiffusionTensorImage(); } } template void AnisotropicDiffusionVesselEnhancementImageFilter ::CopyInputToOutput() { typename TInputImage::ConstPointer input = this->GetInput(); typename TOutputImage::Pointer output = this->GetOutput(); if ( !input || !output ) { itkExceptionMacro(<< "Either input and/or output is NULL."); } // Check if we are doing in-place filtering if ( this->GetInPlace() && (typeid(TInputImage) == typeid(TOutputImage)) ) { typename TInputImage::Pointer tempPtr = dynamic_cast( output.GetPointer() ); if ( tempPtr && tempPtr->GetPixelContainer() == input->GetPixelContainer() ) { // the input and output container are the same - no need to copy return; } } ImageRegionConstIterator in(input, output->GetRequestedRegion()); ImageRegionIterator out(output, output->GetRequestedRegion()); while( ! out.IsAtEnd() ) { out.Value() = static_cast(in.Get()); ++in; ++out; } } template void AnisotropicDiffusionVesselEnhancementImageFilter ::AllocateUpdateBuffer() { /* The update buffer looks just like the output and holds the change in the pixel */ typename TOutputImage::Pointer output = this->GetOutput(); m_UpdateBuffer->SetSpacing(output->GetSpacing()); m_UpdateBuffer->SetOrigin(output->GetOrigin()); m_UpdateBuffer->SetLargestPossibleRegion(output->GetLargestPossibleRegion()); m_UpdateBuffer->SetRequestedRegion(output->GetRequestedRegion()); m_UpdateBuffer->SetBufferedRegion(output->GetBufferedRegion()); m_UpdateBuffer->Allocate(); } template void AnisotropicDiffusionVesselEnhancementImageFilter ::AllocateDiffusionTensorImage() { itkDebugMacro( << "AllocateDiffusionTensorImage() called" ); /* The diffusionTensor image has the same size as the output and holds the diffusion tensor matrix for each pixel */ typename TOutputImage::Pointer output = this->GetOutput(); m_DiffusionTensorImage->SetSpacing(output->GetSpacing()); m_DiffusionTensorImage->SetOrigin(output->GetOrigin()); m_DiffusionTensorImage->SetLargestPossibleRegion(output->GetLargestPossibleRegion()); m_DiffusionTensorImage->SetRequestedRegion(output->GetRequestedRegion()); m_DiffusionTensorImage->SetBufferedRegion(output->GetBufferedRegion()); m_DiffusionTensorImage->Allocate(); } template void AnisotropicDiffusionVesselEnhancementImageFilter ::UpdateDiffusionTensorImage() { itkDebugMacro( << "UpdateDiffusionTensorImage() called" ); m_MultiScaleVesselnessFilter->SetInput( this->GetOutput() ); m_MultiScaleVesselnessFilter->Modified(); m_MultiScaleVesselnessFilter->Update(); // Hessian matrix typename HessianImageType::ConstPointer hessianOutputImage; hessianOutputImage = m_MultiScaleVesselnessFilter->GetHessianOutput(); // Pass it to the eigenVector matrix analyzer m_EigenVectorMatrixAnalysisFilter->SetInput( hessianOutputImage ); m_EigenVectorMatrixAnalysisFilter->Update(); typename OutputMatrixImageType::Pointer eigenVectorMatrixOutputImage = m_EigenVectorMatrixAnalysisFilter->GetOutput(); typedef itk::ImageRegionIterator< OutputMatrixImageType > EigenVectorMatrixIteratorType; EigenVectorMatrixIteratorType ig(eigenVectorMatrixOutputImage, eigenVectorMatrixOutputImage->GetLargestPossibleRegion()); ig.GoToBegin(); // Vessleness response typename VesselnessImageType::Pointer vesselnessImage; vesselnessImage = m_MultiScaleVesselnessFilter->GetOutput(); typedef itk::ImageRegionIterator VesselnessIteratorType; VesselnessIteratorType iv(vesselnessImage, vesselnessImage->GetLargestPossibleRegion()); iv.GoToBegin(); typename DiffusionTensorImageType::PixelType tensor; double Lambda1; double Lambda2; double Lambda3; double iS = 1.0 / m_Sensitivity; MatrixType eigenValueMatrix; MatrixType hessianEigenVectorMatrix; MatrixType hessianEigenVectorMatrixTranspose; MatrixType productMatrix; typedef itk::ImageRegionIterator DiffusionTensorIteratorType; DiffusionTensorIteratorType it(m_DiffusionTensorImage,m_DiffusionTensorImage->GetLargestPossibleRegion()); it.GoToBegin(); while( !it.IsAtEnd() ) { // Generate matrix "Q" with the eigenvectors of the Hessian hessianEigenVectorMatrix = ig.Get(); hessianEigenVectorMatrixTranspose = hessianEigenVectorMatrix.GetTranspose(); // Generate the diagonal matrix with the eigen values eigenValueMatrix.SetIdentity(); double vesselnessValue = static_cast (iv.Get()); Lambda1 = 1 + ( m_WStrength - 1 ) * vcl_pow ( vesselnessValue, iS ); Lambda2 = Lambda3 = 1 + ( m_Epsilon - 1 ) * vcl_pow ( vesselnessValue, iS ); // Lambda1 = m_Epsilon + (1 - m_Epsilon) * vesselnessValue; // Lambda2 = Lambda3 = m_Epsilon; eigenValueMatrix(0,0) = Lambda1; eigenValueMatrix(1,1) = Lambda2; eigenValueMatrix(2,2) = Lambda3; // Generate the tensor matrix productMatrix = hessianEigenVectorMatrix * eigenValueMatrix * hessianEigenVectorMatrixTranspose; //Copy the ITK::Matrix to the tensor...there should be a better way of doing this TODO tensor(0,0) = productMatrix(0,0); tensor(0,1) = productMatrix(0,1); tensor(0,2) = productMatrix(0,2); tensor(1,0) = productMatrix(1,0); tensor(1,1) = productMatrix(1,1); tensor(1,2) = productMatrix(1,2); tensor(2,0) = productMatrix(2,0); tensor(2,1) = productMatrix(2,1); tensor(2,2) = productMatrix(2,2); it.Set( tensor ); ++it; ++ig; ++iv; } } template void AnisotropicDiffusionVesselEnhancementImageFilter ::ApplyUpdate(TimeStepType dt) { itkDebugMacro( << "ApplyUpdate Invoked with time step size: " << dt ); // Set up for multithreaded processing. DenseFDThreadStruct str; str.Filter = this; str.TimeStep = dt; this->GetMultiThreader()->SetNumberOfThreads(this->GetNumberOfThreads()); this->GetMultiThreader()->SetSingleMethod(this->ApplyUpdateThreaderCallback, &str); // Multithread the execution this->GetMultiThreader()->SingleMethodExecute(); } template ITK_THREAD_RETURN_TYPE AnisotropicDiffusionVesselEnhancementImageFilter ::ApplyUpdateThreaderCallback( void * arg ) { DenseFDThreadStruct * str; int total, threadId, threadCount; threadId = ((MultiThreader::ThreadInfoStruct *)(arg))->ThreadID; threadCount = ((MultiThreader::ThreadInfoStruct *)(arg))->NumberOfThreads; str = (DenseFDThreadStruct *)(((MultiThreader::ThreadInfoStruct *)(arg))->UserData); // Execute the actual method with appropriate output region // first find out how many pieces extent can be split into. // Using the SplitRequestedRegion method from itk::ImageSource. ThreadRegionType splitRegion; total = str->Filter->SplitRequestedRegion(threadId, threadCount, splitRegion); ThreadDiffusionImageRegionType splitRegionDiffusionImage; total = str->Filter->SplitRequestedRegion(threadId, threadCount, splitRegionDiffusionImage); if (threadId < total) { str->Filter->ThreadedApplyUpdate(str->TimeStep, splitRegion, splitRegionDiffusionImage, threadId); } return ITK_THREAD_RETURN_VALUE; } template typename AnisotropicDiffusionVesselEnhancementImageFilter::TimeStepType AnisotropicDiffusionVesselEnhancementImageFilter ::CalculateChange() { itkDebugMacro( << "CalculateChange called" ); int threadCount; TimeStepType dt; // Set up for multithreaded processing. DenseFDThreadStruct str; str.Filter = this; str.TimeStep = NumericTraits::Zero; // Not used during the // calculate change step. this->GetMultiThreader()->SetNumberOfThreads(this->GetNumberOfThreads()); this->GetMultiThreader()->SetSingleMethod(this->CalculateChangeThreaderCallback, &str); // Initialize the list of time step values that will be generated by the // various threads. There is one distinct slot for each possible thread, // so this data structure is thread-safe. threadCount = this->GetMultiThreader()->GetNumberOfThreads(); str.TimeStepList = new TimeStepType[threadCount]; str.ValidTimeStepList = new bool[threadCount]; for (int i =0; i < threadCount; ++i) { str.ValidTimeStepList[i] = false; } // Multithread the execution this->GetMultiThreader()->SingleMethodExecute(); // Resolve the single value time step to return dt = this->ResolveTimeStep(str.TimeStepList, str.ValidTimeStepList, threadCount); delete [] str.TimeStepList; delete [] str.ValidTimeStepList; return dt; } template ITK_THREAD_RETURN_TYPE AnisotropicDiffusionVesselEnhancementImageFilter ::CalculateChangeThreaderCallback( void * arg ) { DenseFDThreadStruct * str; int total, threadId, threadCount; threadId = ((MultiThreader::ThreadInfoStruct *)(arg))->ThreadID; threadCount = ((MultiThreader::ThreadInfoStruct *)(arg))->NumberOfThreads; str = (DenseFDThreadStruct *)(((MultiThreader::ThreadInfoStruct *)(arg))->UserData); // Execute the actual method with appropriate output region // first find out how many pieces extent can be split into. // Using the SplitRequestedRegion method from itk::ImageSource. ThreadRegionType splitRegion; total = str->Filter->SplitRequestedRegion(threadId, threadCount, splitRegion); ThreadDiffusionImageRegionType splitDiffusionimageRegion; total = str->Filter->SplitRequestedRegion(threadId, threadCount, splitDiffusionimageRegion); if (threadId < total) { str->TimeStepList[threadId] = str->Filter->ThreadedCalculateChange(splitRegion, splitDiffusionimageRegion, threadId); str->ValidTimeStepList[threadId] = true; } return ITK_THREAD_RETURN_VALUE; } template void AnisotropicDiffusionVesselEnhancementImageFilter ::ThreadedApplyUpdate(TimeStepType dt, const ThreadRegionType ®ionToProcess, const ThreadDiffusionImageRegionType & diffusionRegionToProcess, int) { ImageRegionIterator u(m_UpdateBuffer, regionToProcess); ImageRegionIterator o(this->GetOutput(), regionToProcess); u = u.Begin(); o = o.Begin(); while ( !u.IsAtEnd() ) { o.Value() += static_cast(u.Value() * dt); // no adaptor support here ++o; ++u; } } template typename AnisotropicDiffusionVesselEnhancementImageFilter::TimeStepType AnisotropicDiffusionVesselEnhancementImageFilter ::ThreadedCalculateChange(const ThreadRegionType ®ionToProcess, const ThreadDiffusionImageRegionType & diffusionRegionToProcess, int) { typedef typename OutputImageType::RegionType RegionType; typedef typename OutputImageType::SizeType SizeType; typedef typename OutputImageType::SizeValueType SizeValueType; typedef typename OutputImageType::IndexType IndexType; typedef typename OutputImageType::IndexValueType IndexValueType; typedef typename FiniteDifferenceFunctionType::NeighborhoodType NeighborhoodIteratorType; typedef ImageRegionIterator UpdateIteratorType; typename OutputImageType::Pointer output = this->GetOutput(); TimeStepType timeStep; void *globalData; // Get the FiniteDifferenceFunction to use in calculations. const typename FiniteDifferenceFunctionType::Pointer df = dynamic_cast *> ( this->GetDifferenceFunction().GetPointer()); const SizeType radius = df->GetRadius(); // Break the input into a series of regions. The first region is free // of boundary conditions, the rest with boundary conditions. We operate // on the output region because input has been copied to output. typedef NeighborhoodAlgorithm::ImageBoundaryFacesCalculator FaceCalculatorType; typedef typename FaceCalculatorType::FaceListType FaceListType; FaceCalculatorType faceCalculator; FaceListType faceList = faceCalculator(output, regionToProcess, radius); typename FaceListType::iterator fIt = faceList.begin(); // Process the non-boundary region. NeighborhoodIteratorType nD(radius, output, *fIt); typedef NeighborhoodAlgorithm::ImageBoundaryFacesCalculator DiffusionTensorFaceCalculatorType; typedef typename DiffusionTensorFaceCalculatorType::FaceListType DiffusionTensorFaceListType; DiffusionTensorFaceCalculatorType diffusionTensorFaceCalculator; DiffusionTensorFaceListType diffusionTensorFaceList = diffusionTensorFaceCalculator(m_DiffusionTensorImage, diffusionRegionToProcess, radius); typename DiffusionTensorFaceListType::iterator dfIt = diffusionTensorFaceList.begin(); DiffusionTensorNeighborhoodType dTN(radius,m_DiffusionTensorImage, *dfIt); // Ask the function object for a pointer to a data structure it // will use to manage any global values it needs. We'll pass this // back to the function object at each calculation and then // again so that the function object can use it to determine a // time step for this iteration. globalData = df->GetGlobalDataPointer(); UpdateIteratorType nU(m_UpdateBuffer, *fIt); nD.GoToBegin(); while( !nD.IsAtEnd() ) { nU.Value() = df->ComputeUpdate(nD, dTN, globalData); ++nD; ++nU; } // Process each of the boundary faces. NeighborhoodIteratorType bD; DiffusionTensorNeighborhoodType bDD; UpdateIteratorType bU; for (++fIt; fIt != faceList.end(); ++fIt) { bD = NeighborhoodIteratorType(radius, output, *fIt); bDD = DiffusionTensorNeighborhoodType(radius, m_DiffusionTensorImage, *dfIt); bU = UpdateIteratorType (m_UpdateBuffer, *fIt); bD.GoToBegin(); bU.GoToBegin(); while ( !bD.IsAtEnd() ) { bU.Value() = df->ComputeUpdate(bD,bDD,globalData); ++bD; ++bU; } ++dfIt; } // Ask the finite difference function to compute the time step for // this iteration. We give it the global data pointer to use, then // ask it to free the global data memory. timeStep = df->ComputeGlobalTimeStep(globalData); df->ReleaseGlobalDataPointer(globalData); return timeStep; } template void AnisotropicDiffusionVesselEnhancementImageFilter ::GenerateData() { itkDebugMacro( << "GenerateData is called" ); if (this->GetState() == Superclass::UNINITIALIZED) { // Allocate the output image this->AllocateOutputs(); // Copy the input image to the output image. Algorithms will operate // directly on the output image and the update buffer. this->CopyInputToOutput(); // Allocate the internal update buffer. this->AllocateUpdateBuffer(); // Allocate buffer for the diffusion tensor image this->AllocateDiffusionTensorImage(); this->SetStateToInitialized(); this->SetElapsedIterations( 0 ); } // Iterative algorithm TimeStepType dt; unsigned int iter = 0; while ( ! this->Halt() ) { std::cout << "Iteration: " << iter << std::endl; this->InitializeIteration(); // An optional method for precalculating // global values, or otherwise setting up // for the next iteration dt = this->CalculateChange(); this->ApplyUpdate(dt); ++iter; this->SetElapsedIterations( iter ); // Invoke the iteration event. this->InvokeEvent( IterationEvent() ); if( this->GetAbortGenerateData() ) { this->InvokeEvent( IterationEvent() ); this->ResetPipeline(); throw ProcessAborted(__FILE__,__LINE__); } } } template void AnisotropicDiffusionVesselEnhancementImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); } }// end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkSigmoidImageFilter.h0000664000175000017500000000460511757446472022563 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSigmoidImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkGradientMagnitudeImageFilter - Wrapper class around itk::GradientMagnitudeImageFilterImageFilter // .SECTION Description // vtkvmtkGradientMagnitudeImageFilter #ifndef __vtkvmtkSigmoidImageFilter_h #define __vtkvmtkSigmoidImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkSigmoidImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkSigmoidImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkSigmoidImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkSigmoidImageFilter, vtkvmtkITKImageToImageFilterFF); void SetAlpha ( float value ) { DelegateITKInputMacro ( SetAlpha, value ); }; void SetBeta ( float value ) { DelegateITKInputMacro ( SetBeta, value ); }; void SetOutputMinimum ( float value ) { DelegateITKInputMacro ( SetOutputMinimum, value ); }; void SetOutputMaximum ( float value ) { DelegateITKInputMacro ( SetOutputMaximum, value ); }; protected: //BTX typedef itk::SigmoidImageFilter ImageFilterType; vtkvmtkSigmoidImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkSigmoidImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkSigmoidImageFilter(const vtkvmtkSigmoidImageFilter&); // Not implemented. void operator=(const vtkvmtkSigmoidImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkSatoVesselnessMeasureImageFilter.cxx0000664000175000017500000000611211757446472026041 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSatoVesselnessMeasureImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSatoVesselnessMeasureImageFilter.h" #include "vtkImageData.h" #include "vtkObjectFactory.h" #include "vtkvmtkITKFilterUtilities.h" #include "itkMultiScaleHessianBasedMeasureImageFilter.h" #include "itkHessian3DToVesselnessMeasureImageFilter.h" vtkCxxRevisionMacro(vtkvmtkSatoVesselnessMeasureImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkSatoVesselnessMeasureImageFilter); vtkvmtkSatoVesselnessMeasureImageFilter::vtkvmtkSatoVesselnessMeasureImageFilter() { this->SigmaMin = 1.0; this->SigmaMax = 2.0; this->NumberOfSigmaSteps = 2; this->SetSigmaStepMethodToEquispaced(); this->Alpha1 = 0.5; this->Alpha2 = 2.0; } vtkvmtkSatoVesselnessMeasureImageFilter::~vtkvmtkSatoVesselnessMeasureImageFilter() { } void vtkvmtkSatoVesselnessMeasureImageFilter::SimpleExecute(vtkImageData *input, vtkImageData *output) { typedef itk::Image ImageType; ImageType::Pointer inImage = ImageType::New(); vtkvmtkITKFilterUtilities::VTKToITKImage(input,inImage); typedef itk::SymmetricSecondRankTensor HessianPixelType; typedef itk::Image HessianImageType; typedef itk::Hessian3DToVesselnessMeasureImageFilter VesselnessFilterType; typedef itk::MultiScaleHessianBasedMeasureImageFilter ImageFilterType; VesselnessFilterType::Pointer vesselnessFilter = VesselnessFilterType::New(); vesselnessFilter->SetAlpha1(this->Alpha1); vesselnessFilter->SetAlpha2(this->Alpha2); ImageFilterType::Pointer imageFilter = ImageFilterType::New(); imageFilter->SetSigmaMinimum(this->SigmaMin); imageFilter->SetSigmaMaximum(this->SigmaMax); imageFilter->SetNumberOfSigmaSteps(this->NumberOfSigmaSteps); if (this->SigmaStepMethod == EQUISPACED) { imageFilter->SetSigmaStepMethodToEquispaced(); } else if (this->SigmaStepMethod == LOGARITHMIC) { imageFilter->SetSigmaStepMethodToLogarithmic(); } imageFilter->GenerateScalesOutputOn(); imageFilter->SetHessianToMeasureFilter(vesselnessFilter.GetPointer()); imageFilter->SetInput(inImage); imageFilter->Update(); vtkvmtkITKFilterUtilities::ITKToVTKImage(imageFilter->GetOutput(),output); } vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkFWHMFeatureImageFilter.h0000664000175000017500000000751411757446472023247 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFWHMFeatureImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCollidingFrontsImageFilter - Wrapper class around itk::CollidingFrontsImageFilter // .SECTION Description // vtkvmtkCollidingFrontsImageFilter #ifndef __vtkvmtkFWHMFeatureImageFilter_h #define __vtkvmtkFWHMFeatureImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkFWHMFeatureImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkFWHMFeatureImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkFWHMFeatureImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkFWHMFeatureImageFilter, vtkvmtkITKImageToImageFilterFF); void SetUseImageSpacing ( int value ) { DelegateITKInputMacro ( SetUseImageSpacing, (bool) value ); } void UseImageSpacingOn() { this->SetUseImageSpacing (true); } void UseImageSpacingOff() { this->SetUseImageSpacing (false); } int GetUseImageSpacing() { DelegateITKOutputMacro ( GetUseImageSpacing ); } void SetRadius ( int value[3] ) { // DelegateITKInputMacro ( SetRadius, (int*) value ); this->Radius[0] = value[0]; this->Radius[1] = value[1]; this->Radius[2] = value[2]; //BTX typedef ImageFilterType::StructuringElementRadiusType RadiusType; long unsigned int radiusValue[3]; radiusValue[0] = static_cast(value[0]); radiusValue[1] = static_cast(value[1]); radiusValue[2] = static_cast(value[2]); //ETX RadiusType radius; radius.SetSize(radiusValue); this->GetImageFilterPointer()->SetRadius(radius); this->Modified(); } vtkGetVectorMacro(Radius,int,3); void SetBackgroundValue ( float value ) { DelegateITKInputMacro ( SetBackgroundValue, (float) value ); } float GetBackgroundValue() { DelegateITKOutputMacro ( GetBackgroundValue ); } void Update() { this->itkImporter->Update(); if (this->vtkExporter->GetInput()) { } // Force the internal pipeline to update. if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } protected: //BTX typedef itk::FWHMFeatureImageFilter ImageFilterType; vtkvmtkFWHMFeatureImageFilter() : Superclass ( ImageFilterType::New() ) { this->Radius = new int[3]; } ~vtkvmtkFWHMFeatureImageFilter() { if (this->Radius) { delete[] this->Radius; this->Radius = NULL; } } ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX int* Radius; float BackgroundValue; private: vtkvmtkFWHMFeatureImageFilter(const vtkvmtkFWHMFeatureImageFilter&); // Not implemented. void operator=(const vtkvmtkFWHMFeatureImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkCurvesLevelSetImageFilter.h0000664000175000017500000001432511757446472024103 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCurvesLevelSetImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCurvesLevelSetImageFilter - Wrapper class around itk::CurvesLevelSetImageFilter // .SECTION Description // vtkvmtkCurvesLevelSetImageFilter #ifndef __vtkvmtkCurvesLevelSetImageFilter_h #define __vtkvmtkCurvesLevelSetImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkCurvesLevelSetImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkCurvesLevelSetImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkCurvesLevelSetImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkCurvesLevelSetImageFilter, vtkvmtkITKImageToImageFilterFF); float GetIsoSurfaceValue () { DelegateITKOutputMacro(GetIsoSurfaceValue) ; }; void SetIsoSurfaceValue ( float value ) { DelegateITKInputMacro ( SetIsoSurfaceValue, value ); }; void SetNumberOfIterations ( int value ) { DelegateITKInputMacro ( SetNumberOfIterations, value ); }; void SetPropagationScaling ( float value ) { DelegateITKInputMacro ( SetPropagationScaling, value ); }; void SetCurvatureScaling ( float value ) { DelegateITKInputMacro ( SetCurvatureScaling, value ); }; void SetAdvectionScaling ( float value ) { DelegateITKInputMacro ( SetAdvectionScaling, value ); }; void SetMaximumRMSError ( float value ) { DelegateITKInputMacro ( SetMaximumRMSError, value ); }; void SetUseNegativeFeatures (int value ) { DelegateITKInputMacro( SetUseNegativeFeatures, value); } void SetUseImageSpacing (int value ) { DelegateITKInputMacro( SetUseImageSpacing, value); } void SetAutoGenerateSpeedAdvection (int value ) { DelegateITKInputMacro( SetAutoGenerateSpeedAdvection, value); } void SetInterpolateSurfaceLocation (int value ) { DelegateITKInputMacro( SetInterpolateSurfaceLocation, value); } void SetDerivativeSigma ( float value ) { DelegateITKInputMacro ( SetDerivativeSigma, value ); }; void SetFeatureImage ( vtkImageData *value) { this->vtkFeatureExporter->SetInput(value); } vtkImageData *GetSpeedImage() { this->vtkSpeedImporter->Update(); return this->vtkSpeedImporter->GetOutput(); } void SetFeatureScaling ( float value ) { DelegateITKInputMacro ( SetFeatureScaling, value ); }; float GetRMSChange () { DelegateITKOutputMacro(GetRMSChange); }; int GetElapsedIterations() { DelegateITKOutputMacro(GetElapsedIterations); }; float GetPropagationScaling ( ) { DelegateITKOutputMacro ( GetPropagationScaling ); }; float GetCurvatureScaling ( ) { DelegateITKOutputMacro ( GetCurvatureScaling ); }; float GetAdvectionScaling ( ) { DelegateITKOutputMacro ( GetAdvectionScaling ); }; int GetAutoGenerateSpeedAdvection ( ) { DelegateITKOutputMacro( GetAutoGenerateSpeedAdvection ); } int GetInterpolateSurfaceLocation ( ) { DelegateITKOutputMacro( GetInterpolateSurfaceLocation ); } float GetDerivativeSigma ( float value ) { DelegateITKOutputMacro ( GetDerivativeSigma ); }; // Description: Override vtkSource's Update so that we can access this class's GetOutput(). vtkSource's GetOutput is not virtual. void Update() { if (this->vtkFeatureExporter->GetInput()) { this->itkFeatureImporter->Update(); if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } } protected: //BTX typedef itk::CurvesLevelSetImageFilter ImageFilterType; typedef itk::VTKImageImport FeatureImageImportType; typedef itk::VTKImageExport SpeedImageExportType; vtkvmtkCurvesLevelSetImageFilter() : Superclass ( ImageFilterType::New() ) { this->vtkFeatureExporter = vtkImageExport::New(); this->itkFeatureImporter = FeatureImageImportType::New(); this->itkSpeedExporter = SpeedImageExportType::New(); this->vtkSpeedImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkSpeedImporter->SetScalarArrayName("Scalars_"); #endif ConnectPipelines(this->itkSpeedExporter, this->vtkSpeedImporter); ConnectPipelines(this->vtkFeatureExporter, this->itkFeatureImporter); (dynamic_cast(m_Filter.GetPointer()))->SetFeatureImage(this->itkFeatureImporter->GetOutput()); this->itkSpeedExporter->SetInput((dynamic_cast(m_Filter.GetPointer()))->GetSpeedImage()); }; ~vtkvmtkCurvesLevelSetImageFilter() { this->vtkSpeedImporter->Delete(); this->vtkFeatureExporter->Delete(); }; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } FeatureImageImportType::Pointer itkFeatureImporter; SpeedImageExportType::Pointer itkSpeedExporter; //ETX vtkImageExport *vtkFeatureExporter; vtkImageImport *vtkSpeedImporter; private: vtkvmtkCurvesLevelSetImageFilter(const vtkvmtkCurvesLevelSetImageFilter&); // Not implemented. void operator=(const vtkvmtkCurvesLevelSetImageFilter&); // // Not implemented }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter.h0000664000175000017500000000525011757446472030143 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter - Wrapper class around itk::GradientMagnitudeRecursiveGaussianImageFilter // .SECTION Description // vtkvmtkGradientMagnitudeImageFilter #ifndef __vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter_h #define __vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter, vtkvmtkITKImageToImageFilterFF); void SetSigma ( float value ) { DelegateITKInputMacro ( SetSigma, value ); }; void SetNormalizeAcrossScale ( int value ) { DelegateITKInputMacro ( SetNormalizeAcrossScale, value ); }; int GetNormalizeAcrossScale() { DelegateITKOutputMacro( GetNormalizeAcrossScale ); }; protected: //BTX typedef itk::GradientMagnitudeRecursiveGaussianImageFilter ImageFilterType; vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter() : Superclass ( ImageFilterType::New() ){}; ~vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } //ETX private: vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter(const vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter&); // Not implemented. void operator=(const vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkHessianToObjectnessMeasureImageFilter.txx0000664000175000017500000001540611757446472026105 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkHessianToObjectnessMeasureImageFilter.txx,v $ Language: C++ Date: $Date: 2009-05-11 07:50: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 __itkHessianToObjectnessMeasureImageFilter_txx #define __itkHessianToObjectnessMeasureImageFilter_txx #include "itkHessianToObjectnessMeasureImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "itkProgressAccumulator.h" #include "itkSymmetricEigenAnalysis.h" #include "vnl/vnl_math.h" namespace itk { /** * Constructor */ template < typename TInputImage, typename TOutputImage > HessianToObjectnessMeasureImageFilter< TInputImage, TOutputImage> ::HessianToObjectnessMeasureImageFilter() { m_Alpha = 0.5; m_Beta = 0.5; m_Gamma = 5.0; m_ScaleObjectnessMeasure = true; // by default extract bright lines (equivalent to vesselness) m_ObjectDimension = 1; m_BrightObject = true; } template < typename TInputImage, typename TOutputImage > void HessianToObjectnessMeasureImageFilter< TInputImage, TOutputImage> ::BeforeThreadedGenerateData( void ) { if (m_ObjectDimension >= ImageDimension) { itkExceptionMacro( "ObjectDimension must be lower than ImageDimension." ); } } template < typename TInputImage, typename TOutputImage > void HessianToObjectnessMeasureImageFilter< TInputImage, TOutputImage> ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId) { typename OutputImageType::Pointer output = this->GetOutput(); typename InputImageType::ConstPointer input = this->GetInput(); // support progress methods/callbacks ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels(), 1000 / this->GetNumberOfThreads() ); // calculator for computation of the eigen values typedef SymmetricEigenAnalysis< InputPixelType, EigenValueArrayType > CalculatorType; CalculatorType eigenCalculator( ImageDimension ); // walk the region of eigen values and get the objectness measure ImageRegionConstIterator it(input, outputRegionForThread); ImageRegionIterator oit(output, outputRegionForThread ); oit.GoToBegin(); it.GoToBegin(); while (!it.IsAtEnd()) { // compute eigen values EigenValueArrayType eigenValues; eigenCalculator.ComputeEigenValues( it.Get(), eigenValues ); // Sort the eigenvalues by magnitude but retain their sign EigenValueArrayType sortedEigenValues = eigenValues; bool done = false; while (!done) { done = true; for (unsigned int i=0; i vnl_math_abs(sortedEigenValues[i+1])) { std::swap( sortedEigenValues[i], sortedEigenValues[i+1] ); done = false; } } } // check whether eigenvalues have the right sign bool signConstraintsSatisfied = true; for (unsigned int i=m_ObjectDimension; i 0.0) || (!m_BrightObject && sortedEigenValues[i] < 0.0) ) { signConstraintsSatisfied = false; break; } } if (!signConstraintsSatisfied) { oit.Set(NumericTraits< OutputPixelType >::Zero); ++it; ++oit; progress.CompletedPixel(); continue; } EigenValueArrayType sortedAbsEigenValues; for (unsigned int i=0; i 0.0) { if ( vcl_fabs( m_Alpha ) > 0.0 ) { rA /= vcl_pow(rADenominatorBase, 1.0 / (ImageDimension-m_ObjectDimension-1)); objectnessMeasure *= 1.0 - vcl_exp(- 0.5 * vnl_math_sqr(rA) / vnl_math_sqr(m_Alpha)); } } else { objectnessMeasure = 0.0; } } if (m_ObjectDimension > 0) { double rB = sortedAbsEigenValues[m_ObjectDimension-1]; double rBDenominatorBase = 1.0; for (unsigned int j=m_ObjectDimension; j 0.0 && vcl_fabs( m_Beta ) > 0.0 ) { rB /= vcl_pow(rBDenominatorBase, 1.0 / (ImageDimension-m_ObjectDimension)); objectnessMeasure *= vcl_exp(- 0.5 * vnl_math_sqr(rB) / vnl_math_sqr(m_Beta)); } else { objectnessMeasure = 0.0; } } if ( vcl_fabs( m_Gamma ) > 0.0 ) { double frobeniusNormSquared = 0.0; for (unsigned int i=0; i(objectnessMeasure)); ++it; ++oit; progress.CompletedPixel(); } } template < typename TInputImage, typename TOutputImage > void HessianToObjectnessMeasureImageFilter< TInputImage, TOutputImage> ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "Alpha: " << m_Alpha << std::endl; os << indent << "Beta: " << m_Beta << std::endl; os << indent << "Gamma: " << m_Gamma << std::endl; os << indent << "ScaleObjectnessMeasure: " << m_ScaleObjectnessMeasure << std::endl; os << indent << "ObjectDimension: " << m_ObjectDimension << std::endl; os << indent << "BrightObject: " << m_BrightObject << std::endl; } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkFastMarchingUpwindGradientImageFilter.txx0000664000175000017500000002263611757446472026064 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkFastMarchingUpwindGradientImageFilter.txx,v $ Language: C++ Date: $Date: 2009-07-29 10:31:53 $ Version: $Revision: 1.11 $ 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 __itkFastMarchingUpwindGradientImageFilter_txx #define __itkFastMarchingUpwindGradientImageFilter_txx #include "itkFastMarchingUpwindGradientImageFilter.h" #include "itkImageRegionIterator.h" #include "itkNumericTraits.h" #include "vnl/vnl_math.h" #include namespace itk { /** * */ template FastMarchingUpwindGradientImageFilter ::FastMarchingUpwindGradientImageFilter() { m_TargetPoints = NULL; m_ReachedTargetPoints = NULL; m_GradientImage = GradientImageType::New(); m_GenerateGradientImage = false; m_TargetOffset = 1.0; m_TargetReachedMode = NoTargets; m_TargetValue = 0.0; m_NumberOfTargets = 0; } /** * */ template void FastMarchingUpwindGradientImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os,indent); os << indent << "Target points: " << m_TargetPoints.GetPointer() << std::endl; os << indent << "Reached points: " << m_ReachedTargetPoints.GetPointer() << std::endl; os << indent << "Gradient image: " << m_GradientImage.GetPointer() << std::endl; os << indent << "Generate gradient image: " << m_GenerateGradientImage << std::endl; os << indent << "Number of targets: " << m_NumberOfTargets << std::endl; os << indent << "Target offset: " << m_TargetOffset << std::endl; os << indent << "Target reach mode: " << m_TargetReachedMode << std::endl; os << indent << "Target value: " << m_TargetValue << std::endl; } /** * */ template void FastMarchingUpwindGradientImageFilter ::Initialize( LevelSetImageType * output ) { Superclass::Initialize(output); // allocate memory for the GradientImage if requested if (m_GenerateGradientImage) { m_GradientImage->CopyInformation( this->GetInput() ); m_GradientImage->SetBufferedRegion( output->GetBufferedRegion() ); m_GradientImage->Allocate(); } // set all gradient vectors to zero if (m_GenerateGradientImage) { typedef ImageRegionIterator< GradientImageType > GradientIterator; GradientIterator gradientIt( m_GradientImage, m_GradientImage->GetBufferedRegion() ); GradientPixelType zeroGradient; typedef typename GradientPixelType::ValueType GradientPixelValueType; zeroGradient.Fill(NumericTraits< GradientPixelValueType >::Zero); for ( gradientIt.GoToBegin(); !gradientIt.IsAtEnd(); ++gradientIt ) { gradientIt.Set( zeroGradient ); } } // Need to reset the target value. m_TargetValue = 0.0; if ( m_TargetReachedMode == SomeTargets || m_TargetReachedMode == AllTargets) { m_ReachedTargetPoints = NodeContainer::New(); } } template void FastMarchingUpwindGradientImageFilter ::GenerateData() { // cache the original stopping value that was set by the user // because this subclass may change it once a target point is // reached in order to control the execution of the superclass. double stoppingValue = this->GetStoppingValue(); // run the GenerateData() method of the superclass try { Superclass::GenerateData(); } catch (ProcessAborted &exc) { // process was aborted, clean up the state of the filter // (most of the cleanup will have already been done by the // superclass) // restore the original stopping value this->SetStoppingValue( stoppingValue ); throw exc; } // restore the original stopping value this->SetStoppingValue( stoppingValue ); } template void FastMarchingUpwindGradientImageFilter ::UpdateNeighbors( const IndexType& index, const SpeedImageType * speedImage, LevelSetImageType * output ) { Superclass::UpdateNeighbors(index,speedImage,output); if (m_GenerateGradientImage) { this->ComputeGradient(index, output, this->GetLabelImage(), m_GradientImage); } AxisNodeType node; // Only check for reached targets if the mode is not NoTargets and // there is at least one TargetPoint. if( m_TargetReachedMode != NoTargets && m_TargetPoints ) { bool targetReached = false; if (m_TargetReachedMode == OneTarget) { typename NodeContainer::ConstIterator pointsIter = m_TargetPoints->Begin(); typename NodeContainer::ConstIterator pointsEnd = m_TargetPoints->End(); for (; pointsIter != pointsEnd; ++pointsIter ) { node = pointsIter.Value(); if (node.GetIndex() == index) { targetReached = true; break; } } } else if (m_TargetReachedMode == SomeTargets) { typename NodeContainer::ConstIterator pointsIter = m_TargetPoints->Begin(); typename NodeContainer::ConstIterator pointsEnd = m_TargetPoints->End(); for (; pointsIter != pointsEnd; ++pointsIter ) { node = pointsIter.Value(); if (node.GetIndex() == index) { m_ReachedTargetPoints->InsertElement(m_ReachedTargetPoints->Size(),node); break; } } if (static_cast(m_ReachedTargetPoints->Size()) == m_NumberOfTargets) { targetReached = true; } } else if (m_TargetReachedMode == AllTargets) { typename NodeContainer::ConstIterator pointsIter = m_TargetPoints->Begin(); typename NodeContainer::ConstIterator pointsEnd = m_TargetPoints->End(); for (; pointsIter != pointsEnd; ++pointsIter ) { node = pointsIter.Value(); if (node.GetIndex() == index) { m_ReachedTargetPoints->InsertElement(m_ReachedTargetPoints->Size(),node); break; } } if (m_ReachedTargetPoints->Size() == m_TargetPoints->Size()) { targetReached = true; } } if (targetReached) { m_TargetValue = static_cast(output->GetPixel(index)); double newStoppingValue = m_TargetValue + m_TargetOffset; if (newStoppingValue < this->GetStoppingValue()) { // This changes the stopping value that may have been set by // the user. Therefore, the value set by the user needs to be // cached in GenerateUpdate() so that it will be correct for // future Update() commands. this->SetStoppingValue(newStoppingValue); } } } else { m_TargetValue = static_cast(output->GetPixel(index)); } } /** * */ template void FastMarchingUpwindGradientImageFilter ::ComputeGradient( const IndexType& index, const LevelSetImageType * output, const LabelImageType * itkNotUsed(labelImage), GradientImageType * gradientImage) { IndexType neighIndex = index; typedef typename TLevelSet::PixelType LevelSetPixelType; LevelSetPixelType centerPixel; LevelSetPixelType dx_forward; LevelSetPixelType dx_backward; GradientPixelType gradientPixel; const LevelSetIndexType & lastIndex = this->GetLastIndex(); const LevelSetIndexType & startIndex = this->GetStartIndex(); const LevelSetPixelType ZERO = NumericTraits< LevelSetPixelType >::Zero; OutputSpacingType spacing = this->GetOutput()->GetSpacing(); unsigned int xStride[itkGetStaticConstMacro(SetDimension)]; for ( unsigned int j = 0; j < SetDimension; j++ ) { centerPixel = output->GetPixel(index); neighIndex = index; // Set stride of one in each direction xStride[j] = 1; // Compute one-sided finite differences with alive neighbors // (the front can only come from there) dx_backward = 0.0; neighIndex[j] = index[j] - xStride[j]; if(! (neighIndex[j] > lastIndex[j] || neighIndex[j] < startIndex[j]) ) { if ( this->GetLabelImage()->GetPixel( neighIndex ) == Superclass::AlivePoint ) { dx_backward = centerPixel - output->GetPixel( neighIndex ); } } dx_forward = 0.0; neighIndex[j] = index[j] + xStride[j]; if(! (neighIndex[j] > lastIndex[j] || neighIndex[j] < startIndex[j]) ) { if ( this->GetLabelImage()->GetPixel( neighIndex ) == Superclass::AlivePoint ) { dx_forward = output->GetPixel( neighIndex ) - centerPixel; } } // Compute upwind finite differences if (vnl_math_max(dx_backward,-dx_forward) < ZERO) { gradientPixel[j] = ZERO; } else if (dx_backward > -dx_forward) { gradientPixel[j] = dx_backward; } else { gradientPixel[j] = dx_forward; } gradientPixel[j] /= spacing[j]; } gradientImage->SetPixel( index, gradientPixel ); } } // namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkRecursiveGaussian2DImageFilter.cxx0000664000175000017500000000216611757446472025373 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsRecursiveGaussian2DImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkRecursiveGaussian2DImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkRecursiveGaussian2DImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkVesselEnhancingDiffusionImageFilter.h0000664000175000017500000001734411757446472026117 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkVesselEnhancingDiffusionImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkVesselEnhancingDiffusionImageFilter - Wrapper class around itk::VesselEnhancingDiffusionImageFilter // .SECTION Description // vtkvmtkVesselEnhancingDiffusionImageFilter #ifndef __vtkvmtkVesselEnhancingDiffusionImageFilter_h #define __vtkvmtkVesselEnhancingDiffusionImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkAnisotropicDiffusionVesselEnhancementImageFilter.h" #include "itkMultiScaleHessianBasedMeasureImageFilter.h" #include "itkHessianSmoothed3DToVesselnessMeasureImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkVesselEnhancingDiffusionImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkVesselEnhancingDiffusionImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkVesselEnhancingDiffusionImageFilter, vtkvmtkITKImageToImageFilterFF); void SetSigmaMin(double value) { DelegateITKInputMacro(GetMultiScaleVesselnessFilter()->SetSigmaMinimum,value); } double GetSigmaMin() { DelegateITKOutputMacro(GetMultiScaleVesselnessFilter()->GetSigmaMinimum); } void SetSigmaMax(double value) { DelegateITKInputMacro(GetMultiScaleVesselnessFilter()->SetSigmaMaximum,value); } double GetSigmaMax() { DelegateITKOutputMacro(GetMultiScaleVesselnessFilter()->GetSigmaMaximum); } void SetNumberOfSigmaSteps(int value) { DelegateITKInputMacro(GetMultiScaleVesselnessFilter()->SetNumberOfSigmaSteps,value); } int GetNumberOfSigmaSteps() { DelegateITKOutputMacro(GetMultiScaleVesselnessFilter()->GetNumberOfSigmaSteps); } void SetSigmaStepMethodToEquispaced() { this->GetImageFilterPointer()->GetMultiScaleVesselnessFilter()->SetSigmaStepMethodToEquispaced(); this->Modified(); } void SetSigmaStepMethodToLogarithmic() { this->GetImageFilterPointer()->GetMultiScaleVesselnessFilter()->SetSigmaStepMethodToLogarithmic(); this->Modified(); } void SetTimeStep(double value) { DelegateITKInputMacro(SetTimeStep,value); } double GetTimeStep() { DelegateITKOutputMacro(GetTimeStep); } void SetEpsilon(double value) { DelegateITKInputMacro(SetEpsilon,value); } double GetEpsilon() { DelegateITKOutputMacro(GetEpsilon); } void SetWStrength(double value) { DelegateITKInputMacro(SetWStrength,value); } double GetWStrength() { DelegateITKOutputMacro(GetWStrength); } void SetSensitivity(double value) { DelegateITKInputMacro(SetSensitivity,value); } double GetSensitivity() { DelegateITKOutputMacro(GetSensitivity); } void SetNumberOfIterations(int value) { DelegateITKInputMacro(SetNumberOfIterations,value); } int GetNumberOfIterations() { DelegateITKOutputMacro(GetNumberOfIterations); } void SetAlpha(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->SetAlpha(value); this->Modified(); } } double GetAlpha() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->GetAlpha(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetBeta(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->SetBeta(value); this->Modified(); } } double GetBeta() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->GetBeta(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetGamma(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->SetGamma(value); this->Modified(); } } double GetGamma() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->GetGamma(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetC(double value) { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->SetC(value); this->Modified(); } } double GetC() { ImageFilterType* tempFilter = dynamic_cast(this->m_Filter.GetPointer()); if (tempFilter) { return dynamic_cast(tempFilter->GetMultiScaleVesselnessFilter()->GetHessianToMeasureFilter())->GetC(); } else { vtkErrorMacro ( << this->GetClassName() << " Error getting method. Dynamic cast returned 0" ); return 0.0; } } void SetNumberOfDiffusionSubIterations(int value) { DelegateITKInputMacro(SetNumberOfDiffusionSubIterations,value); } int GetNumberOfDiffusionSubIterations() { DelegateITKOutputMacro(GetNumberOfDiffusionSubIterations); } protected: //BTX typedef itk::AnisotropicDiffusionVesselEnhancementImageFilter ImageFilterType; typedef ImageFilterType::VesselnessFilterType VesselnessFilterType; vtkvmtkVesselEnhancingDiffusionImageFilter() : Superclass(ImageFilterType::New()) { ImageFilterType* imageFilter = this->GetImageFilterPointer(); imageFilter->GetMultiScaleVesselnessFilter()->SetSigmaStepMethodToEquispaced(); } ~vtkvmtkVesselEnhancingDiffusionImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast(m_Filter.GetPointer()); } //ETX private: vtkvmtkVesselEnhancingDiffusionImageFilter(const vtkvmtkVesselEnhancingDiffusionImageFilter&); // Not implemented. void operator=(const vtkvmtkVesselEnhancingDiffusionImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkSymmetricEigenVectorAnalysisImageFilter.h0000664000175000017500000001335311757446472026064 0ustar lucaluca/*========================================================================= 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 class ITK_EXPORT SymmetricEigenVectorAnalysisImageFilter : public UnaryFunctorImageFilter > { public: /** Standard class typedefs. */ typedef SymmetricEigenVectorAnalysisImageFilter Self; typedef UnaryFunctorImageFilter > Superclass; typedef SmartPointer Pointer; typedef SmartPointer 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 { 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 vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeImageFilter.cxx0000664000175000017500000000215611757446472025135 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsGradientMagnitudeImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkGradientMagnitudeImageFilter, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkGradientMagnitudeImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/itkVesselEnhancingDiffusion3DImageFilter.h0000664000175000017500000001507011757446472025361 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkVesselEnhancingDiffusion3DImageFilter.h,v $ Language: C++ Date: $Date: 2008/12/30 12:32:29 $ Version: $Revision: 1.1 $ =========================================================================*/ #ifndef __itkVesselEnhancingDiffusion3DImageFilter_h #define __itkVesselEnhancingDiffusion3DImageFilter_h #include "itkImageToImageFilter.h" #include namespace itk { /** \class VesselEnhancingDiffusion3DImageFilter * * Complete rewrite of previous versions, only using itk/vnl routines * for derivatives, eigensystem calculations and diffusion. Internally, * the input image image is converted to internalprecision (float) for * calculation, and converted back when returning the results. * * Uses simple forward Euler scheme (explicit) with 3x3x3 stencil, * see eg phd of Joachim Weickert for theory and implementation regarding * the construction of this discretization scheme. See 'Vessel Enhancing * Diffusion', Manniesing, media 2006, for information regarding the * construction of the diffusion tensor. * * - Stores all elements of the Hessian of the complete image during * diffusion. An alternative implementation is to only store the * scale for which the vesselness has maximum response, and to * recalculate the hessian (locally) during diffusion. Also stores * the current image, ie at iteration i + temp image, therefore the complete * memory consumption approximately peaks at 8 times the input image * (input image in float) * - The hessian is stored as six individual images, an alternative * implementation is to use the itk symmetric second rank tensor * as pixeltype (and eg using the class SymmetricEigenAnalysisImage * Filter). However, we are lazy, and using this since we rely * on vnl datatypes and its eigensystem calculations * - note: most of computation time is spent at calculation of vesselness * response * * - PixelType short, 3D * Precision float, 3D * * * - todo * - using parallelism/threading eg over scales * - completely itk-fying, eg eigenvalues calculation * - possibly embedding within itk-diffusion framework * - itk expert to have a look at use of iterators * (there must be a potential gain there) * * email: r.manniesing@erasmusmc.nl * */ template class ITK_EXPORT VesselEnhancingDiffusion3DImageFilter : public ImageToImageFilter , Image > { public: typedef float Precision; typedef Image ImageType; typedef Image PrecisionImageType; typedef VesselEnhancingDiffusion3DImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; itkNewMacro(Self); itkTypeMacro(VesselEnhancingDiffusion3DImageFilter, ImageToImageFilter); itkSetMacro(TimeStep, Precision); itkSetMacro(Iterations, unsigned int); itkSetMacro(RecalculateVesselness, unsigned int); itkSetMacro(Alpha, Precision); itkSetMacro(Beta, Precision); itkSetMacro(Gamma, Precision); itkSetMacro(Epsilon, Precision); itkSetMacro(Omega, Precision); itkSetMacro(Sensitivity, Precision); void SetScales(const std::vector scales) { m_Scales = scales; } itkBooleanMacro(DarkObjectLightBackground); itkSetMacro(DarkObjectLightBackground,bool); itkBooleanMacro(Verbose); itkSetMacro(Verbose,bool); // some defaults for lowdose example // used in the paper void SetDefaultPars() { m_TimeStep = 0.001; m_Iterations = 30; m_RecalculateVesselness = 100; m_Alpha = 0.5; m_Beta = 0.5; m_Gamma = 5.0; m_Epsilon = 0.01; m_Omega = 25.0; m_Sensitivity = 5.0; m_Scales.resize(5); m_Scales[0] = 0.300; m_Scales[1] = 0.482; m_Scales[2] = 0.775; m_Scales[3] = 1.245; m_Scales[4] = 2.000; m_DarkObjectLightBackground = false; m_Verbose = true; } protected: VesselEnhancingDiffusion3DImageFilter(); ~VesselEnhancingDiffusion3DImageFilter() {}; void PrintSelf(std::ostream &os, Indent indent) const; void GenerateData(); private: VesselEnhancingDiffusion3DImageFilter(const Self&); void operator=(const Self&); Precision m_TimeStep; unsigned int m_Iterations; unsigned int m_RecalculateVesselness; Precision m_Alpha; Precision m_Beta; Precision m_Gamma; Precision m_Epsilon; Precision m_Omega; Precision m_Sensitivity; std::vector m_Scales; bool m_DarkObjectLightBackground; bool m_Verbose; unsigned int m_CurrentIteration; // current hessian for which we have max vesselresponse typename PrecisionImageType::Pointer m_Dxx; typename PrecisionImageType::Pointer m_Dxy; typename PrecisionImageType::Pointer m_Dxz; typename PrecisionImageType::Pointer m_Dyy; typename PrecisionImageType::Pointer m_Dyz; typename PrecisionImageType::Pointer m_Dzz; void VED3DSingleIteration (typename ImageType::Pointer ); // Calculates maxvessel response of the range // of scales and stores the hessian of each voxel // into the member images m_Dij. void MaxVesselResponse (const typename ImageType::Pointer); // calculates diffusion tensor // based on current values of hessian (for which we have // maximim vessel response). void DiffusionTensor(); inline Precision VesselnessFunction3D ( // sorted magn increasing const Precision, // l1 const Precision, // l2 const Precision // l3 ); }; } // end namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkVesselEnhancingDiffusion3DImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkThresholdSegmentationLevelSetImageFilter.cxx0000664000175000017500000000223711757446472027520 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkThresholdSegmentationLevelSetImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkThresholdSegmentationLevelSetImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkThresholdSegmentationLevelSetImageFilter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkThresholdSegmentationLevelSetImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkCardinalSpline.h0000664000175000017500000000346511757446472021752 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCardinalSpline.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCardinalSpline - Wrapper class around itk::VesselnessMeasureImageFilter // .SECTION Description // vtkvmtkCardinalSpline #ifndef __vtkvmtkCardinalSpline_h #define __vtkvmtkCardinalSpline_h #include "vtkCardinalSpline.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkCardinalSpline : public vtkCardinalSpline { public: static vtkvmtkCardinalSpline *New(); vtkTypeRevisionMacro(vtkvmtkCardinalSpline,vtkCardinalSpline); void PrintSelf(ostream& os, vtkIndent indent); virtual double EvaluateDerivative(double t); virtual double EvaluateSecondDerivative(double t); virtual void EvaluateValueAndDerivatives(double t, double valueAndDerivatives[3]); protected: vtkvmtkCardinalSpline(); ~vtkvmtkCardinalSpline() {} private: vtkvmtkCardinalSpline(const vtkvmtkCardinalSpline&); // Not implemented. void operator=(const vtkvmtkCardinalSpline&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkFastMarchingUpwindGradientImageFilter.h0000664000175000017500000002104211757446472025456 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkFastMarchingUpwindGradientImageFilter.h,v $ Language: C++ Date: $Date: 2009-07-29 10:31:53 $ Version: $Revision: 1.8 $ 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 __itkFastMarchingUpwindGradientImageFilter_h #define __itkFastMarchingUpwindGradientImageFilter_h #include "itkFastMarchingImageFilter.h" #include "itkImage.h" namespace itk { /** \class FastMarchingUpwindGradientImageFilter * * \brief Generates the upwind gradient field of fast marching arrival times. * * This filter adds some extra functionality to its base class. While the * solution T(x) of the Eikonal equation is being generated by the base class * with the fast marching method, the filter generates the upwind gradient * vectors of T(x), storing them in an image. * * Since the Eikonal equation generates the arrival times of a wave travelling * at a given speed, the generated gradient vectors can be interpreted as the * slowness (1/velocity) vectors of the front (the quantity inside the modulus * operator in the Eikonal equation). * * Gradient vectors are computed using upwind finite differences, that is, * information only propagates from points where the wavefront has already * passed. This is consistent with how the fast marching method works. * * One more extra feature is the possibility to define a set of Target points * where the propagation stops. This can be used to avoid computing the Eikonal * solution for the whole domain. The front can be stopped either when one * Target point is reached or all Target points are reached. The propagation * can stop after a time TargetOffset has passed since the stop condition is * met. This way the solution is computed a bit downstream the Target points, * so that the level sets of T(x) corresponding to the Target are smooth. * * * \author Luca Antiga Ph.D. Biomedical Technologies Laboratory, * Bioengineering Deparment, Mario Negri Institute, Italy. * */ template < class TLevelSet, class TSpeedImage = Image::ImageDimension> > class ITK_EXPORT FastMarchingUpwindGradientImageFilter : public FastMarchingImageFilter { public: /** Standard class typdedefs. */ typedef FastMarchingUpwindGradientImageFilter Self; typedef FastMarchingImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Run-time type information (and related methods). */ itkTypeMacro(FastMarchingUpwindGradientImageFilter, FastMarchingImageFilter); /** 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::OutputPointType PointType; /** The dimension of the level set. */ itkStaticConstMacro(SetDimension, unsigned int,Superclass::SetDimension); /** Set the container of Target Points. * If a target point is reached, the propagation stops. * Trial points are represented as a VectorContainer of LevelSetNodes. */ void SetTargetPoints( NodeContainer * points ) { m_TargetPoints = points; this->Modified(); }; /** Get the container of Target Points. */ NodeContainerPointer GetTargetPoints( ) { return m_TargetPoints; } /** Get the container of Reached Target Points. */ NodeContainerPointer GetReachedTargetPoints( ) { return m_ReachedTargetPoints; } /** GradientPixel typedef support. */ typedef CovariantVector GradientPixelType; /** GradientImage typedef support. */ typedef Image GradientImageType; /** GradientImagePointer typedef support. */ typedef typename GradientImageType::Pointer GradientImagePointer; /** Get the gradient image. */ GradientImagePointer GetGradientImage() const { return m_GradientImage; } /** Set the GenerateGradientImage flag. Instrument the algorithm to generate * the gradient of the Eikonal equation solution while fast marching. */ itkSetMacro( GenerateGradientImage, bool ); /** Get the GenerateGradientImage flag. */ itkGetConstReferenceMacro( GenerateGradientImage, bool ); itkBooleanMacro( GenerateGradientImage ); /** Set how long (in terms of arrival times) after targets are reached the * front must stop. This is useful to ensure that the level set of target * arrival time is smooth. */ itkSetMacro( TargetOffset, double ); /** Get the TargetOffset ivar. */ itkGetConstReferenceMacro( TargetOffset, double ); /** Choose whether the front must stop when the first target has been reached * or all targets have been reached. */ itkSetMacro( TargetReachedMode, int ); itkGetConstReferenceMacro( TargetReachedMode, int ); void SetTargetReachedModeToNoTargets() { this->SetTargetReachedMode(NoTargets); } void SetTargetReachedModeToOneTarget() { this->SetTargetReachedMode(OneTarget); } void SetTargetReachedModeToSomeTargets( long numberOfTargets ) { this->SetTargetReachedMode(SomeTargets); m_NumberOfTargets = numberOfTargets; } void SetTargetReachedModeToAllTargets() { this->SetTargetReachedMode(AllTargets); } /** Get the number of targets. */ itkGetConstReferenceMacro( NumberOfTargets, long ); /** Get the arrival time corresponding to the last reached target. * If TargetReachedMode is set to NoTargets, TargetValue contains * the last (aka largest) Eikonal solution value generated. */ itkGetConstReferenceMacro( TargetValue, double ); enum { NoTargets, OneTarget, SomeTargets, AllTargets }; #ifdef ITK_USE_CONCEPT_CHECKING /** Begin concept checking */ itkConceptMacro(LevelSetDoubleDivisionOperatorsCheck, (Concept::DivisionOperators)); /** End concept checking */ #endif protected: FastMarchingUpwindGradientImageFilter(); ~FastMarchingUpwindGradientImageFilter(){}; void PrintSelf( std::ostream& os, Indent indent ) const; virtual void Initialize( LevelSetImageType * ); void GenerateData(); virtual void UpdateNeighbors( const IndexType& index, const SpeedImageType *, LevelSetImageType * ); virtual void ComputeGradient( const IndexType& index , const LevelSetImageType * output, const LabelImageType * labelImage, GradientImageType * gradientImage); private: FastMarchingUpwindGradientImageFilter(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented NodeContainerPointer m_TargetPoints; NodeContainerPointer m_ReachedTargetPoints; GradientImagePointer m_GradientImage; bool m_GenerateGradientImage; double m_TargetOffset; int m_TargetReachedMode; double m_TargetValue; long m_NumberOfTargets; }; } // namespace itk #ifndef ITK_MANUAL_INSTANTIATION #include "itkFastMarchingUpwindGradientImageFilter.txx" #endif #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.cxx0000664000175000017500000000227211757446472030705 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkbvsGradientMagnitudeRecursiveGaussian2DImageFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkGradientMagnitudeRecursiveGaussian2DImageFilter); vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkVesselEnhancingDiffusion3DImageFilter.h0000664000175000017500000001222411757446472026276 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkVesselEnhancingDiffusion3DImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkVesselEnhancingDiffusion3DImageFilter - Wrapper class around itk::VesselEnhancingDiffusion3DImageFilter // .SECTION Description // vtkvmtkVesselEnhancingDiffusion3DImageFilter #ifndef __vtkvmtkVesselEnhancingDiffusion3DImageFilter_h #define __vtkvmtkVesselEnhancingDiffusion3DImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkVesselEnhancingDiffusion3DImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkVesselEnhancingDiffusion3DImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkVesselEnhancingDiffusion3DImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkVesselEnhancingDiffusion3DImageFilter, vtkvmtkITKImageToImageFilterFF); vtkSetMacro(SigmaMin,double); vtkGetMacro(SigmaMin,double); vtkSetMacro(SigmaMax,double); vtkGetMacro(SigmaMax,double); vtkSetMacro(NumberOfSigmaSteps,int); vtkGetMacro(NumberOfSigmaSteps,int); void SetSigmaStepMethodToEquispaced() { this->SigmaStepMethod = EQUISPACED_STEPS; } void SetSigmaStepMethodToLogarithmic() { this->SigmaStepMethod = LOGARITHMIC_STEPS; } void SetTimeStep(double value) { DelegateITKInputMacro(SetTimeStep,value); } void SetEpsilon(double value) { DelegateITKInputMacro(SetEpsilon,value); } void SetOmega(double value) { DelegateITKInputMacro(SetOmega,value); } void SetSensitivity(double value) { DelegateITKInputMacro(SetSensitivity,value); } void SetNumberOfIterations(int value) { DelegateITKInputMacro(SetIterations,value); } void SetAlpha(double value) { DelegateITKInputMacro(SetAlpha,value); } void SetBeta(double value) { DelegateITKInputMacro(SetBeta,value); } void SetGamma(double value) { DelegateITKInputMacro(SetGamma,value); } void SetRecalculateVesselness(int value) { DelegateITKInputMacro(SetRecalculateVesselness,value); } double ComputeSigmaValue(int scaleLevel) { double sigmaValue; if (this->NumberOfSigmaSteps < 2) { return this->SigmaMin; } switch (this->SigmaStepMethod) { case EQUISPACED_STEPS: { double stepSize = ( SigmaMax - SigmaMin ) / (NumberOfSigmaSteps-1); if (stepSize < 1e-10) { stepSize = 1e-10; } sigmaValue = SigmaMin + stepSize * scaleLevel; break; } case LOGARITHMIC_STEPS: { double stepSize = ( vcl_log(SigmaMax) - vcl_log(SigmaMin) ) / (NumberOfSigmaSteps-1); if (stepSize < 1e-10) { stepSize = 1e-10; } sigmaValue = vcl_exp( vcl_log (SigmaMin) + stepSize * scaleLevel); break; } default: vtkErrorMacro("Error: undefined sigma step method."); sigmaValue = 0.0; break; } return sigmaValue; } void Update() { std::vector scales; for (int i=0; iNumberOfSigmaSteps; i++) { scales.push_back(this->ComputeSigmaValue(i)); } this->GetImageFilterPointer()->SetScales(scales); if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } //BTX enum { EQUISPACED_STEPS, LOGARITHMIC_STEPS }; //ETX protected: //BTX typedef itk::VesselEnhancingDiffusion3DImageFilter ImageFilterType; vtkvmtkVesselEnhancingDiffusion3DImageFilter() : Superclass(ImageFilterType::New()) { this->SigmaMin = 0.0; this->SigmaMax = 0.0; this->NumberOfSigmaSteps = 0; this->SigmaStepMethod = EQUISPACED_STEPS; this->GetImageFilterPointer()->SetDefaultPars(); } ~vtkvmtkVesselEnhancingDiffusion3DImageFilter() {}; ImageFilterType* GetImageFilterPointer() { return dynamic_cast(m_Filter.GetPointer()); } //ETX double SigmaMin; double SigmaMax; int NumberOfSigmaSteps; int SigmaStepMethod; private: vtkvmtkVesselEnhancingDiffusion3DImageFilter(const vtkvmtkVesselEnhancingDiffusion3DImageFilter&); // Not implemented. void operator=(const vtkvmtkVesselEnhancingDiffusion3DImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkMultiScaleHessianBasedMeasureImageFilter.txx0000664000175000017500000003025411757446472026502 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkMultiScaleHessianBasedMeasureImageFilter.txx,v $ Language: C++ Date: $Date: 2009-08-26 19:09:35 $ Version: $Revision: 1.13 $ 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 __itkMultiScaleHessianBasedMeasureImageFilter_txx #define __itkMultiScaleHessianBasedMeasureImageFilter_txx #include "itkMultiScaleHessianBasedMeasureImageFilter.h" #include "itkImageRegionIterator.h" #include "itkImageRegionConstIterator.h" #include "vnl/vnl_math.h" namespace itk { /** * Constructor */ template MultiScaleHessianBasedMeasureImageFilter ::MultiScaleHessianBasedMeasureImageFilter() { m_NonNegativeHessianBasedMeasure = true; m_SigmaMinimum = 0.2; m_SigmaMaximum = 2.0; m_NumberOfSigmaSteps = 10; m_SigmaStepMethod = Self::LogarithmicSigmaSteps; m_HessianFilter = HessianFilterType::New(); m_HessianToMeasureFilter = NULL; //Instantiate Update buffer m_UpdateBuffer = UpdateBufferType::New(); m_GenerateScalesOutput = false; m_GenerateHessianOutput = false; typename ScalesImageType::Pointer scalesImage = ScalesImageType::New(); typename HessianImageType::Pointer hessianImage = HessianImageType::New(); this->ProcessObject::SetNumberOfRequiredOutputs(3); this->ProcessObject::SetNthOutput(1,scalesImage.GetPointer()); this->ProcessObject::SetNthOutput(2,hessianImage.GetPointer()); } template void MultiScaleHessianBasedMeasureImageFilter ::EnlargeOutputRequestedRegion (DataObject *output) { // currently this filter can not stream so we must set the outputs // requested region to the largest output->SetRequestedRegionToLargestPossibleRegion(); } template typename MultiScaleHessianBasedMeasureImageFilter ::DataObjectPointer MultiScaleHessianBasedMeasureImageFilter ::MakeOutput(unsigned int idx) { if (idx == 1) { return static_cast(ScalesImageType::New().GetPointer()); } if (idx == 2) { return static_cast(HessianImageType::New().GetPointer()); } return Superclass::MakeOutput(idx); } template void MultiScaleHessianBasedMeasureImageFilter ::AllocateUpdateBuffer() { /* The update buffer looks just like the output and holds the best response in the objectness measure */ typename TOutputImage::Pointer output = this->GetOutput(); // this copies meta data describing the output such as origin, // spacing and the largest region m_UpdateBuffer->CopyInformation(output); m_UpdateBuffer->SetRequestedRegion(output->GetRequestedRegion()); m_UpdateBuffer->SetBufferedRegion(output->GetBufferedRegion()); m_UpdateBuffer->Allocate(); // Update buffer is used for > comparisons so make it really really small, // just to be sure. Thanks to Hauke Heibel. if (m_NonNegativeHessianBasedMeasure) { m_UpdateBuffer->FillBuffer( itk::NumericTraits< BufferValueType >::Zero ); } else { m_UpdateBuffer->FillBuffer( itk::NumericTraits< BufferValueType >::NonpositiveMin() ); } } template void MultiScaleHessianBasedMeasureImageFilter ::GenerateData() { // TODO: Move the allocation to a derived AllocateOutputs method // Allocate the output this->GetOutput()->SetBufferedRegion(this->GetOutput()->GetRequestedRegion()); this->GetOutput()->Allocate(); if( m_HessianToMeasureFilter.IsNull() ) { itkExceptionMacro( " HessianToMeasure filter is not set. Use SetHessianToMeasureFilter() " ); } if (m_GenerateScalesOutput) { typename ScalesImageType::Pointer scalesImage = dynamic_cast(this->ProcessObject::GetOutput(1)); scalesImage->SetBufferedRegion(scalesImage->GetRequestedRegion()); scalesImage->Allocate(); scalesImage->FillBuffer(0); } if (m_GenerateHessianOutput) { typename HessianImageType::Pointer hessianImage = dynamic_cast(this->ProcessObject::GetOutput(2)); hessianImage->SetBufferedRegion(hessianImage->GetRequestedRegion()); hessianImage->Allocate(); // SymmetricSecondRankTensor is already filled with zero elements at construction. // No strict need of filling the buffer, but we do it explicitly here to make sure. typename HessianImageType::PixelType zeroTensor(0.0); hessianImage->FillBuffer(zeroTensor); } // Allocate the buffer AllocateUpdateBuffer(); typename InputImageType::ConstPointer input = this->GetInput(); this->m_HessianFilter->SetInput(input); this->m_HessianFilter->SetNormalizeAcrossScale(true); double sigma = m_SigmaMinimum; int scaleLevel = 1; while (sigma <= m_SigmaMaximum) { if ( m_NumberOfSigmaSteps == 0 ) { break; } itkDebugMacro ( << "Computing measure for scale with sigma = " << sigma ); m_HessianFilter->SetSigma( sigma ); m_HessianToMeasureFilter->SetInput ( m_HessianFilter->GetOutput() ); m_HessianToMeasureFilter->Update(); this->UpdateMaximumResponse(sigma); sigma = this->ComputeSigmaValue( scaleLevel ); scaleLevel++; if ( m_NumberOfSigmaSteps == 1 ) { break; } } // Write out the best response to the output image // we can assume that the meta-data should match between these two // image, therefore we iterate over the desired output region OutputRegionType outputRegion = this->GetOutput()->GetBufferedRegion(); ImageRegionIterator it( m_UpdateBuffer, outputRegion ); it.GoToBegin(); ImageRegionIterator oit( this->GetOutput(), outputRegion ); oit.GoToBegin(); while(!oit.IsAtEnd()) { oit.Value() = static_cast< OutputPixelType >( it.Get() ); ++oit; ++it; } // Release data from the update buffer. m_UpdateBuffer->ReleaseData(); } template void MultiScaleHessianBasedMeasureImageFilter ::UpdateMaximumResponse(double sigma) { // the meta-data should match between these images, therefore we // iterate over the desired output region OutputRegionType outputRegion = this->GetOutput()->GetBufferedRegion(); ImageRegionIterator oit( m_UpdateBuffer, outputRegion ); typename ScalesImageType::Pointer scalesImage = static_cast(this->ProcessObject::GetOutput(1)); ImageRegionIterator osit; typename HessianImageType::Pointer hessianImage = static_cast(this->ProcessObject::GetOutput(2)); ImageRegionIterator ohit; oit.GoToBegin(); if (m_GenerateScalesOutput) { osit = ImageRegionIterator ( scalesImage, outputRegion ); osit.GoToBegin(); } if (m_GenerateHessianOutput) { ohit = ImageRegionIterator ( hessianImage, outputRegion ); ohit.GoToBegin(); } typedef typename HessianToMeasureFilterType::OutputImageType HessianToMeasureOutputImageType; ImageRegionIterator it( m_HessianToMeasureFilter->GetOutput(), outputRegion ); ImageRegionIterator hit( m_HessianFilter->GetOutput(), outputRegion ); it.GoToBegin(); hit.GoToBegin(); while(!oit.IsAtEnd()) { if( oit.Value() < it.Value() ) { oit.Value() = it.Value(); if (m_GenerateScalesOutput) { osit.Value() = static_cast< ScalesPixelType >( sigma ); } if (m_GenerateHessianOutput) { ohit.Value() = hit.Value(); } } ++oit; ++it; if (m_GenerateScalesOutput) { ++osit; } if (m_GenerateHessianOutput) { ++ohit; ++hit; } } } template double MultiScaleHessianBasedMeasureImageFilter ::ComputeSigmaValue(int scaleLevel) { double sigmaValue; if (m_NumberOfSigmaSteps < 2) { return m_SigmaMinimum; } switch (m_SigmaStepMethod) { case Self::EquispacedSigmaSteps: { const double stepSize = vnl_math_max(1e-10, ( m_SigmaMaximum - m_SigmaMinimum ) / (m_NumberOfSigmaSteps - 1)); sigmaValue = m_SigmaMinimum + stepSize * scaleLevel; break; } case Self::LogarithmicSigmaSteps: { const double stepSize = vnl_math_max(1e-10, ( vcl_log(m_SigmaMaximum) - vcl_log(m_SigmaMinimum) ) / (m_NumberOfSigmaSteps - 1)); sigmaValue = vcl_exp( vcl_log (m_SigmaMinimum) + stepSize * scaleLevel); break; } default: throw ExceptionObject(__FILE__, __LINE__,"Invalid SigmaStepMethod.",ITK_LOCATION); break; } return sigmaValue; } template void MultiScaleHessianBasedMeasureImageFilter ::SetSigmaStepMethodToEquispaced() { this->SetSigmaStepMethod(Self::EquispacedSigmaSteps); } template void MultiScaleHessianBasedMeasureImageFilter ::SetSigmaStepMethodToLogarithmic() { this->SetSigmaStepMethod(Self::LogarithmicSigmaSteps); } /** Get the image containing the Hessian at which each pixel gave the * best response */ template const typename MultiScaleHessianBasedMeasureImageFilter::HessianImageType * MultiScaleHessianBasedMeasureImageFilter ::GetHessianOutput() const { return static_cast(this->ProcessObject::GetOutput(2)); } /** Get the image containing the scales at which each pixel gave the * best response */ template const typename MultiScaleHessianBasedMeasureImageFilter::ScalesImageType * MultiScaleHessianBasedMeasureImageFilter ::GetScalesOutput() const { return static_cast(this->ProcessObject::GetOutput(1)); } template void MultiScaleHessianBasedMeasureImageFilter ::PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "SigmaMinimum: " << m_SigmaMinimum << std::endl; os << indent << "SigmaMaximum: " << m_SigmaMaximum << std::endl; os << indent << "NumberOfSigmaSteps: " << m_NumberOfSigmaSteps << std::endl; os << indent << "SigmaStepMethod: " << m_SigmaStepMethod << std::endl; os << indent << "HessianToMeasureFilter: " << m_HessianToMeasureFilter << std::endl; os << indent << "NonNegativeHessianBasedMeasure: " << m_NonNegativeHessianBasedMeasure << std::endl; os << indent << "GenerateScalesOutput: " << m_GenerateScalesOutput << std::endl; os << indent << "GenerateHessianOutput: " << m_GenerateHessianOutput << std::endl; } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkLaplacianSegmentationLevelSetImageFilter.h0000664000175000017500000001347511757446472027103 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLaplacianSegmentationLevelSetImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkLaplacianSegmentationLevelSetImageFilter - Wrapper class around itk::LaplacianSegmentationLevelSetImageFilter // .SECTION Description // vtkvmtkLaplacianSegmentationLevelSetImageFilter #ifndef __vtkvmtkLaplacianSegmentationLevelSetImageFilter_h #define __vtkvmtkLaplacianSegmentationLevelSetImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkLaplacianSegmentationLevelSetImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkLaplacianSegmentationLevelSetImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkLaplacianSegmentationLevelSetImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkLaplacianSegmentationLevelSetImageFilter, vtkvmtkITKImageToImageFilterFF); float GetIsoSurfaceValue () { DelegateITKOutputMacro(GetIsoSurfaceValue) ; }; void SetIsoSurfaceValue ( float value ) { DelegateITKInputMacro ( SetIsoSurfaceValue, value ); }; void SetNumberOfIterations ( int value ) { DelegateITKInputMacro ( SetNumberOfIterations, value ); }; void SetPropagationScaling ( float value ) { DelegateITKInputMacro ( SetPropagationScaling, value ); }; void SetCurvatureScaling ( float value ) { DelegateITKInputMacro ( SetCurvatureScaling, value ); }; void SetMaximumRMSError ( float value ) { DelegateITKInputMacro ( SetMaximumRMSError, value ); }; void SetUseNegativeFeatures (int value ) { DelegateITKInputMacro( SetUseNegativeFeatures, value); } void SetUseImageSpacing (int value ) { DelegateITKInputMacro( SetUseImageSpacing, value); } void SetInterpolateSurfaceLocation (int value ) { DelegateITKInputMacro( SetInterpolateSurfaceLocation, value); } void SetFeatureImage ( vtkImageData *value) { this->vtkFeatureExporter->SetInput(value); } vtkImageData *GetSpeedImage() { this->vtkSpeedImporter->Update(); return this->vtkSpeedImporter->GetOutput(); } void SetFeatureScaling ( float value ) { DelegateITKInputMacro ( SetFeatureScaling, value ); }; float GetRMSChange () { DelegateITKOutputMacro(GetRMSChange); }; int GetElapsedIterations() { DelegateITKOutputMacro(GetElapsedIterations); }; float GetPropagationScaling ( ) { DelegateITKOutputMacro ( GetPropagationScaling ); }; float GetCurvatureScaling ( ) { DelegateITKOutputMacro ( GetCurvatureScaling ); }; int GetInterpolateSurfaceLocation ( ) { DelegateITKOutputMacro( GetInterpolateSurfaceLocation ); } // Description: Override vtkSource's Update so that we can access this class's GetOutput(). vtkSource's GetOutput is not virtual. void Update() { if (this->vtkFeatureExporter->GetInput()) { this->itkFeatureImporter->Update(); if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } } protected: //BTX typedef itk::LaplacianSegmentationLevelSetImageFilter ImageFilterType; typedef itk::VTKImageImport FeatureImageImportType; typedef itk::VTKImageExport SpeedImageExportType; vtkvmtkLaplacianSegmentationLevelSetImageFilter() : Superclass ( ImageFilterType::New() ) { this->vtkFeatureExporter = vtkImageExport::New(); this->itkFeatureImporter = FeatureImageImportType::New(); this->itkSpeedExporter = SpeedImageExportType::New(); this->vtkSpeedImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkSpeedImporter->SetScalarArrayName("Scalars_"); #endif ConnectPipelines(this->itkSpeedExporter, this->vtkSpeedImporter); ConnectPipelines(this->vtkFeatureExporter, this->itkFeatureImporter); (dynamic_cast(m_Filter.GetPointer()))->SetFeatureImage(this->itkFeatureImporter->GetOutput()); this->itkSpeedExporter->SetInput((dynamic_cast(m_Filter.GetPointer()))->GetSpeedImage()); }; ~vtkvmtkLaplacianSegmentationLevelSetImageFilter() { this->vtkSpeedImporter->Delete(); this->vtkFeatureExporter->Delete(); }; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } FeatureImageImportType::Pointer itkFeatureImporter; SpeedImageExportType::Pointer itkSpeedExporter; //ETX vtkImageExport *vtkFeatureExporter; vtkImageImport *vtkSpeedImporter; private: vtkvmtkLaplacianSegmentationLevelSetImageFilter(const vtkvmtkLaplacianSegmentationLevelSetImageFilter&); // Not implemented. void operator=(const vtkvmtkLaplacianSegmentationLevelSetImageFilter&); // // Not implemented }; #endif vmtk-1.0.1/vtkVmtk/Segmentation/itkAnisotropicDiffusionVesselEnhancementFunction.txx0000664000175000017500000001525411757446472027735 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: itkAnisotropicDiffusionVesselEnhancementFunction.txx,v $ Language: C++ Date: $Date: 2007/06/20 16:03:23 $ Version: $Revision: 1.14 $ 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 __itkAnisotropicDiffusionVesselEnhancementFunction_txx #define __itkAnisotropicDiffusionVesselEnhancementFunction_txx #include "itkAnisotropicDiffusionVesselEnhancementFunction.h" #include "vnl/algo/vnl_symmetric_eigensystem.h" namespace itk { template< class TImageType > AnisotropicDiffusionVesselEnhancementFunction< TImageType> ::AnisotropicDiffusionVesselEnhancementFunction() { RadiusType r; for( unsigned int i=0 ; i < ImageDimension ; i++ ) { r[i] = 1; } this->SetRadius(r); // Dummy neighborhood. NeighborhoodType it; it.SetRadius( r ); // Find the center index of the neighborhood. m_Center = it.Size() / 2; // Get the stride length for each axis. for(unsigned int i = 0; i < ImageDimension; i++) { m_xStride[i] = it.GetStride(i); } } template< class TImageType > typename AnisotropicDiffusionVesselEnhancementFunction< TImageType > ::TimeStepType AnisotropicDiffusionVesselEnhancementFunction ::ComputeGlobalTimeStep(void *GlobalData) const { /* returns the time step supplied by the user. We don't need to use the global data supplied since we are returning a fixed value */ return this->GetTimeStep(); } template< class TImageType > typename AnisotropicDiffusionVesselEnhancementFunction< TImageType >::PixelType AnisotropicDiffusionVesselEnhancementFunction< TImageType > ::ComputeUpdate(const NeighborhoodType &it, void *globalData, const FloatOffsetType& offset) { double value = 0.0; return (PixelType) (value); } template< class TImageType > typename AnisotropicDiffusionVesselEnhancementFunction< TImageType >::PixelType AnisotropicDiffusionVesselEnhancementFunction< TImageType > ::ComputeUpdate(const NeighborhoodType &it, const DiffusionTensorNeighborhoodType >, void *globalData, const FloatOffsetType& offset) { unsigned int i, j; // const ScalarValueType ZERO = NumericTraits::Zero; const ScalarValueType center_value = it.GetCenterPixel(); // Global data structure GlobalDataStruct *gd = (GlobalDataStruct *)globalData; // m_dx -> Intensity first derivative // m_dxy -> Intensity second derivative // m_DT_dxy -> Diffusion tensor first derivative // Compute the first and 2nd derivative gd->m_GradMagSqr = 1.0e-6; for( i = 0; i < ImageDimension; i++) { const unsigned int positionA = static_cast( m_Center + m_xStride[i]); const unsigned int positionB = static_cast( m_Center - m_xStride[i]); gd->m_dx[i] = 0.5 * (it.GetPixel( positionA ) - it.GetPixel( positionB ) ); gd->m_dxy[i][i] = it.GetPixel( positionA ) + it.GetPixel( positionB ) - 2.0 * center_value; for( j = i+1; j < ImageDimension; j++ ) { const unsigned int positionAa = static_cast( m_Center - m_xStride[i] - m_xStride[j] ); const unsigned int positionBa = static_cast( m_Center - m_xStride[i] + m_xStride[j] ); const unsigned int positionCa = static_cast( m_Center + m_xStride[i] - m_xStride[j] ); const unsigned int positionDa = static_cast( m_Center + m_xStride[i] + m_xStride[j] ); gd->m_dxy[i][j] = gd->m_dxy[j][i] = 0.25 *( it.GetPixel( positionAa ) - it.GetPixel( positionBa ) - it.GetPixel( positionCa ) + it.GetPixel( positionDa ) ); } } // Compute the diffusion tensor matrix first derivatives TensorPixelType center_Tensor_value = gt.GetCenterPixel(); for( i = 0; i < ImageDimension; i++) { const unsigned int positionA = static_cast( m_Center + m_xStride[i]); const unsigned int positionB = static_cast( m_Center - m_xStride[i]); TensorPixelType positionA_Tensor_value = gt.GetPixel( positionA ); TensorPixelType positionB_Tensor_value = gt.GetPixel( positionB ); for( j = 0; j < ImageDimension; j++) { gd->m_DT_dxy[i][j] = 0.5 * ( positionA_Tensor_value(i,j) - positionB_Tensor_value(i,j) ); } } ScalarValueType pdWrtDiffusion1; pdWrtDiffusion1 = gd->m_DT_dxy[0][0] * gd->m_dx[0] + gd->m_DT_dxy[0][1] * gd->m_dx[1] + gd->m_DT_dxy[0][2] * gd->m_dx[2]; ScalarValueType pdWrtDiffusion2; pdWrtDiffusion2 = gd->m_DT_dxy[1][0] * gd->m_dx[0] + gd->m_DT_dxy[1][1] * gd->m_dx[1] + gd->m_DT_dxy[1][2] * gd->m_dx[2]; ScalarValueType pdWrtDiffusion3; pdWrtDiffusion3 = gd->m_DT_dxy[2][0] * gd->m_dx[0] + gd->m_DT_dxy[2][1] * gd->m_dx[1] + gd->m_DT_dxy[2][2] * gd->m_dx[2]; ScalarValueType pdWrtImageIntensity1; pdWrtImageIntensity1 = center_Tensor_value(0,0) * gd->m_dxy[0][0] + center_Tensor_value(0,1) * gd->m_dxy[0][1] + center_Tensor_value(0,2) * gd->m_dxy[0][2]; ScalarValueType pdWrtImageIntensity2; pdWrtImageIntensity2 = center_Tensor_value(1,0) * gd->m_dxy[1][0] + center_Tensor_value(1,1) * gd->m_dxy[1][1] + center_Tensor_value(1,2) * gd->m_dxy[1][2]; ScalarValueType pdWrtImageIntensity3; pdWrtImageIntensity3 = center_Tensor_value(2,0) * gd->m_dxy[2][0] + center_Tensor_value(2,1) * gd->m_dxy[2][1] + center_Tensor_value(2,2) * gd->m_dxy[2][2]; ScalarValueType total; total = pdWrtDiffusion1 + pdWrtDiffusion2 + pdWrtDiffusion3 + pdWrtImageIntensity1 + pdWrtImageIntensity2 + pdWrtImageIntensity3; return ( PixelType ) ( total ); } template void AnisotropicDiffusionVesselEnhancementFunction:: PrintSelf(std::ostream& os, Indent indent) const { Superclass::PrintSelf(os, indent); } } // end namespace itk #endif vmtk-1.0.1/vtkVmtk/Segmentation/vtkvmtkGeodesicActiveContourLevelSetImageFilter.h0000664000175000017500000001467711757446472027076 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkGeodesicActiveContourLevelSetImageFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:48:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkGeodesicActiveContourLevelSetImageFilter - Wrapper class around itk::GeodesicActiveContourLevelSetImageFilter // .SECTION Description // vtkvmtkGeodesicActiveContourLevelSetImageFilter #ifndef __vtkvmtkGeodesicActiveContourLevelSetImageFilter_h #define __vtkvmtkGeodesicActiveContourLevelSetImageFilter_h #include "vtkvmtkITKImageToImageFilterFF.h" #include "itkGeodesicActiveContourLevelSetImageFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_SEGMENTATION_EXPORT vtkvmtkGeodesicActiveContourLevelSetImageFilter : public vtkvmtkITKImageToImageFilterFF { public: static vtkvmtkGeodesicActiveContourLevelSetImageFilter *New(); vtkTypeRevisionMacro(vtkvmtkGeodesicActiveContourLevelSetImageFilter, vtkvmtkITKImageToImageFilterFF); float GetIsoSurfaceValue () { DelegateITKOutputMacro(GetIsoSurfaceValue) ; }; void SetIsoSurfaceValue ( float value ) { DelegateITKInputMacro ( SetIsoSurfaceValue, value ); }; void SetNumberOfIterations ( int value ) { DelegateITKInputMacro ( SetNumberOfIterations, value ); }; void SetPropagationScaling ( float value ) { DelegateITKInputMacro ( SetPropagationScaling, value ); }; void SetCurvatureScaling ( float value ) { DelegateITKInputMacro ( SetCurvatureScaling, value ); }; void SetAdvectionScaling ( float value ) { DelegateITKInputMacro ( SetAdvectionScaling, value ); }; void SetMaximumRMSError ( float value ) { DelegateITKInputMacro ( SetMaximumRMSError, value ); }; void SetUseNegativeFeatures (int value ) { DelegateITKInputMacro( SetUseNegativeFeatures, value); } void SetUseImageSpacing (int value ) { DelegateITKInputMacro( SetUseImageSpacing, value); } void SetAutoGenerateSpeedAdvection (int value ) { DelegateITKInputMacro( SetAutoGenerateSpeedAdvection, value); } void SetInterpolateSurfaceLocation (int value ) { DelegateITKInputMacro( SetInterpolateSurfaceLocation, value); } void SetDerivativeSigma ( float value ) { DelegateITKInputMacro ( SetDerivativeSigma, value ); }; void SetFeatureImage ( vtkImageData *value) { this->vtkFeatureExporter->SetInput(value); } vtkImageData *GetSpeedImage() { this->vtkSpeedImporter->Update(); return this->vtkSpeedImporter->GetOutput(); } void SetFeatureScaling ( float value ) { DelegateITKInputMacro ( SetFeatureScaling, value ); }; float GetRMSChange () { DelegateITKOutputMacro(GetRMSChange); }; int GetElapsedIterations() { DelegateITKOutputMacro(GetElapsedIterations); }; float GetPropagationScaling ( ) { DelegateITKOutputMacro ( GetPropagationScaling ); }; float GetCurvatureScaling ( ) { DelegateITKOutputMacro ( GetCurvatureScaling ); }; float GetAdvectionScaling ( ) { DelegateITKOutputMacro ( GetAdvectionScaling ); }; int GetAutoGenerateSpeedAdvection ( ) { DelegateITKOutputMacro( GetAutoGenerateSpeedAdvection ); } int GetInterpolateSurfaceLocation ( ) { DelegateITKOutputMacro( GetInterpolateSurfaceLocation ); } float GetDerivativeSigma ( ) { DelegateITKOutputMacro ( GetDerivativeSigma ); }; // Description: Override vtkSource's Update so that we can access this class's GetOutput(). vtkSource's GetOutput is not virtual. void Update() { if (this->vtkFeatureExporter->GetInput()) { this->itkFeatureImporter->Update(); if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } } protected: //BTX typedef itk::GeodesicActiveContourLevelSetImageFilter ImageFilterType; typedef itk::VTKImageImport FeatureImageImportType; typedef itk::VTKImageExport SpeedImageExportType; vtkvmtkGeodesicActiveContourLevelSetImageFilter() : Superclass ( ImageFilterType::New() ) { this->vtkFeatureExporter = vtkImageExport::New(); this->itkFeatureImporter = FeatureImageImportType::New(); this->itkSpeedExporter = SpeedImageExportType::New(); this->vtkSpeedImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkSpeedImporter->SetScalarArrayName("Scalars_"); #endif ConnectPipelines(this->itkSpeedExporter, this->vtkSpeedImporter); ConnectPipelines(this->vtkFeatureExporter, this->itkFeatureImporter); (dynamic_cast(m_Filter.GetPointer()))->SetFeatureImage(this->itkFeatureImporter->GetOutput()); this->itkSpeedExporter->SetInput((dynamic_cast(m_Filter.GetPointer()))->GetSpeedImage()); }; ~vtkvmtkGeodesicActiveContourLevelSetImageFilter() { this->vtkSpeedImporter->Delete(); this->vtkFeatureExporter->Delete(); }; ImageFilterType* GetImageFilterPointer() { return dynamic_cast ( m_Filter.GetPointer() ); } FeatureImageImportType::Pointer itkFeatureImporter; SpeedImageExportType::Pointer itkSpeedExporter; //ETX vtkImageExport *vtkFeatureExporter; vtkImageImport *vtkSpeedImporter; private: vtkvmtkGeodesicActiveContourLevelSetImageFilter(const vtkvmtkGeodesicActiveContourLevelSetImageFilter&); // Not implemented. void operator=(const vtkvmtkGeodesicActiveContourLevelSetImageFilter&); // // Not implemented }; #endif vmtk-1.0.1/vtkVmtk/Wrapping/0000775000175000017500000000000011757446472014404 5ustar lucalucavmtk-1.0.1/vtkVmtk/Wrapping/JavaDependencies.cmake.in0000664000175000017500000000022111757446472021176 0ustar lucaluca# This file is automatically generated by CMake VTK_WRAP_JAVA SET(VTK_JAVA_DEPENDENCIES ${VTK_JAVA_DEPENDENCIES} @VTK_JAVA_DEPENDENCIES_FILE@ ) vmtk-1.0.1/vtkVmtk/Wrapping/hints0000664000175000017500000000000011757446472015442 0ustar lucalucavmtk-1.0.1/vtkVmtk/Wrapping/vtkWrapperInit.data.in0000664000175000017500000000003011757446472020626 0ustar lucaluca@VTK_WRAPPER_INIT_DATA@ vmtk-1.0.1/vtkVmtk/Wrapping/Tcl/0000775000175000017500000000000011757446472015126 5ustar lucalucavmtk-1.0.1/vtkVmtk/Wrapping/Tcl/hints0000664000175000017500000000000011757446472016164 0ustar lucalucavmtk-1.0.1/vtkVmtk/Wrapping/Tcl/MakePackages.tcl0000664000175000017500000000066511757446472020155 0ustar lucaluca#!/usr/bin/env tclsh # Execute this script each time you add a new directory or file. # Packages #pkg_mkIndex -direct -verbose vtkvmtk #pkg_mkIndex -direct -verbose vtkvmtkcommon #pkg_mkIndex -direct -verbose vtkvmtkcomputationalgeometry #pkg_mkIndex -direct -verbose vtkvmtkdifferentialgeometry #pkg_mkIndex -direct -verbose vtkvmtkio #pkg_mkIndex -direct -verbose vtkvmtkmisc #pkg_mkIndex -direct -verbose vtkvmtksegmentation exit vmtk-1.0.1/vtkVmtk/Common/0000775000175000017500000000000011757446472014045 5ustar lucalucavmtk-1.0.1/vtkVmtk/Common/vtkvmtkMath.cxx0000664000175000017500000001753211757446472017121 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMath.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:47:30 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMath, "$Revision: 1.0 $"); vtkStandardNewMacro(vtkvmtkMath); double vtkvmtkMath::Cotangent(double point0[3], double point1[3], double point2[3]) { double norm0Squared, norm1Squared, dot, crossNorm, cotangent; norm0Squared = (point0[0]-point1[0])*(point0[0]-point1[0]) + (point0[1]-point1[1])*(point0[1]-point1[1]) + (point0[2]-point1[2])*(point0[2]-point1[2]); norm1Squared = (point2[0]-point1[0])*(point2[0]-point1[0]) + (point2[1]-point1[1])*(point2[1]-point1[1]) + (point2[2]-point1[2])*(point2[2]-point1[2]); dot = (point0[0]-point1[0])*(point2[0]-point1[0]) + (point0[1]-point1[1])*(point2[1]-point1[1]) + (point0[2]-point1[2])*(point2[2]-point1[2]); crossNorm = sqrt(norm0Squared * norm1Squared - dot*dot); cotangent = 0.0; if (crossNorm < GetTolerance(crossNorm)) { if (fabs(dot) < GetTolerance(dot)) cotangent = 0.0; else cotangent = GetLarge(cotangent); } else if (fabs(dot) < GetTolerance(dot)) { cotangent = 0.0; } else { cotangent = dot / crossNorm; } return cotangent; } double vtkvmtkMath::TriangleArea(double point0[3], double point1[3], double point2[3]) { double norm0Squared, norm1Squared, dot, crossNorm; norm0Squared = (point0[0]-point1[0])*(point0[0]-point1[0]) + (point0[1]-point1[1])*(point0[1]-point1[1]) + (point0[2]-point1[2])*(point0[2]-point1[2]); norm1Squared = (point2[0]-point1[0])*(point2[0]-point1[0]) + (point2[1]-point1[1])*(point2[1]-point1[1]) + (point2[2]-point1[2])*(point2[2]-point1[2]); dot = (point0[0]-point1[0])*(point2[0]-point1[0]) + (point0[1]-point1[1])*(point2[1]-point1[1]) + (point0[2]-point1[2])*(point2[2]-point1[2]); crossNorm = sqrt(norm0Squared * norm1Squared - dot*dot); if (crossNorm < GetTolerance(crossNorm)) crossNorm = 0.0; return 0.5 * crossNorm; } int vtkvmtkMath::IsAngleObtuse(double point0[3], double point1[3], double point2[3]) { if ((point0[0]-point1[0])*(point2[0]-point1[0]) + (point0[1]-point1[1])*(point2[1]-point1[1]) + (point0[2]-point1[2])*(point2[2]-point1[2])GetTolerance(scalar0))||(fabs(scalar1-scalar2)>GetTolerance(scalar1))||(fabs(scalar2-scalar0)>GetTolerance(scalar2))) return GetLarge(scalar0); else return 0.0; } vector0[0] = point2[0] - point1[0]; vector0[1] = point2[1] - point1[1]; vector0[2] = point2[2] - point1[2]; vector1[0] = point0[0] - point2[0]; vector1[1] = point0[1] - point2[1]; vector1[2] = point0[2] - point2[2]; vector2[0] = point1[0] - point0[0]; vector2[1] = point1[1] - point0[1]; vector2[2] = point1[2] - point0[2]; vtkMath::Cross(vector0,vector1,triangleNormal); vtkMath::Normalize(triangleNormal); gradientNormalVector[0] = vector0[0]*scalar0 + vector1[0]*scalar1 + vector2[0]*scalar2; gradientNormalVector[1] = vector0[1]*scalar0 + vector1[1]*scalar1 + vector2[1]*scalar2; gradientNormalVector[2] = vector0[2]*scalar0 + vector1[2]*scalar1 + vector2[2]*scalar2; gradientNormalVector[0] /= 2.0*area; gradientNormalVector[1] /= 2.0*area; gradientNormalVector[2] /= 2.0*area; gradientNorm = vtkMath::Norm(gradientNormalVector); vtkMath::Cross(triangleNormal,gradientNormalVector,gradientDirection); vtkMath::Normalize(gradientDirection); gradient[0] = gradientNorm * gradientDirection[0]; gradient[1] = gradientNorm * gradientDirection[1]; gradient[2] = gradientNorm * gradientDirection[2]; return gradientNorm; } void vtkvmtkMath::TwoSphereIntersection(double center0[3], double radius0, double center1[3], double radius1, double origin[3], double normal[3]) { double distance, displacement, squaredRadiusDifference, displacementRatio; normal[0] = center1[0] - center0[0]; normal[1] = center1[1] - center0[1]; normal[2] = center1[2] - center0[2]; distance = vtkMath::Normalize(normal); if (distance GetTolerance(distance)) { displacement = 0.5 * (displacementRatio + distance); } else { if (squaredRadiusDifference > GetTolerance(distance)) { displacement = 0.5 * (displacementRatio - distance); } else { displacement = 0.5 * (displacementRatio + distance); } } origin[0] = center0[0] + displacement * normal[0]; origin[1] = center0[1] + displacement * normal[1]; origin[2] = center0[2] + displacement * normal[2]; } double vtkvmtkMath::AngleBetweenNormals(double normal0[3], double normal1[3]) { double sum[3], difference[3]; double sumNorm, differenceNorm; sum[0] = normal0[0] + normal1[0]; sum[1] = normal0[1] + normal1[1]; sum[2] = normal0[2] + normal1[2]; sumNorm = vtkMath::Norm(sum); difference[0] = normal0[0] - normal1[0]; difference[1] = normal0[1] - normal1[1]; difference[2] = normal0[2] - normal1[2]; differenceNorm = vtkMath::Norm(difference); return 2.0 * atan2(differenceNorm,sumNorm); } double vtkvmtkMath::EvaluateSphereFunction(double center[3], double radius, double point[3]) { return (center[0]-point[0]) * (center[0]-point[0]) + (center[1]-point[1]) * (center[1]-point[1]) + (center[2]-point[2]) * (center[2]-point[2]) - radius * radius; } vmtk-1.0.1/vtkVmtk/Common/vtkvmtkCocoaRenderWindowInteractor.h0000664000175000017500000000351711757446472023262 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCocoaRenderWindowInteractor.h,v $ Language: C++ Date: $Date: 2010/05/05 16:46:43 $ Version: $Revision: 1.0 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCocoaRenderWindowInteractor - .. // .SECTION Description // .. #ifndef __vtkvmtkCocoaRenderWindowInteractor_h #define __vtkvmtkCocoaRenderWindowInteractor_h #include "vtkCocoaRenderWindowInteractor.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMMON_EXPORT vtkvmtkCocoaRenderWindowInteractor : public vtkCocoaRenderWindowInteractor { public: static vtkvmtkCocoaRenderWindowInteractor *New(); vtkTypeRevisionMacro(vtkvmtkCocoaRenderWindowInteractor,vtkCocoaRenderWindowInteractor); void PrintSelf(ostream& os, vtkIndent indent); virtual void TerminateApp(); virtual void Close(); vtkSetMacro(CloseWindowOnTerminateApp,int); vtkGetMacro(CloseWindowOnTerminateApp,int); vtkBooleanMacro(CloseWindowOnTerminateApp,int); protected: vtkvmtkCocoaRenderWindowInteractor(); ~vtkvmtkCocoaRenderWindowInteractor(); int CloseWindowOnTerminateApp; private: vtkvmtkCocoaRenderWindowInteractor(const vtkvmtkCocoaRenderWindowInteractor&); // Not implemented. void operator=(const vtkvmtkCocoaRenderWindowInteractor&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Common/vtkvmtkWin32Header.h0000664000175000017500000001357711757446472017675 0ustar lucaluca/*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkvmtkWin32Header.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 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. =========================================================================*/ // .NAME vtkWin32Header - manage Windows system differences // .SECTION Description // The vtkWin32Header captures some system differences between Unix and // Windows operating systems. #ifndef __vtkvmtkWIN32Header_h #define __vtkvmtkWIN32Header_h //#ifndef __VTK_SYSTEM_INCLUDES__INSIDE //Do_not_include_vtkWin32Header_directly__vtkSystemIncludes_includes_it; //#endif #include // // Windows specific stuff------------------------------------------ #if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) // define strict header for windows #ifndef STRICT #define STRICT #endif #ifdef VTK_USE_ANSI_STDLIB #ifndef NOMINMAX #define NOMINMAX #endif #endif #endif // Never include the windows header here when building VTK itself. #if defined(VTK_IN_VTK) # undef VTK_INCLUDE_WINDOWS_H #endif #if defined(_WIN32) // Include the windows header here only if requested by user code. # if defined(VTK_INCLUDE_WINDOWS_H) # include // Define types from the windows header file. typedef DWORD vtkWindowsDWORD; typedef PVOID vtkWindowsPVOID; typedef LPVOID vtkWindowsLPVOID; typedef HANDLE vtkWindowsHANDLE; typedef LPTHREAD_START_ROUTINE vtkWindowsLPTHREAD_START_ROUTINE; # else // Define types from the windows header file. typedef unsigned long vtkWindowsDWORD; typedef void* vtkWindowsPVOID; typedef vtkWindowsPVOID vtkWindowsLPVOID; typedef vtkWindowsPVOID vtkWindowsHANDLE; typedef vtkWindowsDWORD (__stdcall *vtkWindowsLPTHREAD_START_ROUTINE)(vtkWindowsLPVOID); # endif // Enable workaround for windows header name mangling. // See VTK/Utilities/Upgrading/README.WindowsMangling.txt for details. # define VTK_WORKAROUND_WINDOWS_MANGLE #endif #if defined(_MSC_VER) // Enable MSVC compiler warning messages that are useful but off by default. # pragma warning ( default : 4263 ) /* no override, call convention differs */ // Disable MSVC compiler warning messages that often occur in valid code. # if !defined(VTK_DISPLAY_WIN32_WARNINGS) # pragma warning ( disable : 4097 ) /* typedef is synonym for class */ # pragma warning ( disable : 4127 ) /* conditional expression is constant */ # pragma warning ( disable : 4244 ) /* possible loss in conversion */ # pragma warning ( disable : 4251 ) /* missing DLL-interface */ # pragma warning ( disable : 4305 ) /* truncation from type1 to type2 */ # pragma warning ( disable : 4309 ) /* truncation of constant value */ # pragma warning ( disable : 4514 ) /* unreferenced inline function */ # pragma warning ( disable : 4706 ) /* assignment in conditional expression */ # pragma warning ( disable : 4710 ) /* function not inlined */ # pragma warning ( disable : 4786 ) /* identifier truncated in debug info */ # endif #endif // MSVC 6.0 in release mode will warn about code it produces with its // optimizer. Disable the warnings specifically for this // configuration. Real warnings will be revealed by a debug build or // by other compilers. #if defined(_MSC_VER) && (_MSC_VER < 1300) && defined(NDEBUG) # pragma warning ( disable : 4701 ) /* Variable may be used uninitialized. */ # pragma warning ( disable : 4702 ) /* Unreachable code. */ #endif #if defined(WIN32) && defined(VTK_VMTK_BUILD_SHARED_LIBS) // #define VTK_EXPORT __declspec( dllexport ) #if defined(vtkvmtkCommon_EXPORTS) #define VTK_VMTK_COMMON_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_COMMON_EXPORT __declspec( dllimport ) #endif #if defined(vtkvmtkComputationalGeometry_EXPORTS) #define VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT __declspec( dllimport ) #endif #if defined(vtkvmtkDifferentialGeometry_EXPORTS) #define VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT __declspec( dllimport ) #endif #if defined(vtkvmtkIO_EXPORTS) #define VTK_VMTK_IO_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_IO_EXPORT __declspec( dllimport ) #endif #if defined(vtkvmtkMisc_EXPORTS) #define VTK_VMTK_MISC_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_MISC_EXPORT __declspec( dllimport ) #endif // #if defined(vtkvmtkITK_EXPORTS) #define VTK_VMTK_ITK_EXPORT __declspec( dllexport ) // #else // #define VTK_ITK_EXPORT __declspec( dllimport ) // #endif #if defined(vtkvmtkSegmentation_EXPORTS) #define VTK_VMTK_SEGMENTATION_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_SEGMENTATION_EXPORT __declspec( dllimport ) #endif #if defined(vtkvmtkContrib_EXPORTS) #define VTK_VMTK_CONTRIB_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_CONTRIB_EXPORT __declspec( dllimport ) #endif #if defined(vtkvmtkRendering_EXPORTS) #define VTK_VMTK_RENDERING_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_RENDERING_EXPORT __declspec( dllimport ) #endif #else #define VTK_VMTK_COMMON_EXPORT #define VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT #define VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT #define VTK_VMTK_IO_EXPORT #define VTK_VMTK_MISC_EXPORT #define VTK_VMTK_ITK_EXPORT #define VTK_VMTK_SEGMENTATION_EXPORT #define VTK_VMTK_CONTRIB_EXPORT #define VTK_VMTK_RENDERING_EXPORT #endif // this is exclusively for the tcl Init functions #if defined(WIN32) // #define VTK_TK_EXPORT __declspec( dllexport ) #else // #define VTK_TK_EXPORT #endif #endif vmtk-1.0.1/vtkVmtk/Common/CMakeLists.txt0000664000175000017500000001155011757446472016607 0ustar lucalucaSET (VTK_VMTK_COMMON_SRCS vtkvmtkMath.cxx ) SET (VTK_VMTK_COMMON_TARGET_LINK_LIBRARIES vtkCommon) IF(APPLE) IF(VTK_VMTK_USE_COCOA) SET(VTK_VMTK_COCOA_OBJC_SRCS vtkvmtkCocoaServer.mm vtkvmtkCocoaGLView.mm) SET(VTK_VMTK_COCOA_SRCS vtkvmtkCocoaRenderWindowInteractor.mm) SET(VTK_VMTK_COMMON_SRCS ${VTK_VMTK_COMMON_SRCS} ${VTK_VMTK_COCOA_SRCS} ${VTK_VMTK_COCOA_OBJC_SRCS}) IF(VTK_REQUIRED_OBJCXX_FLAGS) SET_SOURCE_FILES_PROPERTIES(${VTK_VMTK_COCOA_SRCS} PROPERTIES COMPILE_FLAGS "${VTK_REQUIRED_OBJCXX_FLAGS}") SET_SOURCE_FILES_PROPERTIES(${VTK_VMTK_COCOA_OBJC_SRCS} PROPERTIES COMPILE_FLAGS "${VTK_REQUIRED_OBJCXX_FLAGS}") ENDIF(VTK_REQUIRED_OBJCXX_FLAGS) SET_SOURCE_FILES_PROPERTIES(${VTK_VMTK_COCOA_OBJC_SRCS} WRAP_EXCLUDE) SET (VTK_VMTK_COMMON_TARGET_LINK_LIBRARIES ${VTK_VMTK_COMMON_TARGET_LINK_LIBRARIES} vtkRendering ${OPENGL_gl_LIBRARY} "-framework Cocoa") ENDIF(VTK_VMTK_USE_COCOA) ENDIF(APPLE) ADD_LIBRARY (vtkvmtkCommon ${VTK_VMTK_COMMON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkCommon PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkCommon PROPERTIES LINKER_LANGUAGE CXX) TARGET_LINK_LIBRARIES(vtkvmtkCommon ${VTK_VMTK_COMMON_TARGET_LINK_LIBRARIES}) INSTALL(TARGETS vtkvmtkCommon LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_COMMON_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/Common/*.h") #INSTALL(FILES ${files} vtkvmtkConstants.h vtkvmtkWin32Header.h DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR}) INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkCommon) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkCommonPython VTK_VMTK_COMMON_PYTHON_SRCS "${VTK_VMTK_COMMON_SRCS}") ADD_LIBRARY(vtkvmtkCommonPythonD ${VTK_VMTK_COMMON_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkCommonPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkCommonPython MODULE vtkvmtkCommonPythonInit.cxx) IF(APPLE AND VTK_VMTK_USE_COCOA) TARGET_LINK_LIBRARIES(vtkvmtkCommonPythonD vtkvmtkCommon vtkCommon vtkCommonPythonD vtkRendering vtkRenderingPythonD) ELSE(APPLE AND VTK_VMTK_USE_COCOA) TARGET_LINK_LIBRARIES(vtkvmtkCommonPythonD vtkvmtkCommon vtkCommon vtkCommonPythonD) ENDIF(APPLE AND VTK_VMTK_USE_COCOA) IF(NOT WIN32) SET_TARGET_PROPERTIES(vtkvmtkCommonPython PROPERTIES COMPILE_FLAGS -fPIC) ENDIF(NOT WIN32) TARGET_LINK_LIBRARIES (vtkvmtkCommonPython vtkvmtkCommonPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkCommonPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkCommonPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkCommonPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkCommonTCL VTK_VMTK_COMMON_TCL_SRCS "${VTK_VMTK_COMMON_SRCS}" "") ADD_LIBRARY(vtkvmtkCommonTCL ${VTK_VMTK_COMMON_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkCommonTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) IF(APPLE AND VTK_VMTK_USE_COCOA) TARGET_LINK_LIBRARIES(vtkvmtkCommonTCL vtkvmtkCommon vtkCommon vtkCommonTCL vtkRendering vtkRenderingTCL) ELSE(APPLE AND VTK_VMTK_USE_COCOA) TARGET_LINK_LIBRARIES(vtkvmtkCommonTCL vtkvmtkCommon vtkCommon vtkCommonTCL) ENDIF(APPLE AND VTK_VMTK_USE_COCOA) INSTALL(TARGETS vtkvmtkCommonTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkCommonTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/Common/vtkvmtkCocoaServer.mm0000664000175000017500000000352511757446472020247 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCocoaServer.h,v $ Language: C++ Date: $Date: 2010/01/08 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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. =========================================================================*/ #import "vtkvmtkCocoaServer.h" #import "vtkCocoaRenderWindow.h" @implementation vtkCocoaServer(vtkvmtkCocoaServer) - (void)start { NSWindow *win = nil; if (renWin != NULL) { #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 5) win = reinterpret_cast(renWin->GetRootWindow()); #else win = reinterpret_cast(renWin->GetWindowId()); #endif if (win != nil) { NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(windowWillClose:) name:@"NSWindowWillCloseNotification" object:win]; } } [NSApp activateIgnoringOtherApps:YES]; [NSApp run]; } - (void)stop { [NSApp stop:NSApp]; } - (void)close { NSWindow *win = nil; if (renWin != NULL) { #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 5) win = reinterpret_cast(renWin->GetRootWindow()); #else win = reinterpret_cast(renWin->GetWindowId()); #endif } [win close]; } @end vmtk-1.0.1/vtkVmtk/Common/vtkvmtkCocoaGLView.h0000664000175000017500000000202611757446472017747 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCocoaGLView.h,v $ Language: C++ Date: $Date: 2010/01/08 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCocoaGLView - .. // .SECTION Description // .. #ifndef __vtkvmtkCocoaGLView_h #define __vtkvmtkCocoaGLView_h #import #import "vtkCocoaGLView.h" @interface vtkCocoaGLView(vtkvmtkCocoaGLView) - (void)mouseDown:(NSEvent *)theEvent; @end #endif vmtk-1.0.1/vtkVmtk/Common/vtkvmtkCocoaGLView.mm0000664000175000017500000000624511757446472020140 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCocoaGLView.mm,v $ Language: C++ Date: $Date: 2010/01/08 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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. =========================================================================*/ #import "vtkvmtkCocoaGLView.h" #import "vtkCocoaRenderWindow.h" #import "vtkCocoaRenderWindowInteractor.h" #import "vtkCommand.h" @implementation vtkCocoaGLView(vtkvmtkCocoaGLView) - (void)mouseDown:(NSEvent *)theEvent { vtkCocoaRenderWindowInteractor *interactor = [self getInteractor]; if (!interactor) { return; } vtkCocoaRenderWindow* renWin = vtkCocoaRenderWindow::SafeDownCast([self getVTKRenderWindow]); if (!renWin) { return; } double factor = renWin->GetScaleFactor(); BOOL keepOn = YES; NSPoint mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; int shiftDown = ([theEvent modifierFlags] & NSShiftKeyMask); int controlDown = ([theEvent modifierFlags] & NSControlKeyMask); int commandDown = ([theEvent modifierFlags] & NSCommandKeyMask); int optionDown = ([theEvent modifierFlags] & NSAlternateKeyMask); interactor->SetEventInformation((int)round(mouseLoc.x * factor), (int)round(mouseLoc.y * factor), controlDown, shiftDown); if (commandDown) { interactor->InvokeEvent(vtkCommand::RightButtonPressEvent,NULL); } else if (optionDown) { interactor->InvokeEvent(vtkCommand::MiddleButtonPressEvent,NULL); } else { interactor->InvokeEvent(vtkCommand::LeftButtonPressEvent,NULL); } [[self nextResponder] mouseDown:theEvent]; NSDate* infinity = [NSDate distantFuture]; do { theEvent = [NSApp nextEventMatchingMask: NSLeftMouseUpMask | NSLeftMouseDraggedMask untilDate: infinity inMode: NSEventTrackingRunLoopMode dequeue: YES]; if (theEvent) { mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; interactor->SetEventInformation( (int)round(mouseLoc.x * factor), (int)round(mouseLoc.y * factor), controlDown, shiftDown); switch ([theEvent type]) { case NSLeftMouseDragged: interactor->InvokeEvent(vtkCommand::MouseMoveEvent, NULL); break; case NSLeftMouseUp: if (commandDown) { interactor->InvokeEvent(vtkCommand::RightButtonReleaseEvent, NULL); } else if (optionDown) { interactor->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent, NULL); } else { interactor->InvokeEvent(vtkCommand::LeftButtonReleaseEvent, NULL); } keepOn = NO; default: break; } } else { keepOn = NO; } } while (keepOn); } @end vmtk-1.0.1/vtkVmtk/Common/vtkvmtkCocoaRenderWindowInteractor.mm0000664000175000017500000000431611757446472023442 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCocoaRenderWindowInteractor.mm,v $ Language: C++ Date: $Date: 2010/01/08 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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. =========================================================================*/ #import "vtkvmtkCocoaServer.h" #import "vtkvmtkCocoaRenderWindowInteractor.h" #import "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCocoaRenderWindowInteractor, "$Revision: 1.70 $"); vtkStandardNewMacro(vtkvmtkCocoaRenderWindowInteractor); vtkvmtkCocoaRenderWindowInteractor::vtkvmtkCocoaRenderWindowInteractor() { this->CloseWindowOnTerminateApp = 0; } vtkvmtkCocoaRenderWindowInteractor::~vtkvmtkCocoaRenderWindowInteractor() { } void vtkvmtkCocoaRenderWindowInteractor::Close() { vtkCocoaRenderWindow *renWin = vtkCocoaRenderWindow::SafeDownCast(this->RenderWindow); if (renWin) { vtkCocoaServer *server = reinterpret_cast(this->GetCocoaServer()); [server close]; this->SetCocoaServer(NULL); } } void vtkvmtkCocoaRenderWindowInteractor::TerminateApp() { vtkCocoaRenderWindow *renWin = vtkCocoaRenderWindow::SafeDownCast(this->RenderWindow); if (renWin) { int windowCreated = renWin->GetWindowCreated(); if (windowCreated) { vtkCocoaServer *server = reinterpret_cast(this->GetCocoaServer()); if (this->CloseWindowOnTerminateApp) { [server close]; this->SetCocoaServer(NULL); } else { [server stop]; } } else { [NSApp terminate:NSApp]; } } } void vtkvmtkCocoaRenderWindowInteractor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Common/vtkvmtkConstants.h0000664000175000017500000000333611757446472017626 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkConstants.h,v $ Language: C++ Date: $Date: 2005/11/15 17:39:24 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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. =========================================================================*/ #ifndef VTK_VMTK_LARGE_INTEGER #define VTK_VMTK_LARGE_INTEGER 2147483647 #endif #ifndef VTK_VMTK_FLOAT_TOL #define VTK_VMTK_FLOAT_TOL 1.0E-6 #endif #ifndef VTK_VMTK_LARGE_FLOAT #define VTK_VMTK_LARGE_FLOAT 1.0E+16 #endif #ifndef VTK_VMTK_DOUBLE_TOL #define VTK_VMTK_DOUBLE_TOL 1.0E-12 #endif #ifndef VTK_VMTK_LARGE_DOUBLE #define VTK_VMTK_LARGE_DOUBLE 1.0E+32 #endif #ifndef VTK_VMTK_PIVOTING_TOL #define VTK_VMTK_PIVOTING_TOL 1.0E-12 #endif #ifndef VTK_VMTK_ITEM_TYPES #define VTK_VMTK_ITEM_TYPES enum { VTK_VMTK_EMPTY_NEIGHBORHOOD, VTK_VMTK_POLYDATA_NEIGHBORHOOD, VTK_VMTK_POLYDATA_MANIFOLD_NEIGHBORHOOD, VTK_VMTK_POLYDATA_MANIFOLD_EXTENDED_NEIGHBORHOOD, VTK_VMTK_UNSTRUCTUREDGRID_NEIGHBORHOOD, VTK_VMTK_EMPTY_STENCIL, VTK_VMTK_UMBRELLA_STENCIL, VTK_VMTK_AREA_WEIGHTED_UMBRELLA_STENCIL, VTK_VMTK_GRADIENT_STENCIL, VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL, VTK_VMTK_FVFE_LAPLACE_BELTRAMI_STENCIL, VTK_VMTK_SPARSE_MATRIX_ROW, }; #endif vmtk-1.0.1/vtkVmtk/Common/vtkvmtkMath.h0000664000175000017500000000517311757446472016544 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkTMath.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkMath - .. // .SECTION Description // .. #ifndef __vtkvmtkMath_h #define __vtkvmtkMath_h #include "vtkObject.h" #include "vtkMath.h" #include "vtkvmtkConstants.h" #include "vtkvmtkWin32Header.h" #define VTK_VMTK_NON_OBTUSE 0 #define VTK_VMTK_OBTUSE_IN_POINT 1 #define VTK_VMTK_OBTUSE_NOT_IN_POINT 2 class VTK_VMTK_COMMON_EXPORT vtkvmtkMath : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkMath,vtkObject); // vtkTypeMacro(vtkvmtkMath,vtkObject); static vtkvmtkMath* New(); static double Cotangent(double point0[3], double point1[3], double point2[3]); static double TriangleArea(double point0[3], double point1[3], double point2[3]); static int IsAngleObtuse(double point0[3], double point1[3], double point2[3]); static int IsTriangleObtuse(double point0[3], double point1[3], double point2[3]); static double VoronoiSectorArea(double point0[3], double point1[3], double point2[3]); static double TriangleGradient(double point0[3], double point1[3], double point2[3], double scalar0, double scalar1, double scalar2, double gradient[3]); static void TwoSphereIntersection(double center0[3], double radius0, double center1[3], double radius1, double origin[3], double normal[3]); static double AngleBetweenNormals(double normal0[3], double normal1[3]); static double EvaluateSphereFunction(double center[3], double radius, double point[3]); protected: vtkvmtkMath() {}; ~vtkvmtkMath() {}; static double GetTolerance(float cookie) { return VTK_VMTK_FLOAT_TOL; } static double GetTolerance(double cookie) { return VTK_VMTK_DOUBLE_TOL; } static double GetLarge(float cookie) { return VTK_VMTK_LARGE_FLOAT; } static double GetLarge(double cookie) { return VTK_VMTK_LARGE_DOUBLE; } private: vtkvmtkMath(const vtkvmtkMath&); // Not implemented. void operator=(const vtkvmtkMath&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Common/vtkvmtkCocoaServer.h0000664000175000017500000000233211757446472020060 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCocoaServer.h,v $ Language: C++ Date: $Date: 2010/01/08 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCocoaServer - .. // .SECTION Description // .. #ifndef __vtkvmtkCocoaServer_h #define __vtkvmtkCocoaServer_h #import #import "vtkCocoaRenderWindow.h" @interface vtkCocoaServer : NSObject { vtkCocoaRenderWindow* renWin; } + (id)cocoaServerWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow; - (void)start; - (void)stop; - (void)close; @end @interface vtkCocoaServer(vtkvmtkCocoaServer) - (void)start; - (void)stop; @end #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/0000775000175000017500000000000011757446472017150 5ustar lucalucavmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineEndpointExtractor.cxx0000664000175000017500000001153311757446472027013 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineEndpointExtractor.cxx,v $ Language: C++ Date: $Date: 2005/10/06 11:01:44 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineEndpointExtractor.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineEndpointExtractor, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkCenterlineEndpointExtractor); vtkvmtkCenterlineEndpointExtractor::vtkvmtkCenterlineEndpointExtractor() { this->NumberOfEndpointSpheres = 2; this->NumberOfGapSpheres = 1; this->ExtractionMode = VTK_VMTK_BOTH_ENDPOINTS; } vtkvmtkCenterlineEndpointExtractor::~vtkvmtkCenterlineEndpointExtractor() { } void vtkvmtkCenterlineEndpointExtractor::ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) { this->NumberOfSplittingPoints = 0; if (this->SubIds) { delete[] this->SubIds; this->SubIds = NULL; } if (this->PCoords) { delete[] this->PCoords; this->PCoords = NULL; } if (this->TractBlanking) { delete[] this->TractBlanking; this->TractBlanking = NULL; } vtkCell* centerline = input->GetCell(cellId); if (centerline->GetCellType() != VTK_LINE && centerline->GetCellType() != VTK_POLY_LINE) { return; } this->NumberOfSplittingPoints = 4; if (this->ExtractionMode == VTK_VMTK_FIRST_ENDPOINT || this->ExtractionMode == VTK_VMTK_LAST_ENDPOINT) { this->NumberOfSplittingPoints = 2; } this->SubIds = new vtkIdType[this->NumberOfSplittingPoints]; this->PCoords = new double[this->NumberOfSplittingPoints]; vtkIdType firstSubId, lastSubId; double firstPCoord, lastPCoord; firstSubId = 0; firstPCoord = 0.0; lastSubId = centerline->GetNumberOfPoints() - 2; lastPCoord = 1.0; if (this->ExtractionMode == VTK_VMTK_FIRST_ENDPOINT) { vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,firstSubId,firstPCoord,this->NumberOfEndpointSpheres,this->SubIds[0],this->PCoords[0],false); vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,this->SubIds[0],this->PCoords[0],this->NumberOfGapSpheres,this->SubIds[1],this->PCoords[1],false); } else if (this->ExtractionMode == VTK_VMTK_LAST_ENDPOINT) { vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,lastSubId,lastPCoord,this->NumberOfEndpointSpheres,this->SubIds[1],this->PCoords[1],true); vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,this->SubIds[1],this->PCoords[1],this->NumberOfGapSpheres,this->SubIds[0],this->PCoords[0],true); if (this->SubIds[0] == -1) { this->SubIds[0] = 0; this->PCoords[0] = 0.0; } if (this->SubIds[1] == -1) { this->SubIds[1] = 0; this->PCoords[1] = 0.0; } } else { vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,firstSubId,firstPCoord,this->NumberOfEndpointSpheres,this->SubIds[0],this->PCoords[0],false); vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,this->SubIds[0],this->PCoords[0],this->NumberOfGapSpheres,this->SubIds[1],this->PCoords[1],false); vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,lastSubId,lastPCoord,this->NumberOfEndpointSpheres,this->SubIds[3],this->PCoords[3],true); vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,this->SubIds[3],this->PCoords[3],this->NumberOfGapSpheres,this->SubIds[2],this->PCoords[2],true); } this->TractBlanking = new int[this->NumberOfSplittingPoints+1]; if (this->ExtractionMode == VTK_VMTK_FIRST_ENDPOINT || this->ExtractionMode == VTK_VMTK_LAST_ENDPOINT) { this->TractBlanking[0] = 0; this->TractBlanking[1] = 1; this->TractBlanking[2] = 0; } else { this->TractBlanking[0] = 0; this->TractBlanking[1] = 1; this->TractBlanking[2] = 0; this->TractBlanking[3] = 1; this->TractBlanking[4] = 0; } } void vtkvmtkCenterlineEndpointExtractor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSplitExtractor.h0000664000175000017500000000513411757446472025753 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineSplitExtractor.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCenterlineSplitExtractor - ... // .SECTION Description // ... #ifndef __vtkvmtkCenterlineSplitExtractor_h #define __vtkvmtkCenterlineSplitExtractor_h #include "vtkvmtkCenterlineSplittingAndGroupingFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineSplitExtractor : public vtkvmtkCenterlineSplittingAndGroupingFilter { public: vtkTypeRevisionMacro(vtkvmtkCenterlineSplitExtractor,vtkvmtkCenterlineSplittingAndGroupingFilter); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineSplitExtractor *New(); vtkSetVectorMacro(SplitPoint,double,3); vtkGetVectorMacro(SplitPoint,double,3); vtkSetMacro(Tolerance,double); vtkGetMacro(Tolerance,double); vtkSetMacro(GapLength,double); vtkGetMacro(GapLength,double); vtkSetVectorMacro(SplitPoint2,double,3); vtkGetVectorMacro(SplitPoint2,double,3); vtkSetMacro(SplittingMode,int); vtkGetMacro(SplittingMode,int); void SetSplittingModeToPointAndGap() { this->SetSplittingMode(POINTANDGAP); } void SetSplittingModeToBetweenPoints() { this->SetGroupingMode(BETWEENPOINTS); } //BTX enum { POINTANDGAP, BETWEENPOINTS }; //ETX protected: vtkvmtkCenterlineSplitExtractor(); ~vtkvmtkCenterlineSplitExtractor(); virtual void ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId); virtual void ComputePointAndGapCenterlineSplitting(vtkPolyData* input, vtkIdType cellId); virtual void ComputeBetweenPointsCenterlineSplitting(vtkPolyData* input, vtkIdType cellId); double SplitPoint[3]; double SplitPoint2[3]; double Tolerance; double GapLength; int SplittingMode; private: vtkvmtkCenterlineSplitExtractor(const vtkvmtkCenterlineSplitExtractor&); // Not implemented. void operator=(const vtkvmtkCenterlineSplitExtractor&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyBallLine.h0000664000175000017500000000627111757446472023304 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBallLine.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyBallLine - // .SECTION Description // .. #ifndef __vtkvmtkPolyBallLine_h #define __vtkvmtkPolyBallLine_h #include "vtkImplicitFunction.h" #include "vtkPolyData.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyBallLine : public vtkImplicitFunction { public: static vtkvmtkPolyBallLine *New(); vtkTypeRevisionMacro(vtkvmtkPolyBallLine,vtkImplicitFunction); void PrintSelf(ostream& os, vtkIndent indent); // Description // Evaluate polyball. double EvaluateFunction(double x[3]); double EvaluateFunction(double x, double y, double z) {return this->vtkImplicitFunction::EvaluateFunction(x, y, z); } ; // Description // Evaluate polyball gradient. void EvaluateGradient(double x[3], double n[3]); // Description: // Set / get input poly data. vtkSetObjectMacro(Input,vtkPolyData); vtkGetObjectMacro(Input,vtkPolyData); // Description: // Set / get input cell ids used for the function. vtkSetObjectMacro(InputCellIds,vtkIdList); vtkGetObjectMacro(InputCellIds,vtkIdList); // Description: // Set / get a single input cell id used for the function. vtkSetMacro(InputCellId,vtkIdType); vtkGetMacro(InputCellId,vtkIdType); // Description: // Set / get poly ball radius array name. vtkSetStringMacro(PolyBallRadiusArrayName); vtkGetStringMacro(PolyBallRadiusArrayName); // Description: // Get the id of the last nearest poly ball center. vtkGetMacro(LastPolyBallCellId,vtkIdType); vtkGetMacro(LastPolyBallCellSubId,vtkIdType); vtkGetMacro(LastPolyBallCellPCoord,double); vtkGetVectorMacro(LastPolyBallCenter,double,3); vtkGetMacro(LastPolyBallCenterRadius,double); vtkSetMacro(UseRadiusInformation,int); vtkGetMacro(UseRadiusInformation,int); vtkBooleanMacro(UseRadiusInformation,int); static double ComplexDot(double x[4], double y[4]); protected: vtkvmtkPolyBallLine(); ~vtkvmtkPolyBallLine(); vtkPolyData* Input; vtkIdList* InputCellIds; vtkIdType InputCellId; char* PolyBallRadiusArrayName; vtkIdType LastPolyBallCellId; vtkIdType LastPolyBallCellSubId; double LastPolyBallCellPCoord; double LastPolyBallCenter[3]; double LastPolyBallCenterRadius; int UseRadiusInformation; private: vtkvmtkPolyBallLine(const vtkvmtkPolyBallLine&); // Not implemented. void operator=(const vtkvmtkPolyBallLine&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataDistanceToCenterlines.cxx0000664000175000017500000001375211757446472027222 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDistanceToCenterlines.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:07:48 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataDistanceToCenterlines.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkPolyBallLine.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataDistanceToCenterlines, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataDistanceToCenterlines); vtkvmtkPolyDataDistanceToCenterlines::vtkvmtkPolyDataDistanceToCenterlines() { this->DistanceToCenterlinesArrayName = NULL; this->Centerlines = NULL; this->CenterlineRadiusArrayName = NULL; this->UseRadiusInformation = 1; this->EvaluateTubeFunction = 0; this->EvaluateCenterlineRadius = 0; this->ProjectPointArrays = 0; } vtkvmtkPolyDataDistanceToCenterlines::~vtkvmtkPolyDataDistanceToCenterlines() { if (this->DistanceToCenterlinesArrayName) { delete[] this->DistanceToCenterlinesArrayName; this->DistanceToCenterlinesArrayName = NULL; } if (this->Centerlines) { this->Centerlines->Delete(); this->Centerlines = NULL; } if (this->CenterlineRadiusArrayName) { delete[] this->CenterlineRadiusArrayName; this->CenterlineRadiusArrayName = NULL; } } int vtkvmtkPolyDataDistanceToCenterlines::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->DistanceToCenterlinesArrayName) { vtkErrorMacro(<<"DistanceToCenterlinesArrayName not set."); return 1; } if (!this->Centerlines) { vtkErrorMacro(<<"Centerlines not set"); return 1; } if (this->EvaluateTubeFunction || this->EvaluateCenterlineRadius) { this->UseRadiusInformation = 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); vtkDoubleArray* distanceToCenterlinesArray = vtkDoubleArray::New(); distanceToCenterlinesArray->SetName(this->DistanceToCenterlinesArrayName); distanceToCenterlinesArray->SetNumberOfComponents(1); distanceToCenterlinesArray->SetNumberOfTuples(numberOfInputPoints); distanceToCenterlinesArray->FillComponent(0,0.0); output->GetPointData()->AddArray(distanceToCenterlinesArray); vtkDoubleArray* surfaceCenterlineRadiusArray = NULL; if (this->EvaluateCenterlineRadius) { surfaceCenterlineRadiusArray = vtkDoubleArray::New(); surfaceCenterlineRadiusArray->SetName(this->CenterlineRadiusArrayName); surfaceCenterlineRadiusArray->SetNumberOfComponents(1); surfaceCenterlineRadiusArray->SetNumberOfTuples(numberOfInputPoints); surfaceCenterlineRadiusArray->FillComponent(0,0.0); output->GetPointData()->AddArray(surfaceCenterlineRadiusArray); } vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New(); tube->SetInput(this->Centerlines); tube->SetUseRadiusInformation(this->UseRadiusInformation); if (this->UseRadiusInformation) { tube->SetPolyBallRadiusArrayName(this->CenterlineRadiusArrayName); } if (this->ProjectPointArrays) { output->GetPointData()->InterpolateAllocate(this->Centerlines->GetPointData(),numberOfInputPoints); } double point[3], centerlinePoint[3]; double distanceToCenterlines = 0.0; for (int i=0; iGetPoint(i,point); double tubeFunctionValue = tube->EvaluateFunction(point); if (this->EvaluateTubeFunction) { distanceToCenterlines = tubeFunctionValue; } else { tube->GetLastPolyBallCenter(centerlinePoint); distanceToCenterlines = sqrt(vtkMath::Distance2BetweenPoints(point,centerlinePoint)); } distanceToCenterlinesArray->SetComponent(i,0,distanceToCenterlines); if (this->EvaluateCenterlineRadius) { surfaceCenterlineRadiusArray->SetComponent(i,0,tube->GetLastPolyBallCenterRadius()); } if (this->ProjectPointArrays) { vtkIdType cellId = tube->GetLastPolyBallCellId(); vtkIdType subId = tube->GetLastPolyBallCellSubId(); vtkIdType pcoord = tube->GetLastPolyBallCellPCoord(); vtkCell* cell = this->Centerlines->GetCell(cellId); vtkIdType pointId0 = cell->GetPointId(subId); vtkIdType pointId1 = cell->GetPointId(subId+1); output->GetPointData()->InterpolateEdge(this->Centerlines->GetPointData(),i,pointId0,pointId1,pcoord); } } tube->Delete(); distanceToCenterlinesArray->Delete(); if (surfaceCenterlineRadiusArray) { surfaceCenterlineRadiusArray->Delete(); } return 1; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineAttributesFilter.cxx0000664000175000017500000001576511757446472026646 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineAttributesFilter.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineAttributesFilter.h" #include "vtkvmtkConstants.h" #include "vtkPolyData.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkPolyLine.h" #include "vtkMath.h" #include "vtkTransform.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineAttributesFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkCenterlineAttributesFilter); vtkvmtkCenterlineAttributesFilter::vtkvmtkCenterlineAttributesFilter() { this->AbscissasArrayName = NULL; this->ParallelTransportNormalsArrayName = NULL; } vtkvmtkCenterlineAttributesFilter::~vtkvmtkCenterlineAttributesFilter() { if (this->AbscissasArrayName) { delete[] this->AbscissasArrayName; this->AbscissasArrayName = NULL; } if (this->ParallelTransportNormalsArrayName) { delete[] this->ParallelTransportNormalsArrayName; this->ParallelTransportNormalsArrayName = NULL; } } int vtkvmtkCenterlineAttributesFilter::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())); if (!this->AbscissasArrayName) { vtkErrorMacro(<<"AbscissasArrayName not specified"); return 1; } if (!this->ParallelTransportNormalsArrayName) { vtkErrorMacro(<<"ParallelTransportNormalsArrayName not specified"); return 1; } output->DeepCopy(input); vtkDoubleArray* abscissasArray = vtkDoubleArray::New(); abscissasArray->SetNumberOfComponents(1); abscissasArray->SetName(this->AbscissasArrayName); this->ComputeAbscissas(input,abscissasArray); output->GetPointData()->AddArray(abscissasArray); vtkDoubleArray* parallelTransportNormalsArray = vtkDoubleArray::New(); parallelTransportNormalsArray->SetNumberOfComponents(3); parallelTransportNormalsArray->SetName(this->ParallelTransportNormalsArrayName); this->ComputeParallelTransportNormals(input,parallelTransportNormalsArray); output->GetPointData()->AddArray(parallelTransportNormalsArray); abscissasArray->Delete(); parallelTransportNormalsArray->Delete(); return 1; } void vtkvmtkCenterlineAttributesFilter::ComputeAbscissas(vtkPolyData* input, vtkDoubleArray* abscissasArray) { int numberOfPoints = input->GetNumberOfPoints(); abscissasArray->SetNumberOfTuples(numberOfPoints); abscissasArray->FillComponent(0,0.0); double point0[3], point1[3]; double abscissa; vtkIdType id0, id1; int numberOfCells = input->GetNumberOfCells(); int numberOfPointsInCell; for (int k=0; kGetCell(k)); if (!polyLine) { continue; } numberOfPointsInCell = polyLine->GetNumberOfPoints(); abscissa = 0.0; id0 = polyLine->GetPointId(0); abscissasArray->SetValue(id0,abscissa); for (int i=1; iGetPointId(i-1); id1 = polyLine->GetPointId(i); input->GetPoint(id0,point0); input->GetPoint(id1,point1); abscissa += sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); abscissasArray->SetValue(id1,abscissa); } } } void vtkvmtkCenterlineAttributesFilter::ComputeParallelTransportNormals(vtkPolyData* input, vtkDoubleArray* parallelTransportNormalsArray) { int numberOfPoints = input->GetNumberOfPoints(); parallelTransportNormalsArray->SetNumberOfTuples(numberOfPoints); parallelTransportNormalsArray->FillComponent(0,0.0); int numberOfCells = input->GetNumberOfCells(); int numberOfPointsInCell; vtkTransform* transform = vtkTransform::New(); vtkIdType id0, id1, id2; double p0[3], p1[3], p2[3]; double t0[3], t1[3], v[3]; double dot, theta; double n0[3], n1[3]; id2 = -1; for (int k=0; kGetCell(k)); if (!polyLine) { continue; } numberOfPointsInCell = polyLine->GetNumberOfPoints(); if (numberOfPointsInCell < 2) { continue; } t0[0] = t0[1] = t0[2] = 0.0; id0 = polyLine->GetPointId(0); input->GetPoint(id0,p0); vtkIdType nextId = 1; while (vtkMath::Norm(t0) < VTK_VMTK_DOUBLE_TOL) { id1 = polyLine->GetPointId(nextId); input->GetPoint(id1,p1); t0[0] = p1[0] - p0[0]; t0[1] = p1[1] - p0[1]; t0[2] = p1[2] - p0[2]; ++nextId; } vtkMath::Normalize(t0); double dummy[3]; vtkMath::Perpendiculars(t0,n0,dummy,0.0); parallelTransportNormalsArray->SetTuple(id0,n0); for (int i=1; iGetPointId(i-1); id1 = polyLine->GetPointId(i); id2 = polyLine->GetPointId(i+1); input->GetPoint(id0,p0); input->GetPoint(id1,p1); input->GetPoint(id2,p2); t0[0] = p1[0] - p0[0]; t0[1] = p1[1] - p0[1]; t0[2] = p1[2] - p0[2]; t1[0] = p2[0] - p1[0]; t1[1] = p2[1] - p1[1]; t1[2] = p2[2] - p1[2]; vtkMath::Normalize(t0); vtkMath::Normalize(t1); dot = vtkMath::Dot(t0,t1); if (1-dot < VTK_VMTK_DOUBLE_TOL) { theta = 0.0; } else { theta = acos(dot) * 180.0 / vtkMath::Pi(); } vtkMath::Cross(t0,t1,v); transform->Identity(); transform->RotateWXYZ(theta,v); transform->TransformPoint(n0,n1); dot = vtkMath::Dot(t1,n1); n1[0] -= dot * t1[0]; n1[1] -= dot * t1[1]; n1[2] -= dot * t1[2]; vtkMath::Normalize(n1); parallelTransportNormalsArray->SetTuple(id1,n1); n0[0] = n1[0]; n0[1] = n1[1]; n0[2] = n1[2]; } parallelTransportNormalsArray->SetTuple(id2,n1); } transform->Delete(); } void vtkvmtkCenterlineAttributesFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkUnstructuredGridCenterlineSections.h0000664000175000017500000000737211757446472030017 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridCenterlineSections.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridCenterlineSections - ... // .SECTION Description // ... #ifndef __vtkvmtkUnstructuredGridCenterlineSections_h #define __vtkvmtkUnstructuredGridCenterlineSections_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class vtkUnstructuredGrid; class vtkTransform; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridCenterlineSections : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkUnstructuredGridCenterlineSections,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkUnstructuredGridCenterlineSections* New(); vtkSetObjectMacro(Centerlines,vtkPolyData); vtkGetObjectMacro(Centerlines,vtkPolyData); vtkSetObjectMacro(SectionSource,vtkPolyData); vtkGetObjectMacro(SectionSource,vtkPolyData); vtkSetStringMacro(SectionUpNormalsArrayName); vtkGetStringMacro(SectionUpNormalsArrayName); vtkSetStringMacro(SectionNormalsArrayName); vtkGetStringMacro(SectionNormalsArrayName); vtkSetStringMacro(AdditionalNormalsArrayName); vtkGetStringMacro(AdditionalNormalsArrayName); vtkSetStringMacro(AdditionalScalarsArrayName); vtkGetStringMacro(AdditionalScalarsArrayName); vtkSetMacro(TransformSections,int); vtkGetMacro(TransformSections,int); vtkBooleanMacro(TransformSections,int); vtkSetMacro(UseSectionSource,int); vtkGetMacro(UseSectionSource,int); vtkBooleanMacro(UseSectionSource,int); vtkSetMacro(SourceScaling,int); vtkGetMacro(SourceScaling,int); vtkBooleanMacro(SourceScaling,int); vtkSetVectorMacro(OriginOffset,double,3); vtkGetVectorMacro(OriginOffset,double,3); vtkSetStringMacro(VectorsArrayName); vtkGetStringMacro(VectorsArrayName); vtkSetStringMacro(SectionIdsArrayName); vtkGetStringMacro(SectionIdsArrayName); vtkGetObjectMacro(SectionPointsPolyData,vtkPolyData); protected: vtkvmtkUnstructuredGridCenterlineSections(); ~vtkvmtkUnstructuredGridCenterlineSections(); int FillInputPortInformation(int, vtkInformation *info); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); double ComputeAngle(double vector0[3], double vector1[3]); void CreateTransform(vtkTransform* transform, double currentOrigin[3], double currentNormal[3], double currentUpNormal[3], double targetOrigin[3], double targetNormal[3], double targetUpNormal[3]); vtkPolyData* Centerlines; vtkPolyData* SectionSource; vtkPolyData* SectionPointsPolyData; char* SectionUpNormalsArrayName; char* SectionNormalsArrayName; char* AdditionalNormalsArrayName; char* AdditionalScalarsArrayName; char* SectionIdsArrayName; char* VectorsArrayName; int TransformSections; int UseSectionSource; int SourceScaling; double OriginOffset[3]; private: vtkvmtkUnstructuredGridCenterlineSections(const vtkvmtkUnstructuredGridCenterlineSections&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridCenterlineSections&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkInternalTetrahedraExtractor.cxx0000664000175000017500000002252311757446472027003 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkInternalTetrahedraExtractor.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkInternalTetrahedraExtractor.h" #include "vtkPointData.h" #include "vtkCellArray.h" #include "vtkUnstructuredGrid.h" #include "vtkIntArray.h" #include "vtkTetra.h" #include "vtkTriangle.h" #include "vtkMath.h" #include "vtkvmtkConstants.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkInternalTetrahedraExtractor, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkInternalTetrahedraExtractor); vtkvmtkInternalTetrahedraExtractor::vtkvmtkInternalTetrahedraExtractor() { this->UseCaps = 0; this->CapCenterIds = NULL; this->OutwardNormalsArrayName = NULL; this->Tolerance = VTK_VMTK_DOUBLE_TOL; this->RemoveSubresolutionTetrahedra = 0; this->SubresolutionFactor = 1.0; this->Surface = NULL; } vtkvmtkInternalTetrahedraExtractor::~vtkvmtkInternalTetrahedraExtractor() { if (this->CapCenterIds) { this->CapCenterIds->Delete(); this->CapCenterIds = NULL; } if (this->OutwardNormalsArrayName) { delete [] this->OutwardNormalsArrayName; this->OutwardNormalsArrayName = NULL; } if (this->Surface) { this->Surface->Delete(); this->Surface = NULL; } } int vtkvmtkInternalTetrahedraExtractor::RequestData( vtkInformation *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())); // Declare double circumcenter[3]; double p0[3], p1[3], p2[3], p3[3]; double v0[3], v1[3], v2[3], v3[3], n0[3], n1[3], n2[3], n3[3]; double dot0, dot1, dot2, dot3; bool boundaryTetra; bool allDotPositive, allDotMinusOnePositive; vtkIdType i, j; vtkCellArray* newTetras; vtkIdList* newCellTypes; vtkIntArray* keepCell; vtkDataArray* outwardPointNormals; vtkTetra* tetra; if (!this->OutwardNormalsArrayName) { vtkErrorMacro(<< "No normals array name specified!"); return 1; } outwardPointNormals = input->GetPointData()->GetArray(this->OutwardNormalsArrayName); if (!outwardPointNormals) { vtkErrorMacro(<< "Array with name specified does not exist!"); return 1; } if (outwardPointNormals->GetNumberOfComponents()!=3) { vtkErrorMacro(<< "Normals have NumberOfComponents != 3!"); return 1; } if (outwardPointNormals->GetNumberOfTuples()!=input->GetNumberOfPoints()) { vtkErrorMacro(<< "Number of normals does not match input number of points !"); return 1; } if ((this->UseCaps)&&(!this->CapCenterIds)) { vtkErrorMacro(<< "UseCapsOn but no CapCenterIds specified !"); return 1; } if (this->RemoveSubresolutionTetrahedra && !this->Surface) { vtkErrorMacro(<< "RemoveSubresolutionTetrahedraOn but no Surface specified !"); return 1; } if (this->RemoveSubresolutionTetrahedra && this->Surface->GetNumberOfPoints() != input->GetNumberOfPoints()) { vtkErrorMacro(<< "NumberOfPoints of Surface is different than that of input Delaunay tessellation, the Delaunay tessellation doesn't look like it has been produced from the Surface !"); return 1; } // Allocate newTetras = vtkCellArray::New(); newCellTypes = vtkIdList::New(); keepCell = vtkIntArray::New(); keepCell->SetNumberOfTuples(input->GetNumberOfCells()); // Execute //skeleton: dual of inner delaunay tets (Attali, Sk0)(not necessarily internal) or inner voronoi elements (Sk2)(not necessarily homotpic). //actual choice: Sk2. double tolerance = this->Tolerance; for (i=0; iGetNumberOfCells(); i++) { tetra = vtkTetra::SafeDownCast(input->GetCell(i)); if (!tetra) { continue; } boundaryTetra = false; if (this->UseCaps) { for (j=0; jGetNumberOfPoints(); j++) { if (this->CapCenterIds->IsId(tetra->GetPointId(j))!=-1) { boundaryTetra = true; } } } tetra->GetPoints()->GetPoint(0,p0); tetra->GetPoints()->GetPoint(1,p1); tetra->GetPoints()->GetPoint(2,p2); tetra->GetPoints()->GetPoint(3,p3); vtkTetra::Circumsphere(p0,p1,p2,p3,circumcenter); for (j=0; j<3; j++) { v0[j] = p0[j] - circumcenter[j]; v1[j] = p1[j] - circumcenter[j]; v2[j] = p2[j] - circumcenter[j]; v3[j] = p3[j] - circumcenter[j]; } outwardPointNormals->GetTuple(tetra->GetPointId(0),n0); outwardPointNormals->GetTuple(tetra->GetPointId(1),n1); outwardPointNormals->GetTuple(tetra->GetPointId(2),n2); outwardPointNormals->GetTuple(tetra->GetPointId(3),n3); dot0 = vtkMath::Dot(v0,n0); dot1 = vtkMath::Dot(v1,n1); dot2 = vtkMath::Dot(v2,n2); dot3 = vtkMath::Dot(v3,n3); allDotPositive = false; allDotMinusOnePositive = false; if ((dot0>tolerance)&&(dot1>tolerance)&&(dot2>tolerance)&&(dot3>tolerance)) { allDotPositive = true; } else if (((dot0>tolerance)&&(dot1>tolerance)&&(dot2>tolerance))|| ((dot0>tolerance)&&(dot1>tolerance)&&(dot3>tolerance))|| ((dot0>tolerance)&&(dot2>tolerance)&&(dot3>tolerance))|| ((dot1>tolerance)&&(dot2>tolerance)&&(dot3>tolerance))) { allDotMinusOnePositive = true; } keepCell->SetValue(i,0); if (allDotPositive) { keepCell->SetValue(i,1); } else if (boundaryTetra) { if (allDotMinusOnePositive) { keepCell->SetValue(i,1); } } } if (this->RemoveSubresolutionTetrahedra) { double pt0[3], pt1[3], pt2[3]; this->Surface->BuildLinks(); vtkIdList* cellNeighbors = vtkIdList::New(); for (i=0; iGetNumberOfCells(); i++) { if (keepCell->GetValue(i) == 0) { continue; } tetra = vtkTetra::SafeDownCast(input->GetCell(i)); if (!tetra) { continue; } bool onNewBoundary = false; for (j=0; jGetNumberOfFaces(); j++) { cellNeighbors->Initialize(); input->GetCellNeighbors(i,tetra->GetFace(j)->GetPointIds(),cellNeighbors); if (cellNeighbors->GetNumberOfIds() == 0 || keepCell->GetValue(cellNeighbors->GetId(0)) == 0) { onNewBoundary = true; } } if (!onNewBoundary) { continue; } tetra->GetPoints()->GetPoint(0,p0); tetra->GetPoints()->GetPoint(1,p1); tetra->GetPoints()->GetPoint(2,p2); tetra->GetPoints()->GetPoint(3,p3); double circumradius = vtkTetra::Circumsphere(p0,p1,p2,p3,circumcenter); for (j=0; jGetNumberOfPoints(); j++) { unsigned short ncells; vtkIdType* cells; this->Surface->GetPointCells(j,ncells,cells); double minEdgeLength = VTK_VMTK_LARGE_DOUBLE; int k; for (k=0; kSurface->GetCell(cells[k])); if (!triangle) { continue; } triangle->GetPoints()->GetPoint(0,pt0); triangle->GetPoints()->GetPoint(1,pt1); triangle->GetPoints()->GetPoint(2,pt2); double triangleArea = triangle->TriangleArea(pt0,pt1,pt2); double edgeLength = sqrt(2.0 * triangleArea); if (edgeLength < minEdgeLength) { minEdgeLength = edgeLength; } } // TODO: set factor as a member variable. if (circumradius < this->SubresolutionFactor * minEdgeLength) { keepCell->SetValue(i,0); } } } cellNeighbors->Delete(); } for (i=0; iGetNumberOfCells(); i++) { if (keepCell->GetValue(i)) { newCellTypes->InsertNextId(VTK_TETRA); newTetras->InsertNextCell(input->GetCell(i)); } } int* newCellTypesInt = new int[newCellTypes->GetNumberOfIds()]; for (i=0; iGetNumberOfIds(); i++) { newCellTypesInt[i] = newCellTypes->GetId(i); } output->SetPoints(input->GetPoints()); output->GetPointData()->PassData(input->GetPointData()); output->SetCells(newCellTypesInt,newTetras); // Destroy newTetras->Delete(); newCellTypes->Delete(); keepCell->Delete(); delete[] newCellTypesInt; return 1; } void vtkvmtkInternalTetrahedraExtractor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkBoundaryReferenceSystems.cxx0000664000175000017500000002465311757446472026327 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryReferenceSystems.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkBoundaryReferenceSystems.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkPolyData.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkPointData.h" #include "vtkPolyLine.h" #include "vtkvmtkConstants.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkBoundaryReferenceSystems, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkBoundaryReferenceSystems); vtkvmtkBoundaryReferenceSystems::vtkvmtkBoundaryReferenceSystems() { this->BoundaryRadiusArrayName = NULL; this->BoundaryNormalsArrayName = NULL; this->Point1ArrayName = NULL; this->Point2ArrayName = NULL; } vtkvmtkBoundaryReferenceSystems::~vtkvmtkBoundaryReferenceSystems() { if (this->BoundaryRadiusArrayName) { delete[] this->BoundaryRadiusArrayName; this->BoundaryRadiusArrayName = NULL; } if (this->BoundaryNormalsArrayName) { delete[] this->BoundaryNormalsArrayName; this->BoundaryNormalsArrayName = NULL; } if (this->Point1ArrayName) { delete[] this->Point1ArrayName; this->Point1ArrayName = NULL; } if (this->Point2ArrayName) { delete[] this->Point2ArrayName; this->Point2ArrayName = NULL; } } void vtkvmtkBoundaryReferenceSystems::ComputeBoundaryBarycenter(vtkPoints* points, double* barycenter) { int numberOfPoints; double weightSum, weight; vtkIdType i; // accounts for edge length numberOfPoints = points->GetNumberOfPoints(); weightSum = 0.0; barycenter[0] = 0.0; barycenter[1] = 0.0; barycenter[2] = 0.0; double point0[3], point1[3]; for (i=0; iGetPoint(i,point0); points->GetPoint((i+1)%numberOfPoints,point1); weight = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); if (weight < VTK_VMTK_DOUBLE_TOL) { continue; } weightSum += weight; barycenter[0] += (point0[0] + point1[0])/2.0 * weight; barycenter[1] += (point0[1] + point1[1])/2.0 * weight; barycenter[2] += (point0[2] + point1[2])/2.0 * weight; } barycenter[0] /= weightSum; barycenter[1] /= weightSum; barycenter[2] /= weightSum; } double vtkvmtkBoundaryReferenceSystems::ComputeBoundaryMeanRadius(vtkPoints* points, double* barycenter) { int numberOfPoints = points->GetNumberOfPoints(); // TODO: weight by edge length as for barycenter double meanRadius = 0.0; for (int i=0; iGetPoint(i),barycenter)); } meanRadius /= numberOfPoints; return meanRadius; } void vtkvmtkBoundaryReferenceSystems::ComputeBoundaryNormal(vtkPoints* points, double* barycenter, double* normal) { int numberOfPoints; double point[3], vector1[3], vector0[3], cross[3], sumCross[3] = {0.0f,0.0f,0.0f}; vtkIdType i, j; // TODO: weight by edge length as for barycenter numberOfPoints = points->GetNumberOfPoints(); points->GetPoint(numberOfPoints-1,point); vector0[0] = point[0] - barycenter[0]; vector0[1] = point[1] - barycenter[1]; vector0[2] = point[2] - barycenter[2]; for (i=0; iGetPoint(i,point); vector1[0] = point[0] - barycenter[0]; vector1[1] = point[1] - barycenter[1]; vector1[2] = point[2] - barycenter[2]; vtkMath::Cross(vector1,vector0,cross); for (j=0; j<3; j++) { vector0[j] = vector1[j]; sumCross[j] += cross[j]; } } vtkMath::Normalize(sumCross); for (j=0; j<3; j++) { normal[j] = sumCross[j]; } } void vtkvmtkBoundaryReferenceSystems::OrientBoundaryNormalOutwards(vtkPolyData* surface, vtkPolyData* boundaries, vtkIdType boundaryCellId, double normal[3], double outwardNormal[3]) { vtkPolyLine* boundary = vtkPolyLine::SafeDownCast(boundaries->GetCell(boundaryCellId)); int k=0; if (!boundary) { for (k=0; k<3; k++) { outwardNormal[k] = normal[k]; } return; } surface->BuildCells(); surface->BuildLinks(); unsigned short ncells; vtkIdType *cells; vtkIdType npts, *pts; double boundaryPoint[3], neighborPoint[3]; int numberOfBoundaryPoints = boundary->GetNumberOfPoints(); int j; vtkIdList* boundaryIds = vtkIdList::New(); for (j=0; jInsertNextId(static_cast(vtkMath::Round(boundaries->GetPointData()->GetScalars()->GetComponent(boundary->GetPointId(j),0)))); } double neighborsToBoundaryNormal[3]; neighborsToBoundaryNormal[0] = neighborsToBoundaryNormal[1] = neighborsToBoundaryNormal[2] = 0.0; for (j=0; jGetPointCells(boundaryIds->GetId(j),ncells,cells); for (int c=0; cGetCellPoints(cells[c],npts,pts); for (int p=0; pIsId(pts[p]) == -1) { surface->GetPoint(boundaryIds->GetId(j),boundaryPoint); surface->GetPoint(pts[p],neighborPoint); for (k=0; k<3; k++) { neighborsToBoundaryNormal[k] += boundaryPoint[k] - neighborPoint[k]; } } } } } for (k=0; k<3; k++) { outwardNormal[k] = normal[k]; } vtkMath::Normalize(neighborsToBoundaryNormal); if (vtkMath::Dot(normal,neighborsToBoundaryNormal) < 0.0) { for (k=0; k<3; k++) { outwardNormal[k] *= -1.0; } } boundaryIds->Delete(); } void vtkvmtkBoundaryReferenceSystems::ComputeReferenceSystemPoints(double origin[3], double normal[3], double radius, double point1[3], double point2[3]) { point1[0] = point1[1] = point1[2] = 0.0; point2[0] = point2[1] = point2[2] = 0.0; double x_p[3], y_p[3], x[3]; x[0] = 1.0; x[1] = 0.0; x[2] = 0.0; vtkMath::Cross(normal,x,x_p); vtkMath::Normalize(x_p); vtkMath::Cross(normal,x_p,y_p); vtkMath::Normalize(y_p); for (int i=0; i<3; i++) { point1[i] = origin[i] + x_p[i] * radius; point2[i] = origin[i] + y_p[i] * radius; } } int vtkvmtkBoundaryReferenceSystems::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())); if (!this->BoundaryRadiusArrayName) { vtkErrorMacro(<< "BoundaryRadiusArrayName not specified."); return 1; } if (!this->BoundaryNormalsArrayName) { vtkErrorMacro(<< "BoundaryNormalsArrayName not specified."); return 1; } if (!this->Point1ArrayName) { vtkErrorMacro(<< "Point1ArrayName not specified."); return 1; } if (!this->Point2ArrayName) { vtkErrorMacro(<< "Point2ArrayName not specified."); return 1; } vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputVerts = vtkCellArray::New(); vtkDoubleArray* outputRadius = vtkDoubleArray::New(); outputRadius->SetName(this->BoundaryRadiusArrayName); vtkDoubleArray* outputNormals = vtkDoubleArray::New(); outputNormals->SetName(this->BoundaryNormalsArrayName); outputNormals->SetNumberOfComponents(3); vtkDoubleArray* point1Array = vtkDoubleArray::New(); point1Array->SetName(this->Point1ArrayName); point1Array->SetNumberOfComponents(3); vtkDoubleArray* point2Array = vtkDoubleArray::New(); point2Array->SetName(this->Point2ArrayName); point2Array->SetNumberOfComponents(3); vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(input); boundaryExtractor->Update(); vtkPolyData* boundaries = boundaryExtractor->GetOutput(); double barycenter[3], normal[3], outwardNormal[3], meanRadius; for (int i=0; iGetNumberOfCells(); i++) { vtkPolyLine* boundary = vtkPolyLine::SafeDownCast(boundaries->GetCell(i)); if (!boundary) { vtkErrorMacro(<<"Boundary not a vtkPolyLine"); continue; } this->ComputeBoundaryBarycenter(boundary->GetPoints(),barycenter); meanRadius = this->ComputeBoundaryMeanRadius(boundary->GetPoints(),barycenter); this->ComputeBoundaryNormal(boundary->GetPoints(),barycenter,normal); this->OrientBoundaryNormalOutwards(input,boundaries,i,normal,outwardNormal); double point1[3], point2[3]; this->ComputeReferenceSystemPoints(barycenter,normal,meanRadius,point1,point2); vtkIdType pointId = outputPoints->InsertNextPoint(barycenter); outputVerts->InsertNextCell(1); outputVerts->InsertCellPoint(pointId); outputNormals->InsertNextTuple(outwardNormal); outputRadius->InsertNextValue(meanRadius); point1Array->InsertNextTuple(point1); point2Array->InsertNextTuple(point2); } output->SetPoints(outputPoints); output->SetVerts(outputVerts); output->GetPointData()->AddArray(outputNormals); output->GetPointData()->SetActiveNormals(this->BoundaryNormalsArrayName); output->GetPointData()->AddArray(outputRadius); output->GetPointData()->SetActiveScalars(this->BoundaryRadiusArrayName); output->GetPointData()->AddArray(point1Array); output->GetPointData()->AddArray(point2Array); outputPoints->Delete(); outputVerts->Delete(); outputNormals->Delete(); outputRadius->Delete(); point1Array->Delete(); point2Array->Delete(); boundaryExtractor->Delete(); return 1; } void vtkvmtkBoundaryReferenceSystems::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSmoothing.h0000664000175000017500000000407011757446472024731 0ustar lucaluca/*========================================================================= 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) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .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: vtkTypeRevisionMacro(vtkvmtkCenterlineSmoothing,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); double SmoothingFactor; int NumberOfSmoothingIterations; private: vtkvmtkCenterlineSmoothing(const vtkvmtkCenterlineSmoothing&); // Not implemented. void operator=(const vtkvmtkCenterlineSmoothing&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineSections.h0000664000175000017500000000532111757446472026207 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineSections.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCenterlineSections - ... // .SECTION Description // ... #ifndef __vtkvmtkPolyDataCenterlineSections_h #define __vtkvmtkPolyDataCenterlineSections_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlineSections : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataCenterlineSections,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataCenterlineSections* New(); vtkSetObjectMacro(Centerlines,vtkPolyData); vtkGetObjectMacro(Centerlines,vtkPolyData); vtkSetStringMacro(CenterlineSectionAreaArrayName); vtkGetStringMacro(CenterlineSectionAreaArrayName); vtkSetStringMacro(CenterlineSectionMinSizeArrayName); vtkGetStringMacro(CenterlineSectionMinSizeArrayName); vtkSetStringMacro(CenterlineSectionMaxSizeArrayName); vtkGetStringMacro(CenterlineSectionMaxSizeArrayName); vtkSetStringMacro(CenterlineSectionShapeArrayName); vtkGetStringMacro(CenterlineSectionShapeArrayName); vtkSetStringMacro(CenterlineSectionClosedArrayName); vtkGetStringMacro(CenterlineSectionClosedArrayName); protected: vtkvmtkPolyDataCenterlineSections(); ~vtkvmtkPolyDataCenterlineSections(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ComputeCenterlineSections(vtkPolyData* input, int cellId, vtkPolyData* output); vtkPolyData* Centerlines; char* CenterlineSectionAreaArrayName; char* CenterlineSectionMinSizeArrayName; char* CenterlineSectionMaxSizeArrayName; char* CenterlineSectionShapeArrayName; char* CenterlineSectionClosedArrayName; private: vtkvmtkPolyDataCenterlineSections(const vtkvmtkPolyDataCenterlineSections&); // Not implemented. void operator=(const vtkvmtkPolyDataCenterlineSections&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataStretchMappingFilter.cxx0000664000175000017500000003206211757446472027062 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataStretchMappingFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.11 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataStretchMappingFilter.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkCellArray.h" #include "vtkContourFilter.h" #include "vtkStripper.h" // #include "vtkCardinalSpline.h" #include "vtkPiecewiseFunction.h" #include "vtkPolyLine.h" #include "vtkCleanPolyData.h" #include "vtkMath.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkvmtkConstants.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkPolyDataBranchUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataStretchMappingFilter, "$Revision: 1.11 $"); vtkStandardNewMacro(vtkvmtkPolyDataStretchMappingFilter); vtkvmtkPolyDataStretchMappingFilter::vtkvmtkPolyDataStretchMappingFilter() { this->StretchedMappingArrayName = NULL; this->HarmonicMappingArrayName = NULL; this->GroupIdsArrayName = NULL; this->MetricArrayName = NULL; this->BoundaryMetricArrayName = NULL; this->UseBoundaryMetric = 0; this->MetricBoundsGapFactor = 2.0; } vtkvmtkPolyDataStretchMappingFilter::~vtkvmtkPolyDataStretchMappingFilter() { if (this->StretchedMappingArrayName) { delete[] this->StretchedMappingArrayName; this->StretchedMappingArrayName = NULL; } if (this->HarmonicMappingArrayName) { delete[] this->HarmonicMappingArrayName; this->HarmonicMappingArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->MetricArrayName) { delete[] this->MetricArrayName; this->MetricArrayName = NULL; } if (this->BoundaryMetricArrayName) { delete[] this->BoundaryMetricArrayName; this->BoundaryMetricArrayName = NULL; } } int vtkvmtkPolyDataStretchMappingFilter::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->StretchedMappingArrayName) { vtkErrorMacro(<<"StretchedMappingArrayName not set."); return 1; } if (!this->HarmonicMappingArrayName) { vtkErrorMacro(<<"HarmonicMappingArrayName not set."); return 1; } vtkDataArray* harmonicMappingArray = input->GetPointData()->GetArray(this->HarmonicMappingArrayName); if (!harmonicMappingArray) { vtkErrorMacro(<<"HarmonicMappingArrayName with name specified does not exist."); return 1; } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not set."); return 1; } vtkDataArray* groupIdsArray = input->GetPointData()->GetArray(this->GroupIdsArrayName); if (!groupIdsArray) { vtkErrorMacro(<<"GroupIdsArray with name specified does not exist."); return 1; } if (!this->MetricArrayName) { vtkErrorMacro(<<"MetricArrayName not set."); return 1; } vtkDataArray* metricArray = input->GetPointData()->GetArray(this->MetricArrayName); if (!metricArray) { vtkErrorMacro(<<"MetricArrayName with name specified does not exist."); return 1; } vtkDataArray* boundaryMetricArray = NULL; if (this->UseBoundaryMetric) { if (!this->BoundaryMetricArrayName) { vtkErrorMacro(<<"BoundaryMetricArrayName not set."); return 1; } boundaryMetricArray = input->GetPointData()->GetArray(this->BoundaryMetricArrayName); if (!boundaryMetricArray) { vtkErrorMacro(<<"BoundaryMetricArrayName with name specified does not exist."); return 1; } } int numberOfInputPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkDoubleArray* stretchedMapping = vtkDoubleArray::New(); stretchedMapping->SetName(this->StretchedMappingArrayName); stretchedMapping->SetNumberOfComponents(1); stretchedMapping->SetNumberOfTuples(numberOfInputPoints); output->GetPointData()->AddArray(stretchedMapping); vtkIdList* groupIds = vtkIdList::New(); vtkvmtkPolyDataBranchUtilities::GetGroupsIdList(input,this->GroupIdsArrayName,groupIds); int i, j, k; for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = groupIds->GetId(i); vtkPolyData* cylinder = vtkPolyData::New(); vtkvmtkPolyDataBranchUtilities::ExtractGroup(input,this->GroupIdsArrayName,groupId,true,cylinder); cylinder->GetPointData()->SetActiveScalars(this->HarmonicMappingArrayName); // before contouring, extract boundaries and look for boundary values there if UseBoundaryValues is 1 vtkDataArray* cylinderHarmonicMappingArray = cylinder->GetPointData()->GetArray(this->HarmonicMappingArrayName); vtkDataArray* cylinderMetricArray = cylinder->GetPointData()->GetArray(this->MetricArrayName); vtkDataArray* cylinderBoundaryMetricArray = cylinder->GetPointData()->GetArray(this->BoundaryMetricArrayName); double boundaryMappings[2]; double boundaryMetrics[2]; double boundaryMetricUsefulBounds[2]; // extract boundaries and look at values there. vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(cylinder); boundaryExtractor->Update(); int numberOfBoundaries = boundaryExtractor->GetOutput()->GetNumberOfCells(); if (numberOfBoundaries != 2) { vtkErrorMacro(<<"Branch not topologically a cylinder."); return 1; } double contourMetricBounds[2][2]; contourMetricBounds[0][0] = VTK_DOUBLE_MAX; contourMetricBounds[0][1] = VTK_DOUBLE_MIN; contourMetricBounds[1][0] = VTK_DOUBLE_MAX; contourMetricBounds[1][1] = VTK_DOUBLE_MIN; for (j=0; jGetOutput()->GetCell(j); if (boundary->GetNumberOfPoints() == 0) { vtkErrorMacro(<<"Degenerate branch found."); return 1; } vtkDataArray* boundaryPointIds = boundaryExtractor->GetOutput()->GetPointData()->GetScalars(); vtkIdType boundaryPointId = static_cast(boundaryPointIds->GetComponent(boundary->GetPointId(0),0)); boundaryMappings[j] = cylinderHarmonicMappingArray->GetComponent(boundaryPointId,0); if (UseBoundaryMetric) { boundaryMetrics[j] = cylinderBoundaryMetricArray->GetComponent(boundaryPointId,0); } int numberOfBoundaryPoints = boundary->GetNumberOfPoints(); for (k=0; k(boundaryPointIds->GetComponent(boundary->GetPointId(k),0)); double metricValue = cylinderMetricArray->GetComponent(boundaryPointId,0); if (metricValue < contourMetricBounds[j][0]) { contourMetricBounds[j][0] = metricValue; } if (metricValue > contourMetricBounds[j][1]) { contourMetricBounds[j][1] = metricValue; } } } if (boundaryMetrics[0] > boundaryMetrics[1]) { double temp; temp = boundaryMappings[1]; boundaryMappings[1] = boundaryMappings[0]; boundaryMappings[0] = temp; temp = boundaryMetrics[1]; boundaryMetrics[1] = boundaryMetrics[0]; boundaryMetrics[0] = temp; temp = contourMetricBounds[1][0]; contourMetricBounds[1][0] = contourMetricBounds[0][0]; contourMetricBounds[0][0] = temp; temp = contourMetricBounds[1][1]; contourMetricBounds[1][1] = contourMetricBounds[0][1]; contourMetricBounds[0][1] = temp; } // boundaryMetricUsefulBounds[0] = contourMetricBounds[0][1]; // boundaryMetricUsefulBounds[1] = contourMetricBounds[1][0]; boundaryMetricUsefulBounds[0] = contourMetricBounds[0][0] + this->MetricBoundsGapFactor * (contourMetricBounds[0][1] - contourMetricBounds[0][0]); boundaryMetricUsefulBounds[1] = contourMetricBounds[1][1] - this->MetricBoundsGapFactor * (contourMetricBounds[1][1] - contourMetricBounds[1][0]); if (!this->UseBoundaryMetric) { boundaryMetrics[0] = contourMetricBounds[0][0]; boundaryMetrics[1] = contourMetricBounds[1][1]; } boundaryExtractor->Delete(); vtkContourFilter* contourFilter = vtkContourFilter::New(); contourFilter->SetInput(cylinder); contourFilter->SetValue(0,0.5); contourFilter->Update(); int numberOfContours = static_cast(10.0 * fabs(boundaryMetrics[1] - boundaryMetrics[0]) / (contourFilter->GetOutput()->GetLength()/2.0)); double interval = 1.0/static_cast(numberOfContours); for (j=0; j<=numberOfContours; j++) { contourFilter->SetValue(j,static_cast(j) * interval); } contourFilter->Update(); vtkStripper* contourStripper = vtkStripper::New(); contourStripper->SetInput(contourFilter->GetOutput()); contourStripper->Update(); vtkPolyData* contours = contourStripper->GetOutput(); // vtkCardinalSpline* stretchFunction = vtkCardinalSpline::New(); vtkPiecewiseFunction* stretchFunction = vtkPiecewiseFunction::New(); int numberOfComputedContours = contours->GetNumberOfCells(); vtkDataArray* contourMetricArray = contours->GetPointData()->GetArray(this->MetricArrayName); for (j=0; jGetCell(j)); if (!contour) { continue; } double harmonicMappingValue = contours->GetPointData()->GetScalars()->GetComponent(contour->GetPointId(0),0); int numberOfContourPoints = contour->GetNumberOfPoints(); double contourLength = 0.0; double metricIntegral = 0.0; for (k=0; kGetPointId(k); int pointId1 = contour->GetPointId((k+1)%numberOfContourPoints); double point0[3]; double point1[3]; contours->GetPoint(pointId0,point0); contours->GetPoint(pointId1,point1); double length = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); if (length < VTK_VMTK_DOUBLE_TOL) { continue; } contourLength += length; double metricValue0 = contourMetricArray->GetComponent(pointId0,0); double metricValue1 = contourMetricArray->GetComponent(pointId1,0); metricIntegral += length * 0.5 * (metricValue0 + metricValue1); } if (contourLength < VTK_VMTK_DOUBLE_TOL) { continue; } double metricMean = metricIntegral / contourLength; // if (metricMean < boundaryMetricUsefulBounds[0] || metricMean > boundaryMetricUsefulBounds[1]) // { // continue; // } if (metricMean < boundaryMetricUsefulBounds[0] || metricMean > boundaryMetricUsefulBounds[1]) { continue; } stretchFunction->AddPoint(harmonicMappingValue, metricMean); } stretchFunction->AddPoint(boundaryMappings[0], boundaryMetrics[0]); stretchFunction->AddPoint(boundaryMappings[1], boundaryMetrics[1]); // derivative = (stretchFunction->Evaluate(blendingSkip) - stretchFunction->Evaluate(0.0)) / blendingSkip; // stretchFunction->AddPoint(-blendingSkip, stretchFunction->Evaluate(0.0) - derivative * blendingSkip); // derivative = (stretchFunction->Evaluate(1.0) - stretchFunction->Evaluate(1.0-interval)) / interval; // stretchFunction->AddPoint(1.0+blendingSkip, stretchFunction->Evaluate(1.0) + derivative * blendingSkip); for (j=0; j(groupIdsArray->GetComponent(j,0)); if (currentGroupId != groupId) { continue; } double harmonicMappingValue = harmonicMappingArray->GetComponent(j,0); // double stretchedMappingValue = stretchFunction->Evaluate(harmonicMappingValue); double stretchedMappingValue = stretchFunction->GetValue(harmonicMappingValue); stretchedMapping->SetComponent(j,0,stretchedMappingValue); } stretchFunction->Delete(); contourFilter->Delete(); contourStripper->Delete(); cylinder->Delete(); } groupIds->Delete(); stretchedMapping->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBifurcationReferenceSystems.h0000664000175000017500000000520711757446472030441 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBifurcationReferenceSystems.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCenterlineBifurcationReferenceSystems - ... // .SECTION Description // ... #ifndef __vtkvmtkCenterlineBifurcationReferenceSystems_h #define __vtkvmtkCenterlineBifurcationReferenceSystems_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class vtkPoints; class vtkDoubleArray; class vtkIntArray; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineBifurcationReferenceSystems : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCenterlineBifurcationReferenceSystems,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineBifurcationReferenceSystems* New(); vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); vtkSetStringMacro(BlankingArrayName); vtkGetStringMacro(BlankingArrayName); vtkSetStringMacro(NormalArrayName); vtkGetStringMacro(NormalArrayName); vtkSetStringMacro(UpNormalArrayName); vtkGetStringMacro(UpNormalArrayName); protected: vtkvmtkCenterlineBifurcationReferenceSystems(); ~vtkvmtkCenterlineBifurcationReferenceSystems(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ComputeGroupReferenceSystem(vtkPolyData* input, int referenceGroupId, vtkPoints* outputPoints, vtkDoubleArray* normalArray, vtkDoubleArray* upNormalArray, vtkIntArray* referenceGroupIdsArray); char* RadiusArrayName; char* GroupIdsArrayName; char* BlankingArrayName; char* NormalArrayName; char* UpNormalArrayName; private: vtkvmtkCenterlineBifurcationReferenceSystems(const vtkvmtkCenterlineBifurcationReferenceSystems&); // Not implemented. void operator=(const vtkvmtkCenterlineBifurcationReferenceSystems&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataLineEmbedder.h0000664000175000017500000000521111757446472024724 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataLineEmbedder.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataLineEmbedder - // .SECTION Description // ... #ifndef __vtkvmtkPolyDataLineEmbedder_h #define __vtkvmtkPolyDataLineEmbedder_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataLineEmbedder : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataLineEmbedder,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataLineEmbedder *New(); vtkSetObjectMacro(Lines,vtkPolyData); vtkGetObjectMacro(Lines,vtkPolyData); vtkSetStringMacro(EdgeArrayName); vtkGetStringMacro(EdgeArrayName); vtkSetStringMacro(EdgePCoordArrayName); vtkGetStringMacro(EdgePCoordArrayName); vtkSetMacro(SnapToMeshTolerance,double); vtkGetMacro(SnapToMeshTolerance,double); vtkGetObjectMacro(EmbeddedLinePointIds,vtkIdList); protected: vtkvmtkPolyDataLineEmbedder(); ~vtkvmtkPolyDataLineEmbedder(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdType GetCellId(vtkPolyData* input, vtkIdList* pointIds); void GetNeighbors(vtkIdType pointId, vtkIdList* neighborPointIds); void OrderNeighborhood(vtkIdList* cellPointIds, vtkIdList* neighborIds, vtkIdList* addedPointIds, vtkIdList* snapToMeshIds, vtkDataArray* edgeArray, vtkDataArray* edgePCoordArray, vtkIdList* orderedNeighborIds); void Triangulate(vtkIdList* cellPointIds, vtkIdList* orderedNeighborIds, vtkIdList* triangulationIds); char* EdgeArrayName; char* EdgePCoordArrayName; double SnapToMeshTolerance; vtkPolyData* Lines; vtkIdList* EmbeddedLinePointIds; private: vtkvmtkPolyDataLineEmbedder(const vtkvmtkPolyDataLineEmbedder&); // Not implemented. void operator=(const vtkvmtkPolyDataLineEmbedder&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataScissors.h0000664000175000017500000000430711757446472024222 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataScissors.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataScissors - // .SECTION Description // ... #ifndef __vtkvmtkPolyDataScissors_h #define __vtkvmtkPolyDataScissors_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataScissors : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataScissors,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataScissors *New(); vtkSetObjectMacro(CutLine,vtkPolyData); vtkGetObjectMacro(CutLine,vtkPolyData); vtkSetStringMacro(CutLinePointIdsArrayName); vtkGetStringMacro(CutLinePointIdsArrayName); protected: vtkvmtkPolyDataScissors(); ~vtkvmtkPolyDataScissors(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int GetCellsOnSameSide(vtkPolyData* input, vtkIdType targetCellId0, vtkIdType targetCellId1, vtkIdType referenceCellId, vtkIdType linePointId0, vtkIdType linePointId1, vtkIdType linePointId2, vtkIdList *cellsOnSameSide); int IsEdgeInCell(vtkPolyData *input, vtkIdType edgePointId0, vtkIdType edgePointId1, vtkIdType cellId); char *CutLinePointIdsArrayName; vtkPolyData *CutLine; private: vtkvmtkPolyDataScissors(const vtkvmtkPolyDataScissors&); // Not implemented. void operator=(const vtkvmtkPolyDataScissors&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyBallModeller.h0000664000175000017500000000522711757446472024160 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBallModeller.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyBallModeller - sample poly ball onto structured points // .SECTION Description // .. #ifndef __vtkvmtkPolyBallModeller_h #define __vtkvmtkPolyBallModeller_h #include "vtkImageAlgorithm.h" #include "vtkImageData.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyBallModeller : public vtkImageAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyBallModeller,vtkImageAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyBallModeller *New(); // Description: // Specify i-j-k dimensions on which to sample polyball function. vtkGetVectorMacro(SampleDimensions,int,3); vtkSetVectorMacro(SampleDimensions,int,3); // Description: // Specify the position in space to perform the sampling. vtkSetVectorMacro(ModelBounds,double,6); vtkGetVectorMacro(ModelBounds,double,6); vtkSetObjectMacro(ReferenceImage,vtkImageData); vtkGetObjectMacro(ReferenceImage,vtkImageData); vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); vtkSetMacro(UsePolyBallLine,int); vtkGetMacro(UsePolyBallLine,int); vtkBooleanMacro(UsePolyBallLine,int); vtkSetMacro(NegateFunction,int); vtkGetMacro(NegateFunction,int); vtkBooleanMacro(NegateFunction,int); protected: vtkvmtkPolyBallModeller(); ~vtkvmtkPolyBallModeller(); int FillInputPortInformation(int, vtkInformation *info); virtual int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int SampleDimensions[3]; double ModelBounds[6]; char* RadiusArrayName; int UsePolyBallLine; int NegateFunction; vtkImageData* ReferenceImage; private: vtkvmtkPolyBallModeller(const vtkvmtkPolyBallModeller&); // Not implemented. void operator=(const vtkvmtkPolyBallModeller&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineAngularMetricFilter.cxx0000664000175000017500000002021711757446472030677 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineAngularMetricFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.9 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataCenterlineAngularMetricFilter.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkvmtkPolyBallLine.h" #include "vtkPolyLine.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkPlane.h" #include "vtkvmtkConstants.h" #include "vtkvmtkMath.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlineAngularMetricFilter, "$Revision: 1.9 $"); vtkStandardNewMacro(vtkvmtkPolyDataCenterlineAngularMetricFilter); vtkvmtkPolyDataCenterlineAngularMetricFilter::vtkvmtkPolyDataCenterlineAngularMetricFilter() { this->CenterlineNormalsArrayName = NULL; } vtkvmtkPolyDataCenterlineAngularMetricFilter::~vtkvmtkPolyDataCenterlineAngularMetricFilter() { if (this->CenterlineNormalsArrayName) { delete[] this->CenterlineNormalsArrayName; this->CenterlineNormalsArrayName = NULL; } } void vtkvmtkPolyDataCenterlineAngularMetricFilter::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); tube->SetPolyBallRadiusArrayName(this->RadiusArrayName); double averagePoint[3]; averagePoint[0] = averagePoint[1] = averagePoint[2] = 0.0; double averageNormal[3]; averageNormal[0] = averageNormal[1] = averageNormal[2] = 0.0; double averageTangent[3]; averageTangent[0] = averageTangent[1] = averageTangent[2] = 0.0; double weightSum = 0.0; int numberOfCenterlineCells = this->Centerlines->GetNumberOfCells(); for (int i=0; i(centerlineGroupIdsArray->GetComponent(i,0)); if (centerlineGroupId != groupId) { continue; } centerlineGroupCellIds->Initialize(); centerlineGroupCellIds->InsertNextId(i); if (this->IncludeBifurcations) { int centerlineId = static_cast(centerlineIdsArray->GetComponent(i,0)); int centerlineTractId = static_cast(centerlineTractIdsArray->GetComponent(i,0)); for (int j=0; j(centerlineGroupIdsArray->GetComponent(j,0)); int adjacentCenterlineId = static_cast(centerlineIdsArray->GetComponent(j,0)); int adjacentCenterlineTractId = static_cast(centerlineTractIdsArray->GetComponent(j,0)); int adjacentBlanking = static_cast(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(); vtkCell* polyLine = this->Centerlines->GetCell(centerlineCellId); if (polyLine->GetCellType() != VTK_LINE && polyLine->GetCellType() != VTK_POLY_LINE) { continue; } double radius = 0.0; vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->RadiusArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,radius); double weight = radius * radius; double centerlinePoint[3]; vtkvmtkCenterlineUtilities::InterpolatePoint(this->Centerlines,centerlineCellId,centerlineSubId,centerlinePCoord,centerlinePoint); averagePoint[0] += weight * centerlinePoint[0]; averagePoint[1] += weight * centerlinePoint[1]; averagePoint[2] += weight * centerlinePoint[2]; double centerlinePoint0[3], centerlinePoint1[3]; polyLine->GetPoints()->GetPoint(centerlineSubId,centerlinePoint0); polyLine->GetPoints()->GetPoint(centerlineSubId+1,centerlinePoint1); if (vtkMath::Distance2BetweenPoints(centerlinePoint0,centerlinePoint1) < VTK_VMTK_DOUBLE_TOL) { if (centerlineSubId > 0) { polyLine->GetPoints()->GetPoint(centerlineSubId-1,centerlinePoint0); } else if (centerlineSubId+1 < polyLine->GetNumberOfPoints()-1) { polyLine->GetPoints()->GetPoint(centerlineSubId+2,centerlinePoint1); } } double tangent[3]; tangent[0] = centerlinePoint1[0] - centerlinePoint0[0]; tangent[1] = centerlinePoint1[1] - centerlinePoint0[1]; tangent[2] = centerlinePoint1[2] - centerlinePoint0[2]; averageTangent[0] += weight * tangent[0]; averageTangent[1] += weight * tangent[1]; averageTangent[2] += weight * tangent[2]; double normal[3]; vtkvmtkCenterlineUtilities::InterpolateTuple3(this->Centerlines,this->CenterlineNormalsArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,normal); averageNormal[0] += weight * normal[0]; averageNormal[1] += weight * normal[1]; averageNormal[2] += weight * normal[2]; weightSum += weight; } averagePoint[0] /= weightSum; averagePoint[1] /= weightSum; averagePoint[2] /= weightSum; vtkMath::Normalize(averageNormal); vtkMath::Normalize(averageTangent); double projectedPoint[3]; vtkPlane::ProjectPoint(point,averagePoint,averageTangent,projectedPoint); double positionVector[3]; positionVector[0] = projectedPoint[0] - averagePoint[0]; positionVector[1] = projectedPoint[1] - averagePoint[1]; positionVector[2] = projectedPoint[2] - averagePoint[2]; vtkMath::Normalize(positionVector); double normalPoint[3]; normalPoint[0] = averagePoint[0] + averageNormal[0]; normalPoint[1] = averagePoint[1] + averageNormal[1]; normalPoint[2] = averagePoint[2] + averageNormal[2]; double projectedNormalPoint[3]; vtkPlane::ProjectPoint(normalPoint,averagePoint,averageTangent,projectedNormalPoint); double projectedNormal[3]; projectedNormal[0] = projectedNormalPoint[0] - averagePoint[0]; projectedNormal[1] = projectedNormalPoint[1] - averagePoint[1]; projectedNormal[2] = projectedNormalPoint[2] - averagePoint[2]; vtkMath::Normalize(projectedNormal); double cross[3]; vtkMath::Cross(positionVector,projectedNormal,cross); double tangentDot = vtkMath::Dot(averageTangent,cross); double angle = vtkvmtkMath::AngleBetweenNormals(positionVector,projectedNormal); if (tangentDot < 0.0) { angle *= -1.0; } metricArray->SetComponent(pointId,0,angle); centerlineGroupCellIds->Delete(); tube->Delete(); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkMinHeap.cxx0000664000175000017500000001652111757446472022651 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMinHeap.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMinHeap.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkMinHeap, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkMinHeap); vtkvmtkMinHeap::vtkvmtkMinHeap() { this->MinHeapScalars = NULL; this->Heap = vtkIdList::New(); this->BackPointers = vtkIdList::New(); } vtkvmtkMinHeap::~vtkvmtkMinHeap() { if (this->MinHeapScalars) { this->MinHeapScalars->Delete(); this->MinHeapScalars = NULL; } this->Heap->Delete(); this->BackPointers->Delete(); } void vtkvmtkMinHeap::Initialize() { vtkIdType i; if (this->MinHeapScalars == NULL) { vtkErrorMacro(<< "No HeapScalars."); return; } this->Heap->Initialize(); this->BackPointers->Initialize(); vtkIdType numberOfScalars; numberOfScalars = this->MinHeapScalars->GetNumberOfTuples(); this->BackPointers->SetNumberOfIds(numberOfScalars); for (i=0; iBackPointers->SetId(i,-1); } } void vtkvmtkMinHeap::InsertNextId(vtkIdType id) { if (this->MinHeapScalars == NULL) { vtkErrorMacro(<< "No MinHeapScalars."); return; } vtkIdType numberOfScalars; numberOfScalars = this->MinHeapScalars->GetNumberOfTuples(); if ((id<0)||(id>=numberOfScalars)) { vtkErrorMacro(<< "Id inserted exceeds MinHeapScalars dimension."); return; } vtkIdType currentLoc; currentLoc = this->Heap->InsertNextId(id); this->BackPointers->InsertId(id,currentLoc); this->SiftUp(currentLoc); while (this->BackPointers->GetNumberOfIds() < numberOfScalars) { this->BackPointers->InsertNextId(-1); } if (this->BackPointers->GetNumberOfIds() < numberOfScalars) { this->BackPointers->SetNumberOfIds(numberOfScalars); } } int vtkvmtkMinHeap::GetSize() { return this->Heap->GetNumberOfIds(); } void vtkvmtkMinHeap::UpdateId(vtkIdType id) { if (this->MinHeapScalars == NULL) { vtkErrorMacro(<<"No MinHeapScalars."); return; } if ((id<0)||(id>=this->MinHeapScalars->GetNumberOfTuples())) { vtkErrorMacro(<<"Id inserted exceeds MinHeapScalars dimension."); return; } this->SiftUp(this->BackPointers->GetId(id)); } int vtkvmtkMinHeap::IsLeaf(vtkIdType loc) { vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((loc<0)||(loc>=heapSize)) { vtkErrorMacro(<<"Heap smaller than requested location."); return -1; } if ((loc >= heapSize/2)&&(loc < heapSize)) return 1; return 0; } vtkIdType vtkvmtkMinHeap::GetLeftChild(vtkIdType loc) { vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((loc<0)||(loc>=heapSize)) { vtkErrorMacro(<<"Heap smaller than requested location."); return -1; } if (loc >= heapSize/2) return -1; return 2*loc + 1; } vtkIdType vtkvmtkMinHeap::GetRightChild(vtkIdType loc) { vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((loc<0)||(loc>=heapSize)) { vtkErrorMacro(<< "Heap smaller than requested location."); return -1; } if (loc >= (heapSize-1)/2) return -1; return 2*loc + 2; } vtkIdType vtkvmtkMinHeap::GetParent(vtkIdType loc) { if (loc<0) { vtkErrorMacro(<<"Negative location requested."); return -1; } if (loc==0) return -1; return (loc-1)/2; } void vtkvmtkMinHeap::SiftUp(vtkIdType loc) { if (this->MinHeapScalars == NULL) { vtkErrorMacro(<<"No MinHeapScalars."); return; } vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((loc<0)||(loc>=heapSize)) { vtkErrorMacro(<<"Heap smaller than requested location."); return; } vtkIdType parentLoc; while (loc>0) { parentLoc = this->GetParent(loc); if (this->MinHeapScalars->GetValue(this->Heap->GetId(loc)) - this->MinHeapScalars->GetValue(this->Heap->GetId(parentLoc)) > VTK_VMTK_DOUBLE_TOL) { return; } this->Swap(loc,parentLoc); loc = parentLoc; } } void vtkvmtkMinHeap::SiftDown(vtkIdType loc) { if (this->MinHeapScalars == NULL) { vtkErrorMacro(<<"No MinHeapScalars."); return; } vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((loc<0)||(loc>=heapSize)) { vtkErrorMacro(<<"Heap smaller than requested location."); return; } vtkIdType minChildLoc, leftChildLoc, rightChildLoc; while (!this->IsLeaf(loc)) { leftChildLoc = this->GetLeftChild(loc); rightChildLoc = leftChildLoc + 1; minChildLoc = leftChildLoc; if ((leftChildLocHeap->GetNumberOfIds()-1) && (this->MinHeapScalars->GetValue(this->Heap->GetId(leftChildLoc)) - this->MinHeapScalars->GetValue(this->Heap->GetId(rightChildLoc))) > VTK_VMTK_DOUBLE_TOL) { minChildLoc = rightChildLoc; } if (this->MinHeapScalars->GetValue(this->Heap->GetId(loc)) - this->MinHeapScalars->GetValue(this->Heap->GetId(minChildLoc)) < -VTK_VMTK_DOUBLE_TOL) { return; } this->Swap(loc,minChildLoc); loc = minChildLoc; } } vtkIdType vtkvmtkMinHeap::RemoveMin() { vtkIdType minId, lastElementLoc; minId = this->Heap->GetId(0); lastElementLoc = this->Heap->GetNumberOfIds()-1; this->Swap(0,lastElementLoc); this->Heap->SetNumberOfIds(lastElementLoc); this->BackPointers->SetId(minId,-1); if (this->Heap->GetNumberOfIds()>0) { this->SiftDown(0); } return minId; } vtkIdType vtkvmtkMinHeap::GetMin() { vtkIdType minId; minId = this->Heap->GetId(0); return minId; } vtkIdType vtkvmtkMinHeap::RemoveAt(vtkIdType loc) { vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((loc<0)||(loc>=heapSize)) { vtkErrorMacro(<<"Heap smaller than requested location."); return -1; } vtkIdType locId, lastElementLoc; locId = this->Heap->GetId(loc); lastElementLoc = heapSize-1; this->Swap(locId,lastElementLoc); this->Heap->SetNumberOfIds(lastElementLoc); this->BackPointers->SetId(locId,-1); if (this->Heap->GetNumberOfIds()>0) this->SiftDown(loc); return locId; } void vtkvmtkMinHeap::Swap(vtkIdType loc0, vtkIdType loc1) { vtkIdType temp; vtkIdType heapSize; heapSize = this->Heap->GetNumberOfIds(); if ((heapSizeHeap->GetId(loc0); this->Heap->SetId(loc0,this->Heap->GetId(loc1)); this->Heap->SetId(loc1,temp); this->BackPointers->SetId(this->Heap->GetId(loc0),loc0); this->BackPointers->SetId(this->Heap->GetId(loc1),loc1); } void vtkvmtkMinHeap::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkBoundaryReferenceSystems.h0000664000175000017500000000622611757446472025750 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryReferenceSystems.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkBoundaryReferenceSystems - ... // .SECTION Description // . #ifndef __vtkvmtkBoundaryReferenceSystems_h #define __vtkvmtkBoundaryReferenceSystems_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class vtkPoints; class vtkPolyLine; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkBoundaryReferenceSystems : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkBoundaryReferenceSystems,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkBoundaryReferenceSystems *New(); // Description: // Set/Get the name of the array where mean boundary radius has to be stored. vtkSetStringMacro(BoundaryRadiusArrayName); vtkGetStringMacro(BoundaryRadiusArrayName); // Description: // Set/Get the name of the array where normals to boundaries have to be stored. vtkSetStringMacro(BoundaryNormalsArrayName); vtkGetStringMacro(BoundaryNormalsArrayName); // Description: // Set/Get the name of the array where reference system points 1 have to be stored. vtkSetStringMacro(Point1ArrayName); vtkGetStringMacro(Point1ArrayName); // Description: // Set/Get the name of the array where reference system points 2 have to be stored. vtkSetStringMacro(Point2ArrayName); vtkGetStringMacro(Point2ArrayName); static void ComputeBoundaryBarycenter(vtkPoints* points, double barycenter[3]); static double ComputeBoundaryMeanRadius(vtkPoints* points, double barycenter[3]); static void ComputeBoundaryNormal(vtkPoints* points, double barycenter[3], double normal[3]); static void OrientBoundaryNormalOutwards(vtkPolyData* surface, vtkPolyData* boundaries, vtkIdType boundaryCellId, double normal[3], double outwardNormal[3]); static void ComputeReferenceSystemPoints(double origin[3], double normal[3], double radius, double point1[3], double point2[3]); protected: vtkvmtkBoundaryReferenceSystems(); ~vtkvmtkBoundaryReferenceSystems(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* BoundaryRadiusArrayName; char* BoundaryNormalsArrayName; char* Point1ArrayName; char* Point2ArrayName; private: vtkvmtkBoundaryReferenceSystems(const vtkvmtkBoundaryReferenceSystems&); // Not implemented. void operator=(const vtkvmtkBoundaryReferenceSystems&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineReferenceSystemAttributesOffset.cxx0000664000175000017500000003214711757446472031664 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineReferenceSystemAttributesOffset.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.8 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkCenterlineReferenceSystemAttributesOffset, "$Revision: 1.8 $"); 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(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; iGetNumberOfIds(); i++) { vtkIdType currentCellId = groupCellIds->GetId(i); vtkIdType centerlineId = static_cast(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; jGetNumberOfIds(); j++) { vtkCell* branchCell = input->GetCell(centerlineCellIds->GetId(j)); int numberOfBranchPoints = branchCell->GetNumberOfPoints(); for (int k=0; kGetPointId(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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkMergeCenterlines.cxx0000664000175000017500000003435011757446472024563 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMergeCenterlines.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkMergeCenterlines.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkCenterlineBifurcationReferenceSystems.h" #include "vtkvmtkReferenceSystemUtilities.h" #include "vtkSplineFilter.h" #include "vtkCleanPolyData.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkMergeCenterlines, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkMergeCenterlines); vtkvmtkMergeCenterlines::vtkvmtkMergeCenterlines() { this->RadiusArrayName = NULL; this->GroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->TractIdsArrayName = NULL; this->BlankingArrayName = NULL; this->ResamplingStepLength = 0.0; this->MergeBlanked = 1; } vtkvmtkMergeCenterlines::~vtkvmtkMergeCenterlines() { if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->CenterlineIdsArrayName) { delete[] this->CenterlineIdsArrayName; this->CenterlineIdsArrayName = NULL; } if (this->TractIdsArrayName) { delete[] this->TractIdsArrayName; this->TractIdsArrayName = NULL; } if (this->BlankingArrayName) { delete[] this->BlankingArrayName; this->BlankingArrayName = NULL; } } int vtkvmtkMergeCenterlines::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->RadiusArrayName) { vtkErrorMacro(<<"RadiusArrayName not specified"); return 1; } vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { vtkErrorMacro(<<"RadiusArray 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->TractIdsArrayName) { vtkErrorMacro(<<"TractIdsArrayName not specified"); return 1; } vtkDataArray* tractIdsArray = input->GetCellData()->GetArray(this->TractIdsArrayName); if (!tractIdsArray) { vtkErrorMacro(<<"TractIdsArray with name specified does not exist"); return 1; } if (!this->BlankingArrayName) { vtkErrorMacro(<<"BlankingArrayName not specified"); return 1; } vtkDataArray* blankingArray = input->GetCellData()->GetArray(this->BlankingArrayName); if (!blankingArray) { vtkErrorMacro(<<"BlankingArray with name specified does not exist"); return 1; } vtkCleanPolyData* cleaner = vtkCleanPolyData::New(); cleaner->SetInput(input); cleaner->Update(); if (this->ResamplingStepLength < 1E-12) { this->ResamplingStepLength = 0.01 * cleaner->GetOutput()->GetLength(); } vtkSplineFilter* resampler = vtkSplineFilter::New(); resampler->SetInput(cleaner->GetOutput()); resampler->SetSubdivideToLength(); resampler->SetLength(this->ResamplingStepLength); resampler->Update(); vtkPolyData* resampledCenterlines = vtkPolyData::New(); resampledCenterlines->DeepCopy(resampler->GetOutput()); resampler->Delete(); radiusArray = resampledCenterlines->GetPointData()->GetArray(this->RadiusArrayName); vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputLines = vtkCellArray::New(); output->SetPoints(outputPoints); output->SetLines(outputLines); output->GetPointData()->CopyAllocate(resampledCenterlines->GetPointData()); output->GetCellData()->CopyAllocate(resampledCenterlines->GetCellData()); vtkIdList* nonBlankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetNonBlankedGroupsIdList(resampledCenterlines,this->GroupIdsArrayName,this->BlankingArrayName,nonBlankedGroupIds); vtkIdList* groupIdsToMergedCells = vtkIdList::New(); vtkIdType maxGroupId = vtkvmtkCenterlineUtilities::GetMaxGroupId(resampledCenterlines,this->GroupIdsArrayName); groupIdsToMergedCells->SetNumberOfIds(maxGroupId); int i; for (i=0; iSetId(i,-1); } vtkIdTypeArray* cellEndPointIds = vtkIdTypeArray::New(); cellEndPointIds->SetNumberOfComponents(2); for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = nonBlankedGroupIds->GetId(i); vtkIdList* groupUniqueCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(resampledCenterlines,this->GroupIdsArrayName,groupId,groupUniqueCellIds); int numberOfMergedCellPoints = 0; int j; for (j=0; jGetNumberOfIds(); j++) { vtkIdType cellId = groupUniqueCellIds->GetId(j); int numberOfCellPoints = resampledCenterlines->GetCell(cellId)->GetNumberOfPoints(); if ((j==0) || (numberOfCellPoints < numberOfMergedCellPoints)) { numberOfMergedCellPoints = numberOfCellPoints; } } vtkIdType mergedCellId = outputLines->InsertNextCell(numberOfMergedCellPoints); groupIdsToMergedCells->InsertId(groupId,mergedCellId); int k; for (k=0; kGetNumberOfIds(); j++) { vtkIdType cellId = groupUniqueCellIds->GetId(j); double point[3]; vtkIdType pointId = resampledCenterlines->GetCell(cellId)->GetPointId(k); resampledCenterlines->GetPoint(pointId,point); double radius = radiusArray->GetTuple1(pointId); double weight = radius*radius; resampledCenterlines->GetCell(cellId)->GetPoints()->GetPoint(k,point); mergedPoint[0] += weight * point[0]; mergedPoint[1] += weight * point[1]; mergedPoint[2] += weight * point[2]; weightSum += weight; } mergedPoint[0] /= weightSum; mergedPoint[1] /= weightSum; mergedPoint[2] /= weightSum; vtkIdType mergedPointId = outputPoints->InsertNextPoint(mergedPoint); outputLines->InsertCellPoint(mergedPointId); vtkIdType cellId = groupUniqueCellIds->GetId(0); vtkIdType pointId = resampledCenterlines->GetCell(cellId)->GetPointId(k); output->GetPointData()->CopyData(resampledCenterlines->GetPointData(),pointId,mergedPointId); if (k==0 || k==numberOfMergedCellPoints-1) { cellEndPointIds->InsertNextValue(mergedPointId); } } vtkIdType cellId = groupUniqueCellIds->GetId(0); output->GetCellData()->CopyData(resampledCenterlines->GetCellData(),cellId,mergedCellId); groupUniqueCellIds->Delete(); } if (!this->MergeBlanked) { nonBlankedGroupIds->Delete(); resampledCenterlines->Delete(); outputPoints->Delete(); outputLines->Delete(); groupIdsToMergedCells->Delete(); cellEndPointIds->Delete(); return 1; } vtkvmtkCenterlineBifurcationReferenceSystems* referenceSystemsFilter = vtkvmtkCenterlineBifurcationReferenceSystems::New(); referenceSystemsFilter->SetInput(resampledCenterlines); referenceSystemsFilter->SetRadiusArrayName(this->RadiusArrayName); referenceSystemsFilter->SetGroupIdsArrayName(this->GroupIdsArrayName); referenceSystemsFilter->SetBlankingArrayName(this->BlankingArrayName); referenceSystemsFilter->SetNormalArrayName("Normal"); referenceSystemsFilter->SetUpNormalArrayName("UpNormal"); referenceSystemsFilter->Update(); vtkPolyData* referenceSystems = referenceSystemsFilter->GetOutput(); int numberOfMergedCells = outputLines->GetNumberOfCells(); vtkIdList* blankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetBlankedGroupsIdList(resampledCenterlines,this->GroupIdsArrayName,this->BlankingArrayName,blankedGroupIds); vtkIdList* groupIdsToBifurcationPointIds = vtkIdList::New(); vtkIdTypeArray* cellAdditionalEndPointIds = vtkIdTypeArray::New(); cellAdditionalEndPointIds->SetNumberOfComponents(2); cellAdditionalEndPointIds->SetNumberOfTuples(numberOfMergedCells); vtkIdType tupleValue[2]; tupleValue[0] = tupleValue[1] = -1; for (i=0; iSetTupleValue(i,tupleValue); } for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = blankedGroupIds->GetId(i); vtkIdType referenceSystemPointId = vtkvmtkReferenceSystemUtilities::GetReferenceSystemPointId(referenceSystems,this->GroupIdsArrayName,groupId); vtkIdList* upStreamGroupIds = vtkIdList::New(); vtkIdList* downStreamGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::FindAdjacentCenterlineGroupIds(resampledCenterlines,this->GroupIdsArrayName,this->CenterlineIdsArrayName,this->TractIdsArrayName,groupId,upStreamGroupIds,downStreamGroupIds); double bifurcationPoint[3]; referenceSystems->GetPoint(referenceSystemPointId,bifurcationPoint); vtkIdType bifurcationPointId = outputPoints->InsertNextPoint(bifurcationPoint); vtkIdType sourcePointId = -1; int j; for (j=0; jGetNumberOfIds(); j++) { vtkIdType mergedCellId = groupIdsToMergedCells->GetId(upStreamGroupIds->GetId(j)); if (mergedCellId == -1) { continue; } if (sourcePointId == -1) { vtkIdList* groupUniqueCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(resampledCenterlines,this->GroupIdsArrayName,upStreamGroupIds->GetId(j),groupUniqueCellIds); vtkCell* resampledCell = resampledCenterlines->GetCell(groupUniqueCellIds->GetId(0)); sourcePointId = resampledCell->GetPointId(resampledCell->GetNumberOfPoints()-1); groupUniqueCellIds->Delete(); } vtkIdType tupleValue[2]; cellAdditionalEndPointIds->GetTupleValue(mergedCellId,tupleValue); tupleValue[1] = bifurcationPointId; cellAdditionalEndPointIds->SetTupleValue(mergedCellId,tupleValue); } for (j=0; jGetNumberOfIds(); j++) { vtkIdType mergedCellId = groupIdsToMergedCells->GetId(downStreamGroupIds->GetId(j)); if (mergedCellId == -1) { continue; } if (sourcePointId == -1) { vtkIdList* groupUniqueCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(resampledCenterlines,this->GroupIdsArrayName,downStreamGroupIds->GetId(j),groupUniqueCellIds); vtkCell* resampledCell = resampledCenterlines->GetCell(groupUniqueCellIds->GetId(0)); sourcePointId = resampledCell->GetPointId(0); groupUniqueCellIds->Delete(); } vtkIdType tupleValue[2]; cellAdditionalEndPointIds->GetTupleValue(mergedCellId,tupleValue); tupleValue[0] = bifurcationPointId; cellAdditionalEndPointIds->SetTupleValue(mergedCellId,tupleValue); } if (sourcePointId == -1) { upStreamGroupIds->Delete(); downStreamGroupIds->Delete(); continue; } // TODO: interpolate point data instead of copying from first upstream point - good enough for now output->GetPointData()->CopyData(resampledCenterlines->GetPointData(),sourcePointId,bifurcationPointId); upStreamGroupIds->Delete(); downStreamGroupIds->Delete(); } vtkCellArray* extendedOutputLines = vtkCellArray::New(); outputLines->InitTraversal(); for (i=0; iGetNextCell(npts,pts); vtkIdType tupleValue[2]; cellAdditionalEndPointIds->GetTupleValue(i,tupleValue); vtkIdType extendedNpts = npts; if (tupleValue[0] != -1) { extendedNpts += 1; } if (tupleValue[1] != -1) { extendedNpts += 1; } extendedOutputLines->InsertNextCell(extendedNpts); if (tupleValue[0] != -1) { extendedOutputLines->InsertCellPoint(tupleValue[0]); } int j; for (j=0; jInsertCellPoint(pts[j]); } if (tupleValue[1] != -1) { extendedOutputLines->InsertCellPoint(tupleValue[1]); } } output->SetLines(extendedOutputLines); nonBlankedGroupIds->Delete(); resampledCenterlines->Delete(); outputPoints->Delete(); outputLines->Delete(); groupIdsToMergedCells->Delete(); cellEndPointIds->Delete(); referenceSystemsFilter->Delete(); blankedGroupIds->Delete(); groupIdsToBifurcationPointIds->Delete(); cellAdditionalEndPointIds->Delete(); extendedOutputLines->Delete(); return 1; } void vtkvmtkMergeCenterlines::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkNonManifoldFastMarching.cxx0000664000175000017500000005156311757446472026030 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNonManifoldFastMarching.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkNonManifoldFastMarching.h" #include "vtkvmtkConstants.h" #include "vtkCellData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkCharArray.h" #include "vtkMath.h" #include "vtkPolyLine.h" #include "vtkTriangle.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkNonManifoldFastMarching, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkNonManifoldFastMarching); vtkvmtkNonManifoldFastMarching::vtkvmtkNonManifoldFastMarching() { this->Seeds = NULL; this->TScalars = vtkDoubleArray::New(); this->StatusScalars = vtkCharArray::New(); this->ConsideredMinHeap = vtkvmtkMinHeap::New(); this->Regularization = 0.0; this->StopTravelTime = VTK_VMTK_LARGE_DOUBLE; this->StopNumberOfPoints = VTK_VMTK_LARGE_INTEGER; this->UnitSpeed = 0; this->InitializeFromScalars = 0; this->InitializationArrayName = NULL; this->SolutionArrayName = NULL; this->CostFunctionArrayName = NULL; this->SeedsBoundaryConditions = 0; this->PolyDataBoundaryConditions = 0; this->BoundaryPolyData = NULL; this->IntersectedEdgesArrayName = NULL; this->NumberOfAcceptedPoints = 0; this->AllowLineUpdate = 1; this->UpdateFromConsidered = 1; } vtkvmtkNonManifoldFastMarching::~vtkvmtkNonManifoldFastMarching() { if (this->Seeds) { this->Seeds->Delete(); this->Seeds = NULL; } if (this->BoundaryPolyData) { this->BoundaryPolyData->Delete(); this->BoundaryPolyData = NULL; } if (this->SolutionArrayName) { delete[] this->SolutionArrayName; this->SolutionArrayName = NULL; } if (this->CostFunctionArrayName) { delete[] this->CostFunctionArrayName; this->CostFunctionArrayName = NULL; } this->TScalars->Delete(); this->StatusScalars->Delete(); this->ConsideredMinHeap->Delete(); } void vtkvmtkNonManifoldFastMarching::InitPropagation(vtkPolyData* input) { vtkIdType i, j, k, l; vtkIdType pointId; vtkIdType npts, *pts, *cells; unsigned short ncells; vtkIdType intersectedEdge[2]; vtkDataArray* initializationArray, *costFunctionArray, *intersectedEdgesArray; vtkIdList* neighborCells; vtkIdList* neighborIds; vtkIdList* boundaryPointIds; int subId; double pcoords[3], *weights; double closestPoint[3]; double distance, distance2, minDistance; int allowLineUpdateBackup; vtkPolyLine* polyLine; boundaryPointIds = vtkIdList::New(); neighborCells = vtkIdList::New(); neighborIds = vtkIdList::New(); allowLineUpdateBackup = this->AllowLineUpdate; this->AllowLineUpdate = 1; initializationArray = NULL; if (this->InitializeFromScalars) { initializationArray = input->GetPointData()->GetArray(this->InitializationArrayName); } if (!this->UnitSpeed) { costFunctionArray = input->GetPointData()->GetArray(this->CostFunctionArrayName); } input->BuildCells(); input->BuildLinks(); this->StatusScalars->SetNumberOfTuples(input->GetNumberOfPoints()); this->StatusScalars->FillComponent(0,VTK_VMTK_FAR_STATUS); this->TScalars->SetNumberOfTuples(input->GetNumberOfPoints()); this->TScalars->FillComponent(0,VTK_VMTK_LARGE_DOUBLE); this->NumberOfAcceptedPoints = 0; this->ConsideredMinHeap->SetMinHeapScalars(this->TScalars); this->ConsideredMinHeap->Initialize(); if (this->SeedsBoundaryConditions) { for (i=0; iSeeds->GetNumberOfIds(); i++) { pointId = this->Seeds->GetId(i); boundaryPointIds->InsertUniqueId(pointId); if (this->InitializeFromScalars) { this->TScalars->SetComponent(pointId,0,initializationArray->GetTuple1(pointId)); } else { this->TScalars->SetComponent(pointId,0,0.0f); } } } if (this->PolyDataBoundaryConditions) { this->BoundaryPolyData->BuildCells(); this->BoundaryPolyData->BuildLinks(); intersectedEdgesArray = this->BoundaryPolyData->GetPointData()->GetArray(this->IntersectedEdgesArrayName); for (i=0; iBoundaryPolyData->GetNumberOfPoints(); i++) { intersectedEdge[0] = static_cast(intersectedEdgesArray->GetComponent(i,0)); intersectedEdge[1] = static_cast(intersectedEdgesArray->GetComponent(i,1)); neighborCells->Initialize(); if (intersectedEdge[0]==intersectedEdge[1]) { input->GetPointCells(intersectedEdge[0],neighborCells); boundaryPointIds->InsertUniqueId(intersectedEdge[0]); this->TScalars->SetComponent(intersectedEdge[0],0,0.0); } else { input->GetCellEdgeNeighbors(-1,intersectedEdge[0],intersectedEdge[1],neighborCells); boundaryPointIds->InsertUniqueId(intersectedEdge[0]); boundaryPointIds->InsertUniqueId(intersectedEdge[1]); } for (j=0; jGetNumberOfIds(); j++) { input->GetCellPoints(neighborCells->GetId(j),npts,pts); for (k=0; kInsertUniqueId(pts[k]); minDistance = this->TScalars->GetComponent(pts[k],0); this->BoundaryPolyData->GetPointCells(i,ncells,cells); for (l=0; lBoundaryPolyData->GetCell(cells[l])); if (!polyLine) { vtkWarningMacro(<<"BoundaryPolyData is not all made up of PolyLines"); continue; } weights = new double[polyLine->GetNumberOfPoints()]; double point[3]; input->GetPoint(pts[k],point); polyLine->EvaluatePosition(point,closestPoint,subId,pcoords,distance2,weights); delete[] weights; distance = sqrt(distance2); if (distance - minDistance < -VTK_VMTK_DOUBLE_TOL) { this->TScalars->SetComponent(pts[k],0,distance); minDistance = distance; } } } } } } vtkIdType numberOfBoundaryPointIds; numberOfBoundaryPointIds = boundaryPointIds->GetNumberOfIds(); for (i=0; iStatusScalars->SetValue(boundaryPointIds->GetId(i),VTK_VMTK_ACCEPTED_STATUS); this->NumberOfAcceptedPoints++; } for (k=0; k<3; k++) // get a good initial solution { for (i=0; iUpdateNeighborhood(input,boundaryPointIds->GetId(i)); } } this->AllowLineUpdate = allowLineUpdateBackup; boundaryPointIds->Delete(); neighborCells->Delete(); neighborIds->Delete(); } void vtkvmtkNonManifoldFastMarching::GetNeighbors(vtkPolyData* input, vtkIdType pointId, vtkIdList* neighborIds) { vtkIdType i, j; vtkIdType npts, *pts, *cells; unsigned short ncells; input->GetPointCells(pointId,ncells,cells); for (i=0; iGetCellPoints(cells[i],npts,pts); for (j=0; jInsertUniqueId(pts[j]); } } } } void vtkvmtkNonManifoldFastMarching::SolveQuadratic(double a, double b, double c, char &nSol, double &x0, double &x1) { double delta, q; delta = b*b - 4*a*c; if (delta < -VTK_VMTK_DOUBLE_TOL) { nSol = -1; x0 = VTK_VMTK_LARGE_DOUBLE; x1 = VTK_VMTK_LARGE_DOUBLE; return; } if (fabs(a) > VTK_VMTK_DOUBLE_TOL) { nSol = 2; if (delta < VTK_VMTK_DOUBLE_TOL) { x0 = -b / 2.0*a; x1 = -b / 2.0*a; return; } if (b < - VTK_VMTK_DOUBLE_TOL) { q = - 0.5 * (b - sqrt(delta)); } else if (b > VTK_VMTK_DOUBLE_TOL) { q = - 0.5 * (b + sqrt(delta)); } else { x0 = - sqrt(-c / a); x1 = sqrt(-c / a); return; } x0 = q / a; x1 = c / q; } else if (b > VTK_VMTK_DOUBLE_TOL) { nSol = 1; x0 = -c / b; x1 = VTK_VMTK_LARGE_DOUBLE; } else { nSol = 0; x0 = VTK_VMTK_LARGE_DOUBLE; x1 = VTK_VMTK_LARGE_DOUBLE; } } double vtkvmtkNonManifoldFastMarching::ComputeUpdateFromCellNeighbor(vtkPolyData* input, vtkIdType neighborId, vtkIdType* trianglePts) { double fScalar, neighborT; vtkIdType i; bool canUpdateFromTriangle, canUpdateFromLine; vtkIdType pointIdForLineUpdate, pointId; vtkIdType edgesPointId[2]; double edgesLength[2], edgesTScalar[2]; double edgesVector[2][3]; double edgesNormal[2][3]; double cosTheta; vtkIdType aEdgeId, bEdgeId; char nSol; double bEq, aEq, cEq, uEq, FEq, tEq, tCompEq, t0Eq, t1Eq, t0CompEq, tCompEqLower, tCompEqHigher; double edgeLength; vtkDataArray* costFunctionArray; pointIdForLineUpdate = -1; tCompEq = 0.0; if (!this->UnitSpeed) { costFunctionArray = input->GetPointData()->GetArray(this->CostFunctionArrayName); } if (this->UnitSpeed) { fScalar = 1.0; } else { fScalar = costFunctionArray->GetTuple1(neighborId); } neighborT = this->TScalars->GetValue(neighborId); canUpdateFromTriangle = true; canUpdateFromLine = false; for (i=1; i<3; i++) { pointId = trianglePts[i]; if (pointId!=neighborId) { if ((this->StatusScalars->GetValue(pointId) != VTK_VMTK_ACCEPTED_STATUS) || ((this->StatusScalars->GetValue(pointId) == VTK_VMTK_FAR_STATUS)&&(this->UpdateFromConsidered))) { canUpdateFromTriangle = false; } else { canUpdateFromLine = true; pointIdForLineUpdate = pointId; } } } if (!canUpdateFromTriangle) { if ((canUpdateFromLine)&&(this->AllowLineUpdate)) { double neighborPoint[3], lineUpdatePoint[3]; input->GetPoint(neighborId,neighborPoint); input->GetPoint(pointIdForLineUpdate,lineUpdatePoint); edgeLength = sqrt(vtkMath::Distance2BetweenPoints(neighborPoint,lineUpdatePoint)); neighborT = this->Min(this->TScalars->GetValue(pointIdForLineUpdate) + edgeLength * fScalar,neighborT); return neighborT; } else return VTK_VMTK_LARGE_DOUBLE; } if (trianglePts[0]==neighborId) { edgesPointId[0] = trianglePts[1]; edgesPointId[1] = trianglePts[2]; } else if (trianglePts[1]==neighborId) { edgesPointId[0] = trianglePts[2]; edgesPointId[1] = trianglePts[0]; } else { edgesPointId[0] = trianglePts[0]; edgesPointId[1] = trianglePts[1]; } double neighborPoint[3]; input->GetPoint(neighborId,neighborPoint); double edgePoint0[3], edgePoint1[3]; input->GetPoint(edgesPointId[0],edgePoint0); input->GetPoint(edgesPointId[1],edgePoint1); edgesVector[0][0] = neighborPoint[0] - edgePoint0[0]; edgesVector[0][1] = neighborPoint[1] - edgePoint0[1]; edgesVector[0][2] = neighborPoint[2] - edgePoint0[2]; edgesVector[1][0] = neighborPoint[0] - edgePoint1[0]; edgesVector[1][1] = neighborPoint[1] - edgePoint1[1]; edgesVector[1][2] = neighborPoint[2] - edgePoint1[2]; edgesLength[0] = vtkMath::Norm(edgesVector[0]); edgesLength[1] = vtkMath::Norm(edgesVector[1]); if (edgesLength[0] > VTK_VMTK_DOUBLE_TOL) { edgesNormal[0][0] = edgesVector[0][0] / edgesLength[0]; edgesNormal[0][1] = edgesVector[0][1] / edgesLength[0]; edgesNormal[0][2] = edgesVector[0][2] / edgesLength[0]; } else { edgesLength[0] = 0.0; edgesNormal[0][0] = 0.0; edgesNormal[0][1] = 0.0; edgesNormal[0][2] = 0.0; } if (edgesLength[1] > VTK_VMTK_DOUBLE_TOL) { edgesNormal[1][0] = edgesVector[1][0] / edgesLength[1]; edgesNormal[1][1] = edgesVector[1][1] / edgesLength[1]; edgesNormal[1][2] = edgesVector[1][2] / edgesLength[1]; } else { edgesLength[1] = 0.0; edgesNormal[1][0] = 0.0; edgesNormal[1][1] = 0.0; edgesNormal[1][2] = 0.0; } cosTheta = vtkMath::Dot(edgesNormal[0],edgesNormal[1]); if (fabs(cosTheta) < VTK_VMTK_DOUBLE_TOL) cosTheta = 0.0f; edgesTScalar[0] = this->TScalars->GetValue(edgesPointId[0]); edgesTScalar[1] = this->TScalars->GetValue(edgesPointId[1]); if (edgesTScalar[0]-edgesTScalar[1] > VTK_VMTK_DOUBLE_TOL) { aEdgeId = 0; bEdgeId = 1; } else { aEdgeId = 1; bEdgeId = 0; } FEq = fScalar + this->Regularization; uEq = edgesTScalar[aEdgeId]-edgesTScalar[bEdgeId]; aEq = edgesLength[aEdgeId]*edgesLength[aEdgeId] + edgesLength[bEdgeId]*edgesLength[bEdgeId] - 2*edgesLength[aEdgeId]*edgesLength[bEdgeId]*cosTheta; bEq = 2 * edgesLength[bEdgeId] * uEq * (edgesLength[aEdgeId] * cosTheta - edgesLength[bEdgeId]); cEq = edgesLength[bEdgeId]*edgesLength[bEdgeId] * (uEq*uEq - FEq*FEq*edgesLength[aEdgeId]*edgesLength[aEdgeId]*(1-cosTheta*cosTheta)); this->SolveQuadratic(aEq,bEq,cEq,nSol,t0Eq,t1Eq); if (nSol==2) { tEq = this->Min(t0Eq,t1Eq); } else { tEq = t0Eq; } if (fabs(tEq) > VTK_VMTK_DOUBLE_TOL) { tCompEq = edgesLength[bEdgeId] * (tEq - uEq) / tEq; } else { t0CompEq = VTK_VMTK_LARGE_DOUBLE; } tCompEqLower = edgesLength[aEdgeId]*cosTheta; if (fabs(cosTheta) > VTK_VMTK_DOUBLE_TOL) { tCompEqHigher = edgesLength[aEdgeId]/cosTheta; } else { tCompEqHigher = VTK_VMTK_LARGE_DOUBLE; } if ((uEq - tEq < -VTK_VMTK_DOUBLE_TOL) && (tCompEq - tCompEqLower > VTK_VMTK_DOUBLE_TOL) && (tCompEq - tCompEqHigher < -VTK_VMTK_DOUBLE_TOL)) { neighborT = this->Min(tEq + edgesTScalar[bEdgeId],neighborT); } else { neighborT = this->Min(edgesLength[aEdgeId]*FEq + edgesTScalar[aEdgeId] , edgesLength[bEdgeId]*FEq + edgesTScalar[bEdgeId]); } return neighborT; } void vtkvmtkNonManifoldFastMarching::UpdateNeighbor(vtkPolyData* input, vtkIdType neighborId) { vtkIdType i, j, k; vtkIdType npts, *pts; vtkIdType trianglePts[3]; double tMin, tScalar; vtkIdList* neighborCellNeighborIds; if ((neighborId<0)||(neighborId>=this->TScalars->GetNumberOfTuples())) { vtkErrorMacro("Requested id exceeds TScalars dimension."); return; } neighborCellNeighborIds = vtkIdList::New(); input->GetPointCells(neighborId,neighborCellNeighborIds); tMin = this->TScalars->GetValue(neighborId); trianglePts[0] = neighborId; for (i=0; iGetNumberOfIds(); i++) { // virtual triangulation input->GetCellPoints(neighborCellNeighborIds->GetId(i),npts,pts); for (j=0; jComputeUpdateFromCellNeighbor(input,neighborId,trianglePts); tMin = this->Min(tScalar,tMin); } } } } } this->TScalars->SetValue(neighborId,tMin); neighborCellNeighborIds->Delete(); } void vtkvmtkNonManifoldFastMarching::UpdateNeighborhood(vtkPolyData* input, vtkIdType pointId) { vtkIdList* neighborIds; vtkIdType i, neighborId; neighborIds = vtkIdList::New(); this->GetNeighbors(input,pointId,neighborIds); for (i=0; iGetNumberOfIds(); i++) { neighborId = neighborIds->GetId(i); if (this->StatusScalars->GetValue(neighborId)!=VTK_VMTK_ACCEPTED_STATUS) { this->UpdateNeighbor(input,neighborId); if (this->StatusScalars->GetValue(neighborId) == VTK_VMTK_FAR_STATUS) { this->StatusScalars->SetValue(neighborId,VTK_VMTK_CONSIDERED_STATUS); this->ConsideredMinHeap->InsertNextId(neighborId); } else { this->ConsideredMinHeap->UpdateId(neighborId); } } } neighborIds->Delete(); } void vtkvmtkNonManifoldFastMarching::Propagate(vtkPolyData* input) { double currentTravelTime; vtkIdType trialId; while (this->ConsideredMinHeap->GetSize()>0) { trialId = this->ConsideredMinHeap->RemoveMin(); this->StatusScalars->SetValue(trialId,VTK_VMTK_ACCEPTED_STATUS); this->NumberOfAcceptedPoints++; this->UpdateNeighborhood(input,trialId); currentTravelTime = this->TScalars->GetValue(trialId); if ((this->StopNumberOfPoints)||(this->StopTravelTime)) { if ((this->NumberOfAcceptedPoints >= this->StopNumberOfPoints)||(currentTravelTime - this->StopTravelTime > VTK_VMTK_DOUBLE_TOL)) { break; } } } } int vtkvmtkNonManifoldFastMarching::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())); char eikonalSolutionArrayName[512]; vtkIdType i; if (this->InitializeFromScalars) { if (!this->InitializationArrayName) { vtkErrorMacro(<<"No initialization array name defined!"); return 1; } if (!input->GetPointData()->GetArray(this->InitializationArrayName)) { vtkErrorMacro(<< "Initialization array with name specified does not exist!"); return 1; } } if (!this->UnitSpeed) { if (!this->CostFunctionArrayName) { vtkErrorMacro(<<"No cost function array name defined!"); return 1; } if (!input->GetPointData()->GetArray(this->CostFunctionArrayName)) { vtkErrorMacro(<< "Cost function array with name specified does not exist!"); return 1; } } if (!this->SeedsBoundaryConditions && !this->PolyDataBoundaryConditions) { vtkWarningMacro(<<"No boundary conditions activated!"); return 1; } if (this->SeedsBoundaryConditions) { if (!this->Seeds) { vtkErrorMacro(<<"Seeds not specified!"); return 1; } for (i=0; iSeeds->GetNumberOfIds(); i++) { if ((this->Seeds->GetId(i)<0) || (this->Seeds->GetId(i)>input->GetNumberOfPoints())) { vtkErrorMacro(<<"Seed id exceeds input number of points!"); return 1; } } } if (this->PolyDataBoundaryConditions) { if (!this->BoundaryPolyData) { vtkErrorMacro(<<"Boundary poly data not specified!"); return 1; } if (!this->IntersectedEdgesArrayName) { vtkErrorMacro(<<"Intersected edges array name not specified!"); return 1; } if (!this->BoundaryPolyData->GetPointData()->GetArray(this->IntersectedEdgesArrayName)) { vtkErrorMacro(<<"Intersected edges array with name specified does not exist!"); return 1; } if (!this->UnitSpeed) { vtkWarningMacro(<<"Initialization can be inaccurate if unit speed is not used for poly data boundary conditions."); } } this->InitPropagation(input); this->Propagate(input); int naccepted = 0, nconsidered = 0, nfar = 0; for (i=0; iGetNumberOfPoints(); i++) { if (this->TScalars->GetValue(i)>=VTK_VMTK_LARGE_DOUBLE) { if (this->StatusScalars->GetValue(i) == VTK_VMTK_ACCEPTED_STATUS) { this->TScalars->SetValue(i,0.0); naccepted++; } if (this->StatusScalars->GetValue(i) == VTK_VMTK_CONSIDERED_STATUS) { this->TScalars->SetValue(i,0.0); nconsidered++; } if (this->StatusScalars->GetValue(i) == VTK_VMTK_FAR_STATUS) { this->TScalars->SetValue(i,0.0); nfar++; } } } if (naccepted||nconsidered||nfar) { // vtkWarningMacro(<<"Unvisited points found: "<SolutionArrayName) { strcpy(eikonalSolutionArrayName,this->SolutionArrayName); } else { strcpy(eikonalSolutionArrayName,"EikonalSolution"); } this->TScalars->SetName(eikonalSolutionArrayName); output->CopyStructure(input); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); output->GetPointData()->AddArray(this->TScalars); output->GetPointData()->SetActiveScalars(eikonalSolutionArrayName); return 1; } void vtkvmtkNonManifoldFastMarching::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineAttributesFilter.h0000664000175000017500000000430711757446472026261 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineAttributesFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkCenterlineAttributesFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineAttributesFilter* New(); vtkSetStringMacro(AbscissasArrayName); vtkGetStringMacro(AbscissasArrayName); vtkSetStringMacro(ParallelTransportNormalsArrayName); vtkGetStringMacro(ParallelTransportNormalsArrayName); protected: vtkvmtkCenterlineAttributesFilter(); ~vtkvmtkCenterlineAttributesFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBifurcationVectors.cxx0000664000175000017500000006337111757446472027161 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBifurcationVectors.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineBifurcationVectors.h" #include "vtkPolyData.h" #include "vtkIdList.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkPolyLine.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkvmtkMath.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkReferenceSystemUtilities.h" vtkCxxRevisionMacro(vtkvmtkCenterlineBifurcationVectors, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkCenterlineBifurcationVectors); vtkvmtkCenterlineBifurcationVectors::vtkvmtkCenterlineBifurcationVectors() { this->RadiusArrayName = NULL; this->GroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->TractIdsArrayName = NULL; this->BlankingArrayName = NULL; this->ReferenceSystems = NULL; this->ReferenceSystemGroupIdsArrayName = NULL; this->ReferenceSystemNormalArrayName = NULL; this->ReferenceSystemUpNormalArrayName = NULL; this->BifurcationVectorsArrayName = NULL; this->InPlaneBifurcationVectorsArrayName = NULL; this->OutOfPlaneBifurcationVectorsArrayName = NULL; this->BifurcationVectorsOrientationArrayName = NULL; this->BifurcationGroupIdsArrayName = NULL; this->InPlaneBifurcationVectorAnglesArrayName = NULL; this->OutOfPlaneBifurcationVectorAnglesArrayName = NULL; this->NormalizeBifurcationVectors = false; } vtkvmtkCenterlineBifurcationVectors::~vtkvmtkCenterlineBifurcationVectors() { if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->CenterlineIdsArrayName) { delete[] this->CenterlineIdsArrayName; this->CenterlineIdsArrayName = NULL; } if (this->TractIdsArrayName) { delete[] this->TractIdsArrayName; this->TractIdsArrayName = NULL; } if (this->BlankingArrayName) { delete[] this->BlankingArrayName; this->BlankingArrayName = NULL; } if (this->ReferenceSystems) { this->ReferenceSystems->Delete(); } if (this->ReferenceSystemGroupIdsArrayName) { delete[] this->ReferenceSystemGroupIdsArrayName; this->ReferenceSystemGroupIdsArrayName = NULL; } if (this->ReferenceSystemNormalArrayName) { delete[] this->ReferenceSystemNormalArrayName; this->ReferenceSystemNormalArrayName = NULL; } if (this->ReferenceSystemUpNormalArrayName) { delete[] this->ReferenceSystemUpNormalArrayName; this->ReferenceSystemUpNormalArrayName = NULL; } if (this->BifurcationVectorsArrayName) { delete[] this->BifurcationVectorsArrayName; this->BifurcationVectorsArrayName = NULL; } if (this->InPlaneBifurcationVectorsArrayName) { delete[] this->InPlaneBifurcationVectorsArrayName; this->InPlaneBifurcationVectorsArrayName = NULL; } if (this->OutOfPlaneBifurcationVectorsArrayName) { delete[] this->OutOfPlaneBifurcationVectorsArrayName; this->OutOfPlaneBifurcationVectorsArrayName = NULL; } if (this->InPlaneBifurcationVectorAnglesArrayName) { delete[] this->InPlaneBifurcationVectorAnglesArrayName; this->InPlaneBifurcationVectorAnglesArrayName = NULL; } if (this->OutOfPlaneBifurcationVectorAnglesArrayName) { delete[] this->OutOfPlaneBifurcationVectorAnglesArrayName; this->OutOfPlaneBifurcationVectorAnglesArrayName = NULL; } if (this->BifurcationVectorsOrientationArrayName) { delete[] this->BifurcationVectorsOrientationArrayName; this->BifurcationVectorsOrientationArrayName = NULL; } if (this->BifurcationGroupIdsArrayName) { delete[] this->BifurcationGroupIdsArrayName; this->BifurcationGroupIdsArrayName = NULL; } } int vtkvmtkCenterlineBifurcationVectors::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->RadiusArrayName) { vtkErrorMacro(<<"RadiusArrayName not specified"); return 1; } vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { vtkErrorMacro(<<"RadiusArray 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->TractIdsArrayName) { vtkErrorMacro(<<"TractIdsArrayName not specified"); return 1; } vtkDataArray* tractIdsArray = input->GetCellData()->GetArray(this->TractIdsArrayName); if (!tractIdsArray) { vtkErrorMacro(<<"TractIdsArray with name specified does not exist"); return 1; } if (!this->BlankingArrayName) { vtkErrorMacro(<<"BlankingArrayName not specified"); return 1; } vtkDataArray* blankingArray = input->GetCellData()->GetArray(this->BlankingArrayName); if (!blankingArray) { vtkErrorMacro(<<"BlankingArray with name specified does not exist"); return 1; } if (!this->ReferenceSystemGroupIdsArrayName) { vtkErrorMacro(<<"ReferenceSystemGroupIdsArrayName not specified"); return 1; } vtkDataArray* referenceSystemGroupIdsArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemGroupIdsArrayName); if (!referenceSystemGroupIdsArray) { vtkErrorMacro(<<"ReferenceSystemGroupIdsArray with name specified does not exist"); return 1; } if (!this->ReferenceSystemNormalArrayName) { vtkErrorMacro(<<"ReferenceSystemNormalArrayName not specified"); return 1; } vtkDataArray* referenceSystemNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemNormalArrayName); if (!referenceSystemNormalArray) { vtkErrorMacro(<<"ReferenceSystemNormalArray with name specified does not exist"); return 1; } if (!this->ReferenceSystemUpNormalArrayName) { vtkErrorMacro(<<"ReferenceSystemUpNormalArrayName not specified"); return 1; } vtkDataArray* referenceSystemUpNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemUpNormalArrayName); if (!referenceSystemUpNormalArray) { vtkErrorMacro(<<"ReferenceSystemUpNormalArray with name specified does not exist"); return 1; } if (!this->BifurcationVectorsArrayName) { vtkErrorMacro(<<"BifurcationVectorsArrayName not specified"); return 1; } if (!this->InPlaneBifurcationVectorsArrayName) { vtkErrorMacro(<<"InPlaneBifurcationVectorsArrayName not specified"); return 1; } if (!this->OutOfPlaneBifurcationVectorsArrayName) { vtkErrorMacro(<<"OutOfPlaneBifurcationVectorsArrayName not specified"); return 1; } if (!this->BifurcationVectorsOrientationArrayName) { vtkErrorMacro(<<"BifurcationVectorsOrientationArrayName not specified"); return 1; } if (!this->BifurcationGroupIdsArrayName) { vtkErrorMacro(<<"BifurcationGroupIdsArrayName not specified"); return 1; } if (!this->InPlaneBifurcationVectorAnglesArrayName) { vtkErrorMacro(<<"InPlaneBifurcationVectorAnglesArrayName not specified"); return 1; } if (!this->OutOfPlaneBifurcationVectorAnglesArrayName) { vtkErrorMacro(<<"OutOfPlaneBifurcationVectorAnglesArrayName not specified"); return 1; } vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputVerts = vtkCellArray::New(); output->SetPoints(outputPoints); output->SetVerts(outputVerts); vtkDoubleArray* bifurcationVectorsArray = vtkDoubleArray::New(); bifurcationVectorsArray->SetName(this->BifurcationVectorsArrayName); bifurcationVectorsArray->SetNumberOfComponents(3); vtkDoubleArray* inPlaneBifurcationVectorsArray = vtkDoubleArray::New(); inPlaneBifurcationVectorsArray->SetName(this->InPlaneBifurcationVectorsArrayName); inPlaneBifurcationVectorsArray->SetNumberOfComponents(3); vtkDoubleArray* outOfPlaneBifurcationVectorsArray = vtkDoubleArray::New(); outOfPlaneBifurcationVectorsArray->SetName(this->OutOfPlaneBifurcationVectorsArrayName); outOfPlaneBifurcationVectorsArray->SetNumberOfComponents(3); vtkDoubleArray* inPlaneBifurcationVectorAnglesArray = vtkDoubleArray::New(); inPlaneBifurcationVectorAnglesArray->SetName(this->InPlaneBifurcationVectorAnglesArrayName); inPlaneBifurcationVectorAnglesArray->SetNumberOfComponents(1); vtkDoubleArray* outOfPlaneBifurcationVectorAnglesArray = vtkDoubleArray::New(); outOfPlaneBifurcationVectorAnglesArray->SetName(this->OutOfPlaneBifurcationVectorAnglesArrayName); outOfPlaneBifurcationVectorAnglesArray->SetNumberOfComponents(1); vtkIntArray* bifurcationVectorsOrientationArray = vtkIntArray::New(); bifurcationVectorsOrientationArray->SetName(this->BifurcationVectorsOrientationArrayName); bifurcationVectorsOrientationArray->SetNumberOfComponents(1); vtkIntArray* bifurcationVectorsGroupIdsArray = vtkIntArray::New(); bifurcationVectorsGroupIdsArray->SetName(this->GroupIdsArrayName); bifurcationVectorsGroupIdsArray->SetNumberOfComponents(1); vtkIntArray* bifurcationVectorsBifurcationGroupIdsArray = vtkIntArray::New(); bifurcationVectorsBifurcationGroupIdsArray->SetName(this->BifurcationGroupIdsArrayName); bifurcationVectorsBifurcationGroupIdsArray->SetNumberOfComponents(1); output->GetPointData()->AddArray(bifurcationVectorsArray); output->GetPointData()->AddArray(inPlaneBifurcationVectorsArray); output->GetPointData()->AddArray(outOfPlaneBifurcationVectorsArray); output->GetPointData()->AddArray(inPlaneBifurcationVectorAnglesArray); output->GetPointData()->AddArray(outOfPlaneBifurcationVectorAnglesArray); output->GetPointData()->AddArray(bifurcationVectorsOrientationArray); output->GetPointData()->AddArray(bifurcationVectorsGroupIdsArray); output->GetPointData()->AddArray(bifurcationVectorsBifurcationGroupIdsArray); vtkIdList* blankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetBlankedGroupsIdList(input,this->GroupIdsArrayName,this->BlankingArrayName,blankedGroupIds); int i; for (i=0; iGetNumberOfIds(); i++) { vtkIdType bifurcationGroupId = blankedGroupIds->GetId(i); vtkIdList* groupBifurcationVectorsGroupIds = vtkIdList::New(); vtkIntArray* groupBifurcationVectorsOrientation = vtkIntArray::New(); vtkDoubleArray* groupBifurcationVectors = vtkDoubleArray::New(); vtkPoints* groupBifurcationVectorsPoints = vtkPoints::New(); vtkDoubleArray* groupInPlaneBifurcationVectors = vtkDoubleArray::New(); vtkDoubleArray* groupOutOfPlaneBifurcationVectors = vtkDoubleArray::New(); vtkDoubleArray* groupInPlaneBifurcationVectorAngles = vtkDoubleArray::New(); vtkDoubleArray* groupOutOfPlaneBifurcationVectorAngles = vtkDoubleArray::New(); this->ComputeBifurcationVectors(input,bifurcationGroupId,groupBifurcationVectorsGroupIds,groupBifurcationVectorsOrientation,groupBifurcationVectors,groupBifurcationVectorsPoints); this->ComputeBifurcationVectorComponents(bifurcationGroupId,groupBifurcationVectors,groupInPlaneBifurcationVectors,groupOutOfPlaneBifurcationVectors); this->ComputeBifurcationVectorAngles(bifurcationGroupId,groupBifurcationVectors,groupInPlaneBifurcationVectors,groupOutOfPlaneBifurcationVectors,groupInPlaneBifurcationVectorAngles,groupOutOfPlaneBifurcationVectorAngles); int j; for (j=0; jGetNumberOfIds(); j++) { vtkIdType pointId = outputPoints->InsertNextPoint(groupBifurcationVectorsPoints->GetPoint(j)); outputVerts->InsertNextCell(1); outputVerts->InsertCellPoint(pointId); bifurcationVectorsArray->InsertNextTuple(groupBifurcationVectors->GetTuple(j)); inPlaneBifurcationVectorsArray->InsertNextTuple(groupInPlaneBifurcationVectors->GetTuple(j)); outOfPlaneBifurcationVectorsArray->InsertNextTuple(groupOutOfPlaneBifurcationVectors->GetTuple(j)); inPlaneBifurcationVectorAnglesArray->InsertNextTuple(groupInPlaneBifurcationVectorAngles->GetTuple(j)); outOfPlaneBifurcationVectorAnglesArray->InsertNextTuple(groupOutOfPlaneBifurcationVectorAngles->GetTuple(j)); bifurcationVectorsOrientationArray->InsertNextValue(groupBifurcationVectorsOrientation->GetValue(j)); bifurcationVectorsGroupIdsArray->InsertNextValue(groupBifurcationVectorsGroupIds->GetId(j)); bifurcationVectorsBifurcationGroupIdsArray->InsertNextValue(bifurcationGroupId); } groupBifurcationVectorsGroupIds->Delete(); groupBifurcationVectorsOrientation->Delete(); groupBifurcationVectors->Delete(); groupBifurcationVectorsPoints->Delete(); groupInPlaneBifurcationVectors->Delete(); groupOutOfPlaneBifurcationVectors->Delete(); groupInPlaneBifurcationVectorAngles->Delete(); groupOutOfPlaneBifurcationVectorAngles->Delete(); } blankedGroupIds->Delete(); outputPoints->Delete(); outputVerts->Delete(); bifurcationVectorsArray->Delete(); inPlaneBifurcationVectorsArray->Delete(); outOfPlaneBifurcationVectorsArray->Delete(); inPlaneBifurcationVectorAnglesArray->Delete(); outOfPlaneBifurcationVectorAnglesArray->Delete(); bifurcationVectorsOrientationArray->Delete(); bifurcationVectorsGroupIdsArray->Delete(); bifurcationVectorsBifurcationGroupIdsArray->Delete(); return 1; } void vtkvmtkCenterlineBifurcationVectors::ComputeBifurcationVectors(vtkPolyData* input, int bifurcationGroupId, vtkIdList* bifurcationVectorsGroupIds, vtkIntArray* bifurcationVectorsOrientation, vtkDoubleArray* bifurcationVectors, vtkPoints* bifurcationVectorsPoints) { vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); bifurcationVectorsGroupIds->Initialize(); bifurcationVectorsOrientation->Initialize(); vtkIdList* upStreamGroupIds = vtkIdList::New(); vtkIdList* downStreamGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::FindAdjacentCenterlineGroupIds(input,this->GroupIdsArrayName,this->CenterlineIdsArrayName,this->TractIdsArrayName,bifurcationGroupId,upStreamGroupIds,downStreamGroupIds); int numberOfUpStreamGroupIds = upStreamGroupIds->GetNumberOfIds(); int numberOfDownStreamGroupIds = downStreamGroupIds->GetNumberOfIds(); int i; for (i=0; iInsertNextId(upStreamGroupIds->GetId(i)); bifurcationVectorsOrientation->InsertNextValue(VTK_VMTK_UPSTREAM_ORIENTATION); } for (i=0; iInsertNextId(downStreamGroupIds->GetId(i)); bifurcationVectorsOrientation->InsertNextValue(VTK_VMTK_DOWNSTREAM_ORIENTATION); } upStreamGroupIds->Delete(); downStreamGroupIds->Delete(); bifurcationVectors->Initialize(); bifurcationVectors->SetNumberOfComponents(3); int numberOfBifurcationVectors = bifurcationVectorsGroupIds->GetNumberOfIds(); for (i=0; iGetId(i); int bifurcationVectorOrientation = bifurcationVectorsOrientation->GetValue(i); double averageLastPoint[3], averageTouchingPoint[3]; averageLastPoint[0] = averageLastPoint[1] = averageLastPoint[2] = 0.0; averageTouchingPoint[0] = averageTouchingPoint[1] = averageTouchingPoint[2] = 0.0; double lastPointWeightSum = 0.0; double touchingPointWeightSum = 0.0; vtkIdList* groupCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(input,this->GroupIdsArrayName,bifurcationVectorGroupId,groupCellIds); for (int j=0; jGetNumberOfIds(); j++) { vtkIdType cellId = groupCellIds->GetId(j); vtkCell* cell = input->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 (bifurcationVectorOrientation == 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 (bifurcationVectorOrientation == 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::FindTouchingSphereCenter(input,this->RadiusArrayName,cellId,pointSubId,pointPCoord,touchingSubId,touchingPCoord,forward); if (touchingSubId == -1) { touchingSubId = numberOfCellPoints-2; touchingPCoord = 1.0; } //accumulate last point and touching point (weighted with radius^2) averageLastPoint[0] += lastPointRadius * lastPointRadius * lastPoint[0]; averageLastPoint[1] += lastPointRadius * lastPointRadius * lastPoint[1]; averageLastPoint[2] += lastPointRadius * lastPointRadius * lastPoint[2]; lastPointWeightSum += lastPointRadius * lastPointRadius; double touchingPoint[3], touchingPointRadius; vtkvmtkCenterlineUtilities::InterpolatePoint(input,cellId,touchingSubId,touchingPCoord,touchingPoint); vtkvmtkCenterlineUtilities::InterpolateTuple(input,this->RadiusArrayName,cellId,touchingSubId,touchingPCoord,&touchingPointRadius); averageTouchingPoint[0] += touchingPointRadius * touchingPointRadius * touchingPoint[0]; averageTouchingPoint[1] += touchingPointRadius * touchingPointRadius * touchingPoint[1]; averageTouchingPoint[2] += touchingPointRadius * touchingPointRadius * touchingPoint[2]; touchingPointWeightSum += touchingPointRadius * touchingPointRadius; } groupCellIds->Delete(); averageLastPoint[0] /= lastPointWeightSum; averageLastPoint[1] /= lastPointWeightSum; averageLastPoint[2] /= lastPointWeightSum; averageTouchingPoint[0] /= touchingPointWeightSum; averageTouchingPoint[1] /= touchingPointWeightSum; averageTouchingPoint[2] /= touchingPointWeightSum; //build and store bifurcationVector for this group double bifurcationVector[3], bifurcationVectorPoint[3]; if (bifurcationVectorOrientation == VTK_VMTK_UPSTREAM_ORIENTATION) { bifurcationVector[0] = averageLastPoint[0] - averageTouchingPoint[0]; bifurcationVector[1] = averageLastPoint[1] - averageTouchingPoint[1]; bifurcationVector[2] = averageLastPoint[2] - averageTouchingPoint[2]; bifurcationVectorPoint[0] = averageTouchingPoint[0]; bifurcationVectorPoint[1] = averageTouchingPoint[1]; bifurcationVectorPoint[2] = averageTouchingPoint[2]; } else if (bifurcationVectorOrientation == VTK_VMTK_DOWNSTREAM_ORIENTATION) { bifurcationVector[0] = averageTouchingPoint[0] - averageLastPoint[0]; bifurcationVector[1] = averageTouchingPoint[1] - averageLastPoint[1]; bifurcationVector[2] = averageTouchingPoint[2] - averageLastPoint[2]; bifurcationVectorPoint[0] = averageLastPoint[0]; bifurcationVectorPoint[1] = averageLastPoint[1]; bifurcationVectorPoint[2] = averageLastPoint[2]; } else { vtkErrorMacro("Error: invalid BifurcationVectorOrientation"); return; } if (this->NormalizeBifurcationVectors) { vtkMath::Normalize(bifurcationVector); } bifurcationVectors->InsertNextTuple(bifurcationVector); bifurcationVectorsPoints->InsertNextPoint(bifurcationVectorPoint); } } void vtkvmtkCenterlineBifurcationVectors::ComputeBifurcationVectorComponents(int bifurcationGroupId, vtkDoubleArray* bifurcationVectors, vtkDoubleArray* inPlaneBifurcationVectors, vtkDoubleArray* outOfPlaneBifurcationVectors) { // get the reference system, get the normal, project the angles. vtkDataArray* referenceSystemNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemNormalArrayName); vtkDataArray* referenceSystemUpNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemUpNormalArrayName); inPlaneBifurcationVectors->Initialize(); inPlaneBifurcationVectors->SetNumberOfComponents(3); outOfPlaneBifurcationVectors->Initialize(); outOfPlaneBifurcationVectors->SetNumberOfComponents(3); int referenceSystemPointId = vtkvmtkReferenceSystemUtilities::GetReferenceSystemPointId(this->ReferenceSystems,this->ReferenceSystemGroupIdsArrayName,bifurcationGroupId); double bifurcationPlaneNormal[3]; referenceSystemNormalArray->GetTuple(referenceSystemPointId,bifurcationPlaneNormal); double bifurcationUpNormal[3]; referenceSystemUpNormalArray->GetTuple(referenceSystemPointId,bifurcationUpNormal); double bifurcationVector[3], inPlaneBifurcationVector[3], outOfPlaneBifurcationVector[3]; int numberOfBifurcationVectors = bifurcationVectors->GetNumberOfTuples(); int j; for (j=0; jGetTuple(j,bifurcationVector); double dot = vtkMath::Dot(bifurcationVector,bifurcationPlaneNormal); outOfPlaneBifurcationVector[0] = dot * bifurcationPlaneNormal[0]; outOfPlaneBifurcationVector[1] = dot * bifurcationPlaneNormal[1]; outOfPlaneBifurcationVector[2] = dot * bifurcationPlaneNormal[2]; inPlaneBifurcationVector[0] = bifurcationVector[0] - outOfPlaneBifurcationVector[0]; inPlaneBifurcationVector[1] = bifurcationVector[1] - outOfPlaneBifurcationVector[1]; inPlaneBifurcationVector[2] = bifurcationVector[2] - outOfPlaneBifurcationVector[2]; inPlaneBifurcationVectors->InsertNextTuple(inPlaneBifurcationVector); outOfPlaneBifurcationVectors->InsertNextTuple(outOfPlaneBifurcationVector); } } void vtkvmtkCenterlineBifurcationVectors::ComputeBifurcationVectorAngles(int bifurcationGroupId, vtkDoubleArray* bifurcationVectors, vtkDoubleArray* inPlaneBifurcationVectors, vtkDoubleArray* outOfPlaneBifurcationVectors, vtkDoubleArray* inPlaneBifurcationVectorAngles, vtkDoubleArray* outOfPlaneBifurcationVectorAngles) { vtkDataArray* referenceSystemNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemNormalArrayName); vtkDataArray* referenceSystemUpNormalArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemUpNormalArrayName); int referenceSystemPointId = vtkvmtkReferenceSystemUtilities::GetReferenceSystemPointId(this->ReferenceSystems,this->ReferenceSystemGroupIdsArrayName,bifurcationGroupId); double bifurcationPlaneNormal[3], bifurcationUpNormal[3]; referenceSystemNormalArray->GetTuple(referenceSystemPointId,bifurcationPlaneNormal); referenceSystemUpNormalArray->GetTuple(referenceSystemPointId,bifurcationUpNormal); int numberOfBifurcationVectors = bifurcationVectors->GetNumberOfTuples(); int i; for (i=0; iGetTuple(i,bifurcationVector); inPlaneBifurcationVectors->GetTuple(i,inPlaneBifurcationVector); outOfPlaneBifurcationVectors->GetTuple(i,outOfPlaneBifurcationVector); vtkMath::Normalize(bifurcationVector); vtkMath::Normalize(inPlaneBifurcationVector); double inPlaneBifurcationVectorAngle = vtkvmtkMath::AngleBetweenNormals(inPlaneBifurcationVector,bifurcationUpNormal); double cross[3]; vtkMath::Cross(inPlaneBifurcationVector,bifurcationUpNormal,cross); if (vtkMath::Dot(cross,bifurcationPlaneNormal) < 0.0) { inPlaneBifurcationVectorAngle *= -1.0; } double outOfPlaneBifurcationVectorAngle = vtkMath::Pi()/2.0 - vtkvmtkMath::AngleBetweenNormals(bifurcationVector,bifurcationPlaneNormal); inPlaneBifurcationVectorAngles->InsertNextValue(inPlaneBifurcationVectorAngle); outOfPlaneBifurcationVectorAngles->InsertNextValue(outOfPlaneBifurcationVectorAngle); } } void vtkvmtkCenterlineBifurcationVectors::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataPatchingFilter.cxx0000664000175000017500000006107111757446472025671 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataPatchingFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/10 14:30:17 $ Version: $Revision: 1.11 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataPatchingFilter.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkTriangle.h" #include "vtkTriangleFilter.h" #include "vtkCellArray.h" #include "vtkCleanPolyData.h" #include "vtkClipPolyData.h" #include "vtkAppendPolyData.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkPolyDataConnectivityFilter.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkPolyDataBranchUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataPatchingFilter, "$Revision: 1.11 $"); vtkStandardNewMacro(vtkvmtkPolyDataPatchingFilter); vtkvmtkPolyDataPatchingFilter::vtkvmtkPolyDataPatchingFilter() { this->LongitudinalMappingArrayName = NULL; this->CircularMappingArrayName = NULL; this->GroupIdsArrayName = NULL; this->LongitudinalPatchNumberArrayName = NULL; this->CircularPatchNumberArrayName = NULL; this->PatchAreaArrayName = NULL; this->PatchSize[0] = this->PatchSize[1] = 0.0; this->PatchOffsets[0] = this->PatchOffsets[1] = 0.0; this->LongitudinalPatchBounds[0] = this->LongitudinalPatchBounds[1] = 0.0; this->CircularPatchBounds[0] = this->CircularPatchBounds[1] = 0.0; this->PatchedData = NULL; this->CircularPatching = 1; this->UseConnectivity = 1; } vtkvmtkPolyDataPatchingFilter::~vtkvmtkPolyDataPatchingFilter() { if (this->LongitudinalMappingArrayName) { delete[] this->LongitudinalMappingArrayName; this->LongitudinalMappingArrayName = NULL; } if (this->CircularMappingArrayName) { delete[] this->CircularMappingArrayName; this->CircularMappingArrayName = NULL; } if (this->LongitudinalPatchNumberArrayName) { delete[] this->LongitudinalPatchNumberArrayName; this->LongitudinalPatchNumberArrayName = NULL; } if (this->CircularPatchNumberArrayName) { delete[] this->CircularPatchNumberArrayName; this->CircularPatchNumberArrayName = NULL; } if (this->PatchAreaArrayName) { delete[] this->PatchAreaArrayName; this->PatchAreaArrayName = NULL; } if (this->PatchedData) { this->PatchedData->Delete(); this->PatchedData = NULL; } } int vtkvmtkPolyDataPatchingFilter::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->LongitudinalPatchNumberArrayName) { vtkErrorMacro(<<"LongitudinalPatchNumberArrayName not set."); return 1; } if (!this->CircularPatchNumberArrayName) { vtkErrorMacro(<<"CircularPatchNumberArrayName not set."); return 1; } if (!this->PatchAreaArrayName) { vtkErrorMacro(<<"PatchAreaArrayName not set."); return 1; } if (!this->LongitudinalMappingArrayName) { vtkErrorMacro(<<"LongitudinalMappingArrayName not set."); return 1; } vtkDataArray* longitudinalMappingArray = input->GetPointData()->GetArray(this->LongitudinalMappingArrayName); if (!longitudinalMappingArray) { vtkErrorMacro(<<"LongitudinalMappingArray with name specified does not exist."); return 1; } vtkDataArray* circularMappingArray = NULL; if (this->CircularPatching) { if (!this->CircularMappingArrayName) { vtkErrorMacro(<<"CircularMappingArrayName not set."); return 1; } circularMappingArray = input->GetPointData()->GetArray(this->CircularMappingArrayName); if (!circularMappingArray) { vtkErrorMacro(<<"CircularMappingArray with name specified does not exist."); return 1; } } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not set."); return 1; } vtkDataArray* groupIdsArray = input->GetPointData()->GetArray(this->GroupIdsArrayName); if (!groupIdsArray) { vtkErrorMacro(<<"GroupIdsArray with name specified does not exist."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); double circumferentialActualPatchSize = this->PatchSize[1] * 2.0 * vtkMath::Pi(); char shiftedCircularMapping90ArrayName[] = "ShiftedCircularMapping90"; char shiftedCircularMapping180ArrayName[] = "ShiftedCircularMapping180"; char shiftedCircularMapping270ArrayName[] = "ShiftedCircularMapping270"; vtkDoubleArray* shiftedCircularMapping90Array = vtkDoubleArray::New(); shiftedCircularMapping90Array->SetName(shiftedCircularMapping90ArrayName); shiftedCircularMapping90Array->SetNumberOfComponents(1); shiftedCircularMapping90Array->SetNumberOfTuples(numberOfInputPoints); vtkDoubleArray* shiftedCircularMapping180Array = vtkDoubleArray::New(); shiftedCircularMapping180Array->SetName(shiftedCircularMapping180ArrayName); shiftedCircularMapping180Array->SetNumberOfComponents(1); shiftedCircularMapping180Array->SetNumberOfTuples(numberOfInputPoints); vtkDoubleArray* shiftedCircularMapping270Array = vtkDoubleArray::New(); shiftedCircularMapping270Array->SetName(shiftedCircularMapping270ArrayName); shiftedCircularMapping270Array->SetNumberOfComponents(1); shiftedCircularMapping270Array->SetNumberOfTuples(numberOfInputPoints); int i; if (this->CircularPatching) { for (i=0; iGetComponent(i,0); double shiftedValue = value + 0.5 * vtkMath::Pi(); if (shiftedValue > vtkMath::Pi()) { shiftedValue -= 2.0 * vtkMath::Pi(); } shiftedCircularMapping90Array->SetValue(i,shiftedValue); shiftedValue = value + vtkMath::Pi(); if (shiftedValue > vtkMath::Pi()) { shiftedValue -= 2.0 * vtkMath::Pi(); } shiftedCircularMapping180Array->SetValue(i,shiftedValue); shiftedValue = value + 1.5 * vtkMath::Pi(); if (shiftedValue > vtkMath::Pi()) { shiftedValue -= 2.0 * vtkMath::Pi(); } shiftedCircularMapping270Array->SetValue(i,shiftedValue); } } else { shiftedCircularMapping90Array->FillComponent(0,0.0); shiftedCircularMapping180Array->FillComponent(0,0.0); shiftedCircularMapping270Array->FillComponent(0,0.0); } input->GetPointData()->AddArray(shiftedCircularMapping90Array); input->GetPointData()->AddArray(shiftedCircularMapping180Array); input->GetPointData()->AddArray(shiftedCircularMapping270Array); if (this->PatchedData) { this->PatchedData->Delete(); this->PatchedData = NULL; } this->PatchedData = vtkImageData::New(); vtkPointData* patchedDataPointData = this->PatchedData->GetPointData(); patchedDataPointData->CopyAllocate(input->GetPointData(),0); vtkIntArray* patchedDataLongitudinalPatchNumberArray = vtkIntArray::New(); patchedDataLongitudinalPatchNumberArray->SetName(this->LongitudinalPatchNumberArrayName); patchedDataLongitudinalPatchNumberArray->SetNumberOfComponents(1); vtkIntArray* patchedDataCircularPatchNumberArray = vtkIntArray::New(); patchedDataCircularPatchNumberArray->SetName(this->CircularPatchNumberArrayName); patchedDataCircularPatchNumberArray->SetNumberOfComponents(1); vtkDoubleArray* patchedDataPatchAreaArray = vtkDoubleArray::New(); patchedDataPatchAreaArray->SetName(this->PatchAreaArrayName); patchedDataPatchAreaArray->SetNumberOfComponents(1); vtkAppendPolyData* patchAppendFilter = vtkAppendPolyData::New(); if (this->CircularPatchBounds[0] == 0.0 && this->CircularPatchBounds[1] == 0.0) { this->CircularPatchBounds[0] = - vtkMath::Pi(); this->CircularPatchBounds[1] = vtkMath::Pi(); } int circularPatchStartIndex = 0; int circularPatchEndIndex = 0; if (this->CircularPatching) { circularPatchStartIndex = vtkMath::Floor((this->CircularPatchBounds[0] - this->PatchOffsets[1]) / circumferentialActualPatchSize); if (circularPatchStartIndex*circumferentialActualPatchSize - this->PatchOffsets[1] < - vtkMath::Pi()) { circularPatchStartIndex += 1; } circularPatchEndIndex = vtkMath::Floor((this->CircularPatchBounds[1] - this->PatchOffsets[1] - 1E-3 * circumferentialActualPatchSize) / circumferentialActualPatchSize); } int numberOfPreviousPatchDataLines = 0; vtkIdList* groupIds = vtkIdList::New(); vtkvmtkPolyDataBranchUtilities::GetGroupsIdList(input,this->GroupIdsArrayName,groupIds); for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = groupIds->GetId(i); vtkPolyData* cylinder = vtkPolyData::New(); vtkvmtkPolyDataBranchUtilities::ExtractGroup(input,this->GroupIdsArrayName,groupId,true,cylinder); longitudinalMappingArray = cylinder->GetPointData()->GetArray(this->LongitudinalMappingArrayName); circularMappingArray = cylinder->GetPointData()->GetArray(this->CircularMappingArrayName); cylinder->GetPointData()->SetActiveScalars(this->LongitudinalMappingArrayName); vtkClipPolyData* longitudinalClipper0 = vtkClipPolyData::New(); longitudinalClipper0->SetInput(cylinder); longitudinalClipper0->GenerateClipScalarsOff(); longitudinalClipper0->InsideOutOff(); vtkClipPolyData* longitudinalClipper1 = vtkClipPolyData::New(); longitudinalClipper1->SetInput(longitudinalClipper0->GetOutput()); longitudinalClipper1->GenerateClipScalarsOff(); longitudinalClipper1->InsideOutOn(); vtkClipPolyData* circularClipper0 = vtkClipPolyData::New(); circularClipper0->SetInput(longitudinalClipper1->GetOutput()); circularClipper0->GenerateClipScalarsOff(); circularClipper0->InsideOutOff(); vtkClipPolyData* circularClipper1 = vtkClipPolyData::New(); circularClipper1->SetInput(circularClipper0->GetOutput()); circularClipper1->GenerateClipScalarsOff(); circularClipper1->InsideOutOn(); vtkPolyDataConnectivityFilter* patchConnectivityFilter = vtkPolyDataConnectivityFilter::New(); patchConnectivityFilter->SetInput(circularClipper1->GetOutput()); patchConnectivityFilter->SetExtractionModeToLargestRegion(); double longitudinalMappingRange[2]; longitudinalMappingArray->GetRange(longitudinalMappingRange,0); double longitudinalCylinderPatchBounds[2]; if (this->LongitudinalPatchBounds[0] == 0.0 && this->LongitudinalPatchBounds[1] == 0.0) { longitudinalCylinderPatchBounds[0] = longitudinalMappingRange[0]; longitudinalCylinderPatchBounds[1] = longitudinalMappingRange[1]; } else { longitudinalCylinderPatchBounds[0] = this->LongitudinalPatchBounds[0]; longitudinalCylinderPatchBounds[1] = this->LongitudinalPatchBounds[1]; } int longitudinalPatchStartIndex = vtkMath::Floor((longitudinalCylinderPatchBounds[0] - this->PatchOffsets[0]) / this->PatchSize[0]); int longitudinalPatchEndIndex = vtkMath::Floor((longitudinalCylinderPatchBounds[1] - this->PatchOffsets[0] - 1E-3 * this->PatchSize[0]) / this->PatchSize[0]); int j, k; for (j=longitudinalPatchStartIndex; j<=longitudinalPatchEndIndex; j++) { double longitudinalPatchStart = this->PatchOffsets[0] + j * this->PatchSize[0]; double longitudinalPatchEnd = this->PatchOffsets[0] + (j+1) * this->PatchSize[0]; longitudinalClipper0->SetValue(longitudinalPatchStart); longitudinalClipper1->SetValue(longitudinalPatchEnd); longitudinalClipper1->Update(); if (longitudinalClipper1->GetOutput()->GetNumberOfPoints() == 0) { continue; } for (k=circularPatchStartIndex; k<=circularPatchEndIndex; k++) { int patchId = k - circularPatchStartIndex + (j - longitudinalPatchStartIndex) * (circularPatchEndIndex-circularPatchStartIndex+1) + numberOfPreviousPatchDataLines * (circularPatchEndIndex-circularPatchStartIndex+1); double circularPatchCenter = 0.0; double shiftedCircularPatchCenter = 0.0; char* patchShiftedCircularMappingArrayName = NULL; if (this->CircularPatching) { double circularPatchStart = this->PatchOffsets[1] + k * circumferentialActualPatchSize; double circularPatchEnd = this->PatchOffsets[1] + (k+1) * circumferentialActualPatchSize; double pi = vtkMath::Pi(); if (circularPatchStart < -pi) { circularPatchStart += 2.0 * pi; circularPatchEnd += 2.0 * pi; } circularPatchCenter = 0.5 * (circularPatchStart + circularPatchEnd); // if (circularPatchStart < pi && circularPatchEnd > pi) if (circularPatchCenter <= - 0.75 * pi || circularPatchCenter >= 0.75 * pi) { patchShiftedCircularMappingArrayName = shiftedCircularMapping180ArrayName; if (circularPatchCenter <= - 0.75 * pi) { circularPatchStart += pi; circularPatchEnd += pi; } else if (circularPatchCenter >= 0.75 * pi) { circularPatchStart -= pi; circularPatchEnd -= pi; } } // else if (circularPatchStart < 0.5 * pi && circularPatchEnd > 0.5 * pi) else if (circularPatchCenter >= 0.25 * pi && circularPatchCenter < 0.75 * pi) { patchShiftedCircularMappingArrayName = shiftedCircularMapping270ArrayName; circularPatchStart -= 0.5 * pi; circularPatchEnd -= 0.5 * pi; } // else if (circularPatchStart < -0.5 * pi && circularPatchEnd > -0.5 * pi) else if (circularPatchCenter > -0.75 * pi && circularPatchCenter <= -0.25 * pi) { patchShiftedCircularMappingArrayName = shiftedCircularMapping90ArrayName; circularPatchStart += 0.5 * pi; circularPatchEnd += 0.5 * pi; } else { patchShiftedCircularMappingArrayName = this->CircularMappingArrayName; } longitudinalClipper1->GetOutput()->GetPointData()->SetActiveScalars(patchShiftedCircularMappingArrayName); shiftedCircularPatchCenter = 0.5 * (circularPatchStart + circularPatchEnd); circularClipper0->Modified(); circularClipper0->SetValue(circularPatchStart); circularClipper1->SetValue(circularPatchEnd); circularClipper1->Update(); if (circularClipper1->GetOutput()->GetNumberOfPoints() == 0) { continue; } } vtkTriangleFilter* patchTriangleFilter = vtkTriangleFilter::New(); if (this->UseConnectivity) { if (this->CircularPatching) { patchConnectivityFilter->SetInput(circularClipper1->GetOutput()); } else { patchConnectivityFilter->SetInput(longitudinalClipper1->GetOutput()); } patchConnectivityFilter->Update(); patchTriangleFilter->SetInput(patchConnectivityFilter->GetOutput()); } else { if (this->CircularPatching) { patchTriangleFilter->SetInput(circularClipper1->GetOutput()); } else { patchTriangleFilter->SetInput(longitudinalClipper1->GetOutput()); } } patchTriangleFilter->Update(); vtkPolyData* patch = vtkPolyData::New(); patch->DeepCopy(patchTriangleFilter->GetOutput()); patch->BuildCells(); int patchNumberOfCells = patch->GetNumberOfCells(); if (this->CircularPatching) { vtkDataArray* patchCircularMappingArray = patch->GetPointData()->GetArray(this->CircularMappingArrayName); vtkDataArray* patchShiftedCircularMappingArray = patch->GetPointData()->GetArray(patchShiftedCircularMappingArrayName); double angularOffset = circularPatchCenter - shiftedCircularPatchCenter; vtkIdType patchNumberOfPoints = patch->GetNumberOfPoints(); vtkIdType pointId; for (pointId=0; pointIdGetTuple1(pointId); circularMappingValue += angularOffset; patchCircularMappingArray->SetTuple1(pointId,circularMappingValue); } } vtkIntArray* longitudinalPatchNumberArray = vtkIntArray::New(); longitudinalPatchNumberArray->SetName(this->LongitudinalPatchNumberArrayName); longitudinalPatchNumberArray->SetNumberOfComponents(1); longitudinalPatchNumberArray->SetNumberOfTuples(patchNumberOfCells); vtkIntArray* circularPatchNumberArray = vtkIntArray::New(); circularPatchNumberArray->SetName(this->CircularPatchNumberArrayName); circularPatchNumberArray->SetNumberOfComponents(1); circularPatchNumberArray->SetNumberOfTuples(patchNumberOfCells); vtkDoubleArray* patchAreaArray = vtkDoubleArray::New(); patchAreaArray->SetName(this->PatchAreaArrayName); patchAreaArray->SetNumberOfComponents(1); patchAreaArray->SetNumberOfTuples(patchNumberOfCells); double patchArea = 0.0; vtkPointData* patchPointData = patch->GetPointData(); vtkCellData* patchCellData = vtkCellData::New(); patchCellData->CopyAllocate(patchPointData,patchNumberOfCells); vtkCellData* patchedPatchCellData = patch->GetCellData(); patchedPatchCellData->CopyAllocate(patchCellData,patchNumberOfCells); int cellId; for (cellId=0; cellId < patchNumberOfCells; cellId++) { vtkTriangle* triangle = vtkTriangle::SafeDownCast(patch->GetCell(cellId)); if (!triangle) { continue; } double point0[3], point1[3], point2[3]; triangle->GetPoints()->GetPoint(0,point0); triangle->GetPoints()->GetPoint(1,point1); triangle->GetPoints()->GetPoint(2,point2); patchArea += vtkTriangle::TriangleArea(point0,point1,point2); double weights[3]; weights[1] = 1.0/3.0; weights[2] = 1.0/3.0; weights[0] = (1.0 - weights[1] - weights[2]); patchCellData->InterpolatePoint(patchPointData,cellId,triangle->GetPointIds(),weights); } for (cellId = 0; cellId < patchNumberOfCells; cellId++) { longitudinalPatchNumberArray->SetValue(cellId,j); circularPatchNumberArray->SetValue(cellId,k); patchAreaArray->SetValue(cellId,patchArea); } patchedDataLongitudinalPatchNumberArray->InsertValue(patchId,j); patchedDataCircularPatchNumberArray->InsertValue(patchId,k); patchedDataPatchAreaArray->InsertValue(patchId,patchArea); int numberOfArrays = patchCellData->GetNumberOfArrays(); int arrayId; for (arrayId = 0; arrayIdGetArray(arrayId); vtkDataArray* patchedArray = patchedPatchCellData->GetArray(patchArray->GetName()); vtkDataArray* patchedDataArray = patchedDataPointData->GetArray(arrayId); if (!patchedArray) { continue; } int dataType = patchArray->GetDataType(); if (dataType != VTK_FLOAT && dataType != VTK_DOUBLE) { for (cellId = 0; cellId < patchNumberOfCells; cellId++) { patchedArray->InsertTuple(cellId,patchArray->GetTuple(cellId)); } if (patchNumberOfCells > 0) { patchedDataArray->InsertTuple(patchId,patchArray->GetTuple(0)); } continue; } double* integralTuple = new double[patchArray->GetNumberOfComponents()]; int componentId; for (componentId = 0; componentId < patchArray->GetNumberOfComponents(); componentId++) { integralTuple[componentId] = 0.0; } for (cellId = 0; cellId < patchNumberOfCells; cellId++) { vtkTriangle* triangle = vtkTriangle::SafeDownCast(patch->GetCell(cellId)); if (!triangle) { continue; } double point0[3], point1[3], point2[3]; triangle->GetPoints()->GetPoint(0,point0); triangle->GetPoints()->GetPoint(1,point1); triangle->GetPoints()->GetPoint(2,point2); double area = vtkTriangle::TriangleArea(point0,point1,point2); for (componentId = 0; componentId < patchArray->GetNumberOfComponents(); componentId++) { integralTuple[componentId] += area * patchArray->GetComponent(cellId,componentId); } } for (componentId = 0; componentId < patchArray->GetNumberOfComponents(); componentId++) { integralTuple[componentId] /= patchArea; } for (cellId = 0; cellId < patchNumberOfCells; cellId++) { patchedArray->InsertTuple(cellId,integralTuple); } patchedDataArray->InsertTuple(patchId,integralTuple); delete[] integralTuple; } patch->GetCellData()->AddArray(longitudinalPatchNumberArray); patch->GetCellData()->AddArray(circularPatchNumberArray); patch->GetCellData()->AddArray(patchAreaArray); patchAppendFilter->AddInput(patch); patch->Delete(); patchTriangleFilter->Delete(); patchCellData->Delete(); longitudinalPatchNumberArray->Delete(); circularPatchNumberArray->Delete(); patchAreaArray->Delete(); } } cylinder->Delete(); longitudinalClipper0->Delete(); longitudinalClipper1->Delete(); circularClipper0->Delete(); circularClipper1->Delete(); patchConnectivityFilter->Delete(); numberOfPreviousPatchDataLines += longitudinalPatchEndIndex - longitudinalPatchStartIndex + 1; } groupIds->Delete(); this->PatchedData->SetOrigin(0.0,0.0,0.0); this->PatchedData->SetSpacing(circumferentialActualPatchSize,this->PatchSize[0],1.0); this->PatchedData->SetWholeExtent(0,numberOfPreviousPatchDataLines-1,0,circularPatchEndIndex-circularPatchStartIndex,0,0); this->PatchedData->SetExtent(0,circularPatchEndIndex-circularPatchStartIndex,0,numberOfPreviousPatchDataLines-1,0,0); this->PatchedData->GetPointData()->AddArray(patchedDataLongitudinalPatchNumberArray); this->PatchedData->GetPointData()->AddArray(patchedDataCircularPatchNumberArray); this->PatchedData->GetPointData()->AddArray(patchedDataPatchAreaArray); this->PatchedData->GetPointData()->RemoveArray(shiftedCircularMapping90ArrayName); this->PatchedData->GetPointData()->RemoveArray(shiftedCircularMapping180ArrayName); this->PatchedData->GetPointData()->RemoveArray(shiftedCircularMapping270ArrayName); patchAppendFilter->Update(); output->DeepCopy(patchAppendFilter->GetOutput()); output->GetPointData()->RemoveArray(shiftedCircularMapping90ArrayName); output->GetPointData()->RemoveArray(shiftedCircularMapping180ArrayName); output->GetPointData()->RemoveArray(shiftedCircularMapping270ArrayName); output->GetCellData()->RemoveArray(shiftedCircularMapping90ArrayName); output->GetCellData()->RemoveArray(shiftedCircularMapping180ArrayName); output->GetCellData()->RemoveArray(shiftedCircularMapping270ArrayName); input->GetPointData()->RemoveArray(shiftedCircularMapping90ArrayName); input->GetPointData()->RemoveArray(shiftedCircularMapping180ArrayName); input->GetPointData()->RemoveArray(shiftedCircularMapping270ArrayName); patchedDataLongitudinalPatchNumberArray->Delete(); patchedDataCircularPatchNumberArray->Delete(); patchedDataPatchAreaArray->Delete(); patchAppendFilter->Delete(); shiftedCircularMapping90Array->Delete(); shiftedCircularMapping180Array->Delete(); shiftedCircularMapping270Array->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSmoothing.cxx0000664000175000017500000000701311757446472025304 0ustar lucaluca/*========================================================================= 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) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkCenterlineSmoothing, "$Revision: 1.1 $"); 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; iGetNumberOfCells(); 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; jGetPointId(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; iGetPoint(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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineUtilities.cxx0000664000175000017500000003263111757446472025314 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineUtilities.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkCenterlineUtilities, "$Revision: 1.5 $"); 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(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(groupIdsArray->GetComponent(i,0)); if (blankingArray) { vtkIdType current_blanked = static_cast(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(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(groupIdsArray->GetComponent(i,0)); if (current_groupId != groupId) { continue; } int currentNumberOfGroupCellIds = groupCellIds->GetNumberOfIds(); bool duplicate = false; int j; for (j=0; jGetCell(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(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(centerlineIdsArray->GetComponent(i,0)); if (currentCenterlineId != centerlineId) { continue; } centerlineCellIds->InsertNextId(i); vtkIdType currectTractId = static_cast(tractIdsArray->GetComponent(i,0)); centerlineTractIds->InsertNextId(currectTractId); } int numberOfCenterlineCellIds = centerlineCellIds->GetNumberOfIds(); bool done = false; while (!done) { done = true; for (i=0; iGetId(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(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(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(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(centerlineIdsArray->GetComponent(i,0)); vtkIdType branchCenterlineTractId = static_cast(centerlineTractIdsArray->GetComponent(i,0)); int j; for (j=0; j(centerlineGroupIdsArray->GetComponent(j,0)); vtkIdType currentBranchCenterlineId = static_cast(centerlineIdsArray->GetComponent(j,0)); vtkIdType currentBranchCenterlineTractId = static_cast(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; iInitialize(); int numberOfCells = centerlines->GetNumberOfCells(); int i, j, k; for (i=0; iGetCell(i); int numberOfCenterlinePoints = centerline->GetNumberOfPoints(); int previousMergeStatus = -1; int mergeStatus = -1; for (j=0; jGetPoints()->GetPoint(j,point); for (k=i+1; kGetCell(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; } } } } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataFlowExtensionsFilter.cxx0000664000175000017500000004674011757446472027131 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFlowExtensionsFilter.cxx,v $ Language: C++ Date: $Date: 2006/07/07 10:46:19 $ Version: $Revision: 1.12 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataFlowExtensionsFilter, "$Revision: 1.12 $"); 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(); boundaryExtractor->SetInput(input); 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; iGetNumberOfCells(); 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; jInsertNextId(static_cast(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; jGetNumberOfPoints()-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; jGetPoints()->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; jInsertNextPoint(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; jGetPoint(j,firstBoundaryPoint); double distance = 1E20; double currentPoint[3]; for (int j2=0; j2GetPoint(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; lInitialize(); for (j=0; jGetPoint(j,extensionPoint); } else { targetStaggeredBoundaryPoints->GetPoint(j,extensionPoint); } for (k=0; k<3; k++) { extensionPoint[k] += (l+1) * targetDistanceBetweenPoints * flowExtensionNormal[k]; } if (lInterpolationMode == 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; jGetPoint(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; jGetId(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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkUnstructuredGridCenterlineGroupsClipper.cxx0000664000175000017500000002542111757446472031374 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridCenterlineGroupsClipper.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.9 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridCenterlineGroupsClipper, "$Revision: 1.9 $"); 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; iGetNumberOfTuples(); i++) { if (blankingArray->GetValue(i) == 1) { continue; } centerlineGroupIds->InsertUniqueId(static_cast(vtkMath::Round(centerlineGroupIdsArray->GetComponent(i,0)))); } } else { centerlineGroupIds->DeepCopy(this->CenterlineGroupIds); } for (i=0; iGetNumberOfIds(); i++) { groupId = centerlineGroupIds->GetId(i); groupTubesGroupIds->Initialize(); nonGroupTubesGroupIds->Initialize(); for (int j=0; jCenterlines->GetNumberOfCells(); j++) { if (blankingArray->GetValue(j) == 1) { continue; } if (static_cast(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; kGetPoint(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(); clipper->SetInput(clippingInput); 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()); appendClippedOutput->AddInput(clippedOutputBranch); clippedOutputBranch->Delete(); } groupIdsArray = vtkIntArray::New(); groupIdsArray->SetName(this->GroupIdsArrayName); groupIdsArray->SetNumberOfTuples(clippedBranch->GetNumberOfPoints()); groupIdsArray->FillComponent(0,groupId); clippedBranch->GetPointData()->AddArray(groupIdsArray); appendBranches->AddInput(clippedBranch); 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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkSteepestDescentLineTracer.cxx0000664000175000017500000003051311757446472026400 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSteepestDescentLineTracer.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSteepestDescentLineTracer.h" #include "vtkFloatArray.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellArray.h" #include "vtkLine.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkSteepestDescentLineTracer, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkSteepestDescentLineTracer); vtkvmtkSteepestDescentLineTracer::vtkvmtkSteepestDescentLineTracer() { this->Seeds = NULL; this->Targets = NULL; this->StopOnTargets = 0; this->DataArrayName = NULL; this->EdgeArrayName = NULL; this->EdgePCoordArrayName = NULL; this->MergePaths = 0; this->MergeTolerance = VTK_VMTK_DOUBLE_TOL; this->LineDataArray = NULL; this->HitTargets = vtkIdList::New(); } vtkvmtkSteepestDescentLineTracer::~vtkvmtkSteepestDescentLineTracer() { this->HitTargets->Delete(); if (this->Seeds) { this->Seeds->Delete(); this->Seeds = NULL; } if (this->Targets) { this->Targets->Delete(); this->Targets = NULL; } if (this->EdgePCoordArrayName) { delete [] this->EdgePCoordArrayName; this->EdgePCoordArrayName = NULL; } if (this->EdgeArrayName) { delete [] this->EdgeArrayName; this->EdgeArrayName = NULL; } if (this->DescentArrayName) { delete[] this->DescentArrayName; this->DescentArrayName = NULL; } if (this->DataArrayName) { delete[] this->DataArrayName; this->DataArrayName = NULL; } } void vtkvmtkSteepestDescentLineTracer::Backtrace(vtkPolyData* input, vtkIdType seedId) { bool done; double startingPoint[3], endingPoint[3], currentPoint[3], currentScalar; double currentS; double currentRadius; vtkIdType currentEdge[2], steepestDescentEdge[2], previousEdge[2], previousEdge2[2]; double steepestDescentS, steepestDescent; double previousS, previousS2; double previousPoint[3]; double directionFactor; vtkIdList* neighborCells; vtkIdType pointId, j, targetId; vtkIdList* lineIds; vtkPoints* newPoints; vtkDataArray* newScalars; vtkCellArray* newLines; newPoints = this->GetOutput()->GetPoints(); newScalars = this->GetOutput()->GetPointData()->GetArray(this->DataArrayName); newLines = this->GetOutput()->GetLines(); neighborCells = vtkIdList::New(); lineIds = vtkIdList::New(); directionFactor = 0.0; if (this->Direction==VTK_VMTK_DOWNWARD) { directionFactor = 1.0; } else if (this->Direction==VTK_VMTK_UPWARD) { directionFactor = - 1.0; } done = false; input->GetPoint(seedId,startingPoint); currentPoint[0] = startingPoint[0]; currentPoint[1] = startingPoint[1]; currentPoint[2] = startingPoint[2]; pointId = newPoints->InsertNextPoint(startingPoint); currentScalar = this->DescentArray->GetTuple1(seedId); currentRadius = this->LineDataArray->GetTuple1(seedId); lineIds->InsertNextId(pointId); currentEdge[0] = seedId; currentEdge[1] = seedId; currentS = 0.0; previousS = 0.0; previousS2 = 0.0; newScalars->InsertComponent(pointId,0,currentRadius); this->Edges->InsertComponent(pointId,0,currentEdge[0]); this->Edges->InsertComponent(pointId,1,currentEdge[1]); this->EdgeParCoords->InsertValue(pointId,currentS); previousEdge[0] = currentEdge[0]; previousEdge[1] = currentEdge[1]; while (!done) { if ((this->StopOnTargets) && ((this->Targets->IsId(currentEdge[0]) != -1) || (this->Targets->IsId(currentEdge[1]) != -1))) { if (this->Targets->IsId(currentEdge[0]) != -1) { targetId = currentEdge[0]; } else { targetId = currentEdge[1]; } input->GetPoint(targetId,endingPoint); if (vtkMath::Distance2BetweenPoints(currentPoint,endingPoint) > VTK_VMTK_DOUBLE_TOL) { pointId = newPoints->InsertNextPoint(endingPoint); currentScalar = this->DescentArray->GetTuple1(targetId); currentRadius = this->LineDataArray->GetTuple1(targetId); lineIds->InsertNextId(pointId); currentEdge[0] = targetId; currentEdge[1] = targetId; currentS = 0.0; newScalars->InsertTuple1(pointId,currentRadius); this->Edges->InsertComponent(pointId,0,currentEdge[0]); this->Edges->InsertComponent(pointId,1,currentEdge[1]); this->EdgeParCoords->InsertValue(pointId,currentS); } this->HitTargets->InsertNextId(targetId); done = true; break; } if (done) { break; } input->GetCellEdgeNeighbors(-1,currentEdge[0],currentEdge[1],neighborCells); steepestDescent = this->GetSteepestDescent(input,currentEdge,currentS,steepestDescentEdge,steepestDescentS); if (steepestDescentEdge[0] == -1 || steepestDescentEdge[1] == -1) { vtkWarningMacro(<<"Can't find a steepest descent edge. Target not reached."); done = true; break; } if (directionFactor*steepestDescent < VTK_VMTK_DOUBLE_TOL) { if (!this->StopOnTargets) //if (!this->StopOnTargets || (previousEdge[0] == currentEdge[0] && previousEdge[1] == currentEdge[1])) { vtkWarningMacro(<<"Target not reached."); done = true; // these two lines were outside the if (!this->StopOnTarget), but that may lead to unnecessary failure. break; // Need of better detection of stall. } } currentEdge[0] = steepestDescentEdge[0]; currentEdge[1] = steepestDescentEdge[1]; currentS = steepestDescentS; if ((currentEdge[0] == previousEdge2[0] && currentEdge[1] == previousEdge2[1] && fabs(previousS2 - currentS) < VTK_VMTK_DOUBLE_TOL) || (currentEdge[0] == previousEdge2[1] && currentEdge[1] == previousEdge2[0]) && fabs(1.0 - previousS2 - currentS) < VTK_VMTK_DOUBLE_TOL) { vtkWarningMacro(<<"Degenerate descent detected. Target not reached."); done = true; break; } previousPoint[0] = currentPoint[0]; previousPoint[1] = currentPoint[1]; previousPoint[2] = currentPoint[2]; currentPoint[0] = input->GetPoint(currentEdge[0])[0] * (1.0 - currentS) + input->GetPoint(currentEdge[1])[0] * currentS; currentPoint[1] = input->GetPoint(currentEdge[0])[1] * (1.0 - currentS) + input->GetPoint(currentEdge[1])[1] * currentS; currentPoint[2] = input->GetPoint(currentEdge[0])[2] * (1.0 - currentS) + input->GetPoint(currentEdge[1])[2] * currentS; currentScalar = this->DescentArray->GetTuple1(currentEdge[0]) * (1.0 - currentS) + this->DescentArray->GetTuple1(currentEdge[1]) * currentS; currentRadius = this->LineDataArray->GetTuple1(currentEdge[0]) * (1.0 - currentS) + this->LineDataArray->GetTuple1(currentEdge[1]) * currentS; if (this->MergePaths) { for (j=newPoints->GetNumberOfPoints()-1; j>=0; j--) { if (((this->Edges->GetComponent(j,0)==currentEdge[0])&&(this->Edges->GetComponent(j,1)==currentEdge[1]))|| ((this->Edges->GetComponent(j,0)==currentEdge[1])&&(this->Edges->GetComponent(j,1)==currentEdge[0]))) { double newPoint[3]; newPoints->GetPoint(j,newPoint); if (sqrt(vtkMath::Distance2BetweenPoints(currentPoint,newPoint)) <= this->MergeTolerance) { pointId = j; lineIds->InsertNextId(pointId); done = true; break; } } } if (done) break; } pointId = newPoints->InsertNextPoint(currentPoint); lineIds->InsertNextId(pointId); newScalars->InsertTuple1(pointId,currentRadius); this->Edges->InsertComponent(pointId,0,currentEdge[0]); this->Edges->InsertComponent(pointId,1,currentEdge[1]); this->EdgeParCoords->InsertValue(pointId,currentS); previousEdge2[0] = previousEdge[0]; previousEdge2[1] = previousEdge[1]; previousS2 = previousS; previousEdge[0] = currentEdge[0]; previousEdge[1] = currentEdge[1]; previousS = currentS; } newLines->InsertNextCell(lineIds); neighborCells->Delete(); lineIds->Delete(); } int vtkvmtkSteepestDescentLineTracer::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; vtkPoints* newPoints; vtkCellArray* newLines; vtkDoubleArray* newScalars; if (!this->DescentArrayName) { vtkErrorMacro("Descent array name not specified."); return 1; } if (!input->GetPointData()->GetArray(this->DescentArrayName)) { vtkErrorMacro(<< "Descent array with name specified does not exist!"); return 1; } if (!this->Seeds) { vtkErrorMacro("No Seeds set"); return 1; } if (!this->Seeds->GetNumberOfIds()) { vtkErrorMacro("Empty Seeds list"); return 1; } for (i=0; iSeeds->GetNumberOfIds(); i++) { if ((this->Seeds->GetId(i)<0) || (this->Seeds->GetId(i)>input->GetNumberOfPoints())) { vtkErrorMacro("Seed id invalid or exceeds input number of points."); return 1; } } if (this->StopOnTargets) { for (i=0; iTargets->GetNumberOfIds(); i++) { if ((this->Targets->GetId(i)<0) || (this->Targets->GetId(i) > input->GetNumberOfPoints())) { vtkErrorMacro("Invalid target id."); return 1; } } } this->DescentArray = input->GetPointData()->GetArray(this->DescentArrayName); if (this->DataArrayName) { this->LineDataArray = input->GetPointData()->GetArray(this->DataArrayName); if (!this->LineDataArray) { vtkErrorMacro(<< "Line data array with name specified does not exist!"); return 1; } } else { this->SetDataArrayName("Data Array"); this->LineDataArray = this->DescentArray; } this->Edges = vtkIntArray::New(); this->EdgeParCoords = vtkDoubleArray::New(); this->CellIdsArray = vtkIntArray::New(); this->PCoordsArray = vtkDoubleArray::New(); this->Edges->SetNumberOfComponents(2); this->CellIdsArray->SetNumberOfComponents(2); if (this->EdgeArrayName) { this->Edges->SetName(this->EdgeArrayName); } else { this->Edges->SetName("Edges"); } if (this->EdgePCoordArrayName) { this->EdgeParCoords->SetName(this->EdgePCoordArrayName); } else { this->EdgeParCoords->SetName("EdgePCoords"); } newPoints = vtkPoints::New(); newLines = vtkCellArray::New(); newScalars = vtkDoubleArray::New(); newScalars->SetName(this->DataArrayName); if (this->MergeTolerance < VTK_VMTK_DOUBLE_TOL) { this->MergeTolerance = VTK_VMTK_DOUBLE_TOL; } output->SetPoints(newPoints); output->SetLines(newLines); output->GetPointData()->AddArray(newScalars); newPoints->Delete(); newLines->Delete(); newScalars->Delete(); input->BuildCells(); input->BuildLinks(); this->HitTargets->Initialize(); for (i=0; iSeeds->GetNumberOfIds(); i++) { this->Backtrace(input,this->Seeds->GetId(i)); } output->GetPointData()->AddArray(this->Edges); output->GetPointData()->AddArray(this->EdgeParCoords); this->Edges->Delete(); this->EdgeParCoords->Delete(); this->CellIdsArray->Delete(); this->PCoordsArray->Delete(); return 1; } void vtkvmtkSteepestDescentLineTracer::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSplitExtractor.cxx0000664000175000017500000001735611757446472026337 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineSplitExtractor.cxx,v $ Language: C++ Date: $Date: 2005/10/06 11:01:44 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineSplitExtractor.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkvmtkPolyBallLine.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineSplitExtractor, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkCenterlineSplitExtractor); vtkvmtkCenterlineSplitExtractor::vtkvmtkCenterlineSplitExtractor() { this->SplitPoint[0] = 0.0; this->SplitPoint[1] = 0.0; this->SplitPoint[2] = 0.0; this->SplitPoint2[0] = 0.0; this->SplitPoint2[1] = 0.0; this->SplitPoint2[2] = 0.0; this->Tolerance = 1E-4; this->GapLength = 1.0; this->SplittingMode = POINTANDGAP; this->GroupingMode = FIRSTPOINT; } vtkvmtkCenterlineSplitExtractor::~vtkvmtkCenterlineSplitExtractor() { } void vtkvmtkCenterlineSplitExtractor::ComputePointAndGapCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) { vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New(); tube->SetInput(input); tube->SetInputCellId(cellId); tube->UseRadiusInformationOff(); double tubeFunctionValue = tube->EvaluateFunction(this->SplitPoint); if (tubeFunctionValue > this->Tolerance) { this->NumberOfSplittingPoints = 0; return; } vtkIdType centerlineSubId = tube->GetLastPolyBallCellSubId(); double centerlinePCoord = tube->GetLastPolyBallCellPCoord(); double centerlinePoint[3]; tube->GetLastPolyBallCenter(centerlinePoint); this->NumberOfSplittingPoints = 2; if (this->SubIds) { delete[] this->SubIds; this->SubIds = NULL; } if (this->PCoords) { delete[] this->PCoords; this->PCoords = NULL; } if (this->TractBlanking) { delete[] this->TractBlanking; this->TractBlanking = NULL; } vtkCell* centerline = input->GetCell(cellId); if (centerline->GetCellType() != VTK_LINE && centerline->GetCellType() != VTK_POLY_LINE) { return; } this->SubIds = new vtkIdType[this->NumberOfSplittingPoints]; this->PCoords = new double[this->NumberOfSplittingPoints]; int numberOfCenterlinePoints = centerline->GetNumberOfPoints(); int numberOfCenterlineSubIds = centerline->GetNumberOfPoints() - 1; double currentAbscissa = 0.0; vtkDoubleArray* abscissas = vtkDoubleArray::New(); abscissas->InsertNextValue(currentAbscissa); double point[3], previousPoint[3]; centerline->GetPoints()->GetPoint(0,previousPoint); int i; for (i=1; iGetPoints()->GetPoint(i,point); currentAbscissa += sqrt(vtkMath::Distance2BetweenPoints(previousPoint,point)); abscissas->InsertNextValue(currentAbscissa); previousPoint[0] = point[0]; previousPoint[1] = point[1]; previousPoint[2] = point[2]; } double halfGapLength = this->GapLength * 0.5; double centerlinePointAbscissa = (1.0 - centerlinePCoord) * abscissas->GetValue(centerlineSubId) + centerlinePCoord * abscissas->GetValue(centerlineSubId+1); double abscissa; int lastSubId = numberOfCenterlineSubIds - 1; for (i=centerlineSubId; iGetValue(i+1); if (abscissa - centerlinePointAbscissa > halfGapLength) { lastSubId = i; break; } } double lastPCoord = (centerlinePointAbscissa + halfGapLength - abscissas->GetValue(lastSubId)) / (abscissas->GetValue(lastSubId+1) - abscissas->GetValue(lastSubId)); if (lastPCoord > 1.0) { lastPCoord = 1.0 - 1E-1; } int firstSubId = 0; for (i=centerlineSubId; i>=0; i--) { abscissa = abscissas->GetValue(i); if (centerlinePointAbscissa - abscissa > halfGapLength) { firstSubId = i; break; } } double firstPCoord = (centerlinePointAbscissa - halfGapLength - abscissas->GetValue(firstSubId)) / (abscissas->GetValue(firstSubId+1) - abscissas->GetValue(firstSubId)); if (firstPCoord < 0.0) { firstPCoord = 0.0 + 1E-1; } this->SubIds[0] = firstSubId; this->PCoords[0] = firstPCoord; this->SubIds[1] = lastSubId; this->PCoords[1] = lastPCoord; this->TractBlanking = new int[this->NumberOfSplittingPoints+1]; this->TractBlanking[0] = 0; this->TractBlanking[1] = 1; this->TractBlanking[2] = 0; abscissas->Delete(); } void vtkvmtkCenterlineSplitExtractor::ComputeBetweenPointsCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) { vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New(); tube->SetInput(input); tube->SetInputCellId(cellId); tube->UseRadiusInformationOff(); double tubeFunctionValue = tube->EvaluateFunction(this->SplitPoint); if (tubeFunctionValue > this->Tolerance) { this->NumberOfSplittingPoints = 0; return; } vtkIdType centerlineSubId = tube->GetLastPolyBallCellSubId(); double centerlinePCoord = tube->GetLastPolyBallCellPCoord(); double centerlinePoint[3]; tube->GetLastPolyBallCenter(centerlinePoint); double tubeFunctionValue2 = tube->EvaluateFunction(this->SplitPoint2); if (tubeFunctionValue2 > this->Tolerance) { this->NumberOfSplittingPoints = 0; return; } vtkIdType centerlineSubId2 = tube->GetLastPolyBallCellSubId(); double centerlinePCoord2 = tube->GetLastPolyBallCellPCoord(); double centerlinePoint2[3]; tube->GetLastPolyBallCenter(centerlinePoint2); this->NumberOfSplittingPoints = 2; if (this->SubIds) { delete[] this->SubIds; this->SubIds = NULL; } if (this->PCoords) { delete[] this->PCoords; this->PCoords = NULL; } if (this->TractBlanking) { delete[] this->TractBlanking; this->TractBlanking = NULL; } vtkCell* centerline = input->GetCell(cellId); if (centerline->GetCellType() != VTK_LINE && centerline->GetCellType() != VTK_POLY_LINE) { return; } this->SubIds = new vtkIdType[this->NumberOfSplittingPoints]; this->PCoords = new double[this->NumberOfSplittingPoints]; if (centerlineSubId > centerlineSubId2 || (centerlineSubId == centerlineSubId2 && centerlinePCoord > centerlinePCoord2)) { this->SubIds[0] = centerlineSubId; this->PCoords[0] = centerlinePCoord; this->SubIds[1] = centerlineSubId2; this->PCoords[1] = centerlinePCoord2; } else { this->SubIds[0] = centerlineSubId2; this->PCoords[0] = centerlinePCoord2; this->SubIds[1] = centerlineSubId; this->PCoords[1] = centerlinePCoord; } this->TractBlanking = new int[this->NumberOfSplittingPoints+1]; this->TractBlanking[0] = 0; this->TractBlanking[1] = 1; this->TractBlanking[2] = 0; } void vtkvmtkCenterlineSplitExtractor::ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) { if (this->SplittingMode == POINTANDGAP) { this->ComputePointAndGapCenterlineSplitting(input,cellId); } else if (this->SplittingMode == BETWEENPOINTS) { this->ComputeBetweenPointsCenterlineSplitting(input,cellId); } else { vtkErrorMacro("Error: unsupported splitting mode"); } } void vtkvmtkCenterlineSplitExtractor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlines.h0000664000175000017500000001033011757446472024656 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlines.h,v $ Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCenterlines - Compute centerlines from surface. // .SECTION Description // ... #ifndef __vtkvmtkPolyDataCenterlines_h #define __vtkvmtkPolyDataCenterlines_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkUnstructuredGrid.h" class vtkPolyData; class vtkPoints; class vtkIdList; class vtkDataArray; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlines : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataCenterlines,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataCenterlines *New(); virtual void SetSourceSeedIds(vtkIdList*); vtkGetObjectMacro(SourceSeedIds,vtkIdList); virtual void SetTargetSeedIds(vtkIdList*); vtkGetObjectMacro(TargetSeedIds,vtkIdList); virtual void SetCapCenterIds(vtkIdList*); vtkGetObjectMacro(CapCenterIds,vtkIdList); vtkSetObjectMacro(DelaunayTessellation,vtkUnstructuredGrid); vtkGetObjectMacro(DelaunayTessellation,vtkUnstructuredGrid); vtkGetObjectMacro(VoronoiDiagram,vtkPolyData); vtkGetObjectMacro(PoleIds,vtkIdList); vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); vtkSetStringMacro(CostFunction); vtkGetStringMacro(CostFunction); vtkSetStringMacro(EikonalSolutionArrayName); vtkGetStringMacro(EikonalSolutionArrayName); vtkSetStringMacro(EdgeArrayName); vtkGetStringMacro(EdgeArrayName); vtkSetStringMacro(EdgePCoordArrayName); vtkGetStringMacro(EdgePCoordArrayName); vtkSetStringMacro(CostFunctionArrayName); vtkGetStringMacro(CostFunctionArrayName); vtkSetMacro(FlipNormals,int); vtkGetMacro(FlipNormals,int); vtkBooleanMacro(FlipNormals,int); vtkSetMacro(SimplifyVoronoi,int); vtkGetMacro(SimplifyVoronoi,int); vtkBooleanMacro(SimplifyVoronoi,int); vtkSetMacro(CenterlineResampling,int); vtkGetMacro(CenterlineResampling,int); vtkBooleanMacro(CenterlineResampling,int); vtkSetMacro(ResamplingStepLength,double); vtkGetMacro(ResamplingStepLength,double); vtkSetMacro(AppendEndPointsToCenterlines,int); vtkGetMacro(AppendEndPointsToCenterlines,int); vtkBooleanMacro(AppendEndPointsToCenterlines,int); vtkSetMacro(GenerateDelaunayTessellation,int); vtkGetMacro(GenerateDelaunayTessellation,int); vtkBooleanMacro(GenerateDelaunayTessellation,int); protected: vtkvmtkPolyDataCenterlines(); ~vtkvmtkPolyDataCenterlines(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void FindVoronoiSeeds(vtkUnstructuredGrid *delaunay, vtkIdList *boundaryBaricenterIds, vtkDataArray *normals, vtkIdList *seedIds); void AppendEndPoints(vtkPoints* endPointPairs); void ResampleCenterlines(); void ReverseCenterlines(); vtkIdList* SourceSeedIds; vtkIdList* TargetSeedIds; vtkIdList* CapCenterIds; vtkUnstructuredGrid* DelaunayTessellation; vtkPolyData* VoronoiDiagram; vtkIdList* PoleIds; char* RadiusArrayName; char* CostFunction; char* EikonalSolutionArrayName; char* EdgeArrayName; char* EdgePCoordArrayName; char* CostFunctionArrayName; int FlipNormals; int SimplifyVoronoi; int AppendEndPointsToCenterlines; int CenterlineResampling; double ResamplingStepLength; int GenerateDelaunayTessellation; private: vtkvmtkPolyDataCenterlines(const vtkvmtkPolyDataCenterlines&); // Not implemented. void operator=(const vtkvmtkPolyDataCenterlines&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineGeometry.h0000664000175000017500000000645611757446472024567 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineGeometry.h,v $ Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCenterlineGeometry - ... // .SECTION Description // ... #ifndef __vtkvmtkCenterlineGeometry_h #define __vtkvmtkCenterlineGeometry_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class vtkDoubleArray; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineGeometry : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCenterlineGeometry,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineGeometry* New(); vtkSetStringMacro(LengthArrayName); vtkGetStringMacro(LengthArrayName); vtkSetStringMacro(CurvatureArrayName); vtkGetStringMacro(CurvatureArrayName); vtkSetStringMacro(TorsionArrayName); vtkGetStringMacro(TorsionArrayName); vtkSetStringMacro(TortuosityArrayName); vtkGetStringMacro(TortuosityArrayName); vtkSetStringMacro(FrenetTangentArrayName); vtkGetStringMacro(FrenetTangentArrayName); vtkSetStringMacro(FrenetNormalArrayName); vtkGetStringMacro(FrenetNormalArrayName); vtkSetStringMacro(FrenetBinormalArrayName); vtkGetStringMacro(FrenetBinormalArrayName); vtkSetMacro(SmoothingFactor,double); vtkGetMacro(SmoothingFactor,double); vtkSetMacro(NumberOfSmoothingIterations,int); vtkGetMacro(NumberOfSmoothingIterations,int); vtkSetMacro(LineSmoothing,int); vtkGetMacro(LineSmoothing,int); vtkBooleanMacro(LineSmoothing,int); vtkSetMacro(OutputSmoothedLines,int); vtkGetMacro(OutputSmoothedLines,int); vtkBooleanMacro(OutputSmoothedLines,int); static double ComputeLineCurvature(vtkPoints* linePoints, vtkDoubleArray* curvatureArray); static double ComputeLineTorsion(vtkPoints* linePoints, vtkDoubleArray* torsionArray); static void ComputeLineFrenetReferenceSystem(vtkPoints* linePoints, vtkDoubleArray* lineTangentArray, vtkDoubleArray* lineNormalArray, vtkDoubleArray* lineBinormalArray); protected: vtkvmtkCenterlineGeometry(); ~vtkvmtkCenterlineGeometry(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* LengthArrayName; char* CurvatureArrayName; char* TorsionArrayName; char* TortuosityArrayName; char* FrenetTangentArrayName; char* FrenetNormalArrayName; char* FrenetBinormalArrayName; int LineSmoothing; int OutputSmoothedLines; double SmoothingFactor; int NumberOfSmoothingIterations; private: vtkvmtkCenterlineGeometry(const vtkvmtkCenterlineGeometry&); // Not implemented. void operator=(const vtkvmtkCenterlineGeometry&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBoundaryExtractor.h0000664000175000017500000000376611757446472026101 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBoundaryExtractor.h,v $ Language: C++ Date: $Date: 2006/07/07 10:46:19 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataBoundaryExtractor - Extract boundary edges as poly lines. // .SECTION Description // This class identifies boundary edges and organizes them into poly lines based on connectivity. It also provides the output with a point data vtkIntArray (set as active scalars) in which the ids of boundary points in the input dataset are stored. #ifndef __vtkvmtkPolyDataBoundaryExtractor_h #define __vtkvmtkPolyDataBoundaryExtractor_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataBoundaryExtractor : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataBoundaryExtractor,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataBoundaryExtractor *New(); protected: vtkvmtkPolyDataBoundaryExtractor(); ~vtkvmtkPolyDataBoundaryExtractor() {}; virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); private: vtkvmtkPolyDataBoundaryExtractor(const vtkvmtkPolyDataBoundaryExtractor&); // Not implemented. void operator=(const vtkvmtkPolyDataBoundaryExtractor&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataLocalGeometry.cxx0000664000175000017500000004140511757446472025533 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataLocalGeometry.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataLocalGeometry.h" #include "vtkTriangleFilter.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkDoubleArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataLocalGeometry, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataLocalGeometry); vtkvmtkPolyDataLocalGeometry::vtkvmtkPolyDataLocalGeometry() { this->ComputePoleVectors = 0; this->ComputeGeodesicDistance = 0; this->ComputeNormalizedTangencyDeviation = 0; this->ComputeEuclideanDistance = 0; this->ComputeCenterlineVectors = 0; this->ComputeCellIds = 0; this->ComputePCoords = 0; this->AdjustBoundaryValues = 0; this->PoleVectorsArrayName = NULL; this->GeodesicDistanceArrayName = NULL; this->NormalizedTangencyDeviationArrayName = NULL; this->EuclideanDistanceArrayName = NULL; this->CenterlineVectorsArrayName = NULL; this->CellIdsArrayName = NULL; this->PCoordsArrayName = NULL; this->VoronoiGeodesicDistanceArrayName = NULL; this->VoronoiPoleCenterlineVectorsArrayName = NULL; this->VoronoiCellIdsArrayName = NULL; this->VoronoiPCoordsArrayName = NULL; this->VoronoiDiagram = NULL; this->PoleIds = NULL; } vtkvmtkPolyDataLocalGeometry::~vtkvmtkPolyDataLocalGeometry() { if (this->VoronoiDiagram) { this->VoronoiDiagram->Delete(); this->VoronoiDiagram = NULL; } if (this->PoleIds) { this->PoleIds->Delete(); this->PoleIds = NULL; } if (this->PoleVectorsArrayName) { delete[] this->PoleVectorsArrayName; } if (this->GeodesicDistanceArrayName) { delete[] this->GeodesicDistanceArrayName; } if (this->NormalizedTangencyDeviationArrayName) { delete[] this->NormalizedTangencyDeviationArrayName; } if (this->EuclideanDistanceArrayName) { delete[] this->EuclideanDistanceArrayName; } if (this->CenterlineVectorsArrayName) { delete[] this->CenterlineVectorsArrayName; } if (this->CellIdsArrayName) { delete[] this->CellIdsArrayName; } if (this->PCoordsArrayName) { delete[] this->PCoordsArrayName; } } int vtkvmtkPolyDataLocalGeometry::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, poleId; double surfacePoint[3], polePoint[3], poleVector[3], voronoiPoleVector[3], centerlinePoint[3], centerlineVector[3]; double voronoiRadius, voronoiGeodesicDistance; double geodesicDistance, normalizedTangencyDeviation; double euclideanDistance; vtkDataArray* voronoiGeodesicDistanceArray = NULL; vtkDataArray* voronoiPoleVectorsArray = NULL; vtkDataArray* voronoiCellIdsArray = NULL; vtkDataArray* voronoiPCoordsArray = NULL; vtkDoubleArray* poleVectorsArray = NULL; vtkDoubleArray* geodesicDistanceArray = NULL; vtkDoubleArray* normalizedTangencyDeviationArray = NULL; vtkDoubleArray* euclideanDistanceArray = NULL; vtkDoubleArray* centerlineVectorsArray = NULL; vtkIntArray* cellIdsArray = NULL; vtkDoubleArray* pcoordsArray = NULL; if (!this->VoronoiDiagram) { vtkErrorMacro(<< "No Voronoi diagram specified!"); return 1; } if (!this->PoleIds) { vtkErrorMacro(<< "No poleIds specified!"); return 1; } if (this->ComputeGeodesicDistance || this->ComputeNormalizedTangencyDeviation) { if (!this->VoronoiGeodesicDistanceArrayName) { vtkErrorMacro(<< "No Voronoi geodesic distance array name specified!"); return 1; } voronoiGeodesicDistanceArray = this->VoronoiDiagram->GetPointData()->GetArray(this->VoronoiGeodesicDistanceArrayName); if (!voronoiGeodesicDistanceArray) { vtkErrorMacro(<< "Voronoi geodesic distance array with name specified does not exist!"); return 1; } } if (this->ComputeEuclideanDistance || this->ComputeCenterlineVectors) { if (!this->VoronoiPoleCenterlineVectorsArrayName) { vtkErrorMacro(<< "No Voronoi pole vectors array name specified!"); return 1; } voronoiPoleVectorsArray = this->VoronoiDiagram->GetPointData()->GetArray(this->VoronoiPoleCenterlineVectorsArrayName); if (!voronoiPoleVectorsArray) { vtkErrorMacro(<< "Voronoi pole vectors array with name specified does not exist!"); return 1; } } if (this->ComputeCellIds) { if (!this->VoronoiCellIdsArrayName) { vtkErrorMacro(<< "No Voronoi cellIds array name specified!"); return 1; } voronoiCellIdsArray = this->VoronoiDiagram->GetPointData()->GetArray(this->VoronoiCellIdsArrayName); if (!voronoiCellIdsArray) { vtkErrorMacro(<< "Voronoi cellIds array with name specified does not exist!"); return 1; } } if (this->ComputePCoords) { if (!this->VoronoiPCoordsArrayName) { vtkErrorMacro(<< "No Voronoi pcoords array name specified!"); return 1; } voronoiPCoordsArray = this->VoronoiDiagram->GetPointData()->GetArray(this->VoronoiPCoordsArrayName); if (!voronoiPCoordsArray) { vtkErrorMacro(<< "Voronoi pcoords array with name specified does not exist!"); return 1; } } if (this->ComputeGeodesicDistance) { if (!this->GeodesicDistanceArrayName) { vtkErrorMacro(<< "No geodesic distance array name specified!"); return 1; } } if (this->ComputeNormalizedTangencyDeviation) { if (!this->NormalizedTangencyDeviationArrayName) { vtkErrorMacro(<< "No normalized tangency deviation array name specified!"); return 1; } } if (this->ComputeEuclideanDistance || this->ComputeCenterlineVectors) { if (!this->EuclideanDistanceArrayName) { vtkErrorMacro(<< "No Euclidean distance array name specified!"); return 1; } } if (this->ComputeCellIds) { if (!this->CellIdsArrayName) { vtkErrorMacro(<< "No cellIds array name specified!"); return 1; } } if (this->ComputePCoords) { if (!this->PCoordsArrayName) { vtkErrorMacro(<< "No pcoords array name specified!"); return 1; } } if (this->ComputePoleVectors) { if (!this->PoleVectorsArrayName) { vtkErrorMacro(<< "No pole vectors array name specified!"); return 1; } } if (this->ComputePoleVectors) { poleVectorsArray = vtkDoubleArray::New(); poleVectorsArray->SetName(this->PoleVectorsArrayName); poleVectorsArray->SetNumberOfComponents(3); poleVectorsArray->SetNumberOfTuples(input->GetNumberOfPoints()); poleVectorsArray->FillComponent(0,0.0); poleVectorsArray->FillComponent(1,0.0); poleVectorsArray->FillComponent(2,0.0); } if (this->ComputeGeodesicDistance) { geodesicDistanceArray = vtkDoubleArray::New(); geodesicDistanceArray->SetName(this->GeodesicDistanceArrayName); geodesicDistanceArray->SetNumberOfTuples(input->GetNumberOfPoints()); geodesicDistanceArray->FillComponent(0,0.0); } if (this->ComputeNormalizedTangencyDeviation) { normalizedTangencyDeviationArray = vtkDoubleArray::New(); normalizedTangencyDeviationArray->SetName(this->NormalizedTangencyDeviationArrayName); normalizedTangencyDeviationArray->SetNumberOfTuples(input->GetNumberOfPoints()); normalizedTangencyDeviationArray->FillComponent(0,0.0); } if (this->ComputeEuclideanDistance) { euclideanDistanceArray = vtkDoubleArray::New(); euclideanDistanceArray->SetName(this->EuclideanDistanceArrayName); euclideanDistanceArray->SetNumberOfTuples(input->GetNumberOfPoints()); euclideanDistanceArray->FillComponent(0,0.0); } if (this->ComputeCenterlineVectors) { centerlineVectorsArray = vtkDoubleArray::New(); centerlineVectorsArray->SetNumberOfComponents(3); centerlineVectorsArray->SetName(this->CenterlineVectorsArrayName); centerlineVectorsArray->SetNumberOfTuples(input->GetNumberOfPoints()); centerlineVectorsArray->FillComponent(0,0.0); centerlineVectorsArray->FillComponent(1,0.0); centerlineVectorsArray->FillComponent(2,0.0); } if (this->ComputeCellIds) { cellIdsArray = vtkIntArray::New(); cellIdsArray->SetNumberOfComponents(2); cellIdsArray->SetName(this->CellIdsArrayName); cellIdsArray->SetNumberOfTuples(input->GetNumberOfPoints()); cellIdsArray->FillComponent(0,0.0); cellIdsArray->FillComponent(1,0.0); } if (this->ComputePCoords) { pcoordsArray = vtkDoubleArray::New(); pcoordsArray->SetName(this->PCoordsArrayName); pcoordsArray->SetNumberOfTuples(input->GetNumberOfPoints()); pcoordsArray->FillComponent(0,0.0); } for (i=0; iGetNumberOfPoints(); i++) { poleId = this->PoleIds->GetId(i); if (poleId == -1) { vtkWarningMacro(<<"Invalid PoleId found"); } if (this->ComputePoleVectors) { input->GetPoint(i,surfacePoint); this->VoronoiDiagram->GetPoint(poleId,polePoint); poleVector[0] = polePoint[0] - surfacePoint[0]; poleVector[1] = polePoint[1] - surfacePoint[1]; poleVector[2] = polePoint[2] - surfacePoint[2]; poleVectorsArray->SetTuple(i,poleVector); } if (this->ComputeGeodesicDistance || this->ComputeNormalizedTangencyDeviation) { input->GetPoint(i,surfacePoint); this->VoronoiDiagram->GetPoint(poleId,polePoint); voronoiRadius = sqrt(vtkMath::Distance2BetweenPoints(surfacePoint,polePoint)); voronoiGeodesicDistance = voronoiGeodesicDistanceArray->GetTuple1(poleId); geodesicDistance = voronoiGeodesicDistance + voronoiRadius; if (geodesicDistance > VTK_VMTK_DOUBLE_TOL) { normalizedTangencyDeviation = voronoiGeodesicDistance / geodesicDistance; } else { normalizedTangencyDeviation = 1.0; } if (this->ComputeGeodesicDistance) { geodesicDistanceArray->SetComponent(i,0,geodesicDistance); } if (this->ComputeNormalizedTangencyDeviation) { normalizedTangencyDeviationArray->SetComponent(i,0,normalizedTangencyDeviation); } } if (this->ComputeEuclideanDistance || this->ComputeCenterlineVectors) { input->GetPoint(i,surfacePoint); this->VoronoiDiagram->GetPoint(poleId,polePoint); voronoiPoleVectorsArray->GetTuple(poleId,voronoiPoleVector); centerlinePoint[0] = polePoint[0] + voronoiPoleVector[0]; centerlinePoint[1] = polePoint[1] + voronoiPoleVector[1]; centerlinePoint[2] = polePoint[2] + voronoiPoleVector[2]; centerlineVector[0] = centerlinePoint[0] - surfacePoint[0]; centerlineVector[1] = centerlinePoint[1] - surfacePoint[1]; centerlineVector[2] = centerlinePoint[2] - surfacePoint[2]; if (this->ComputeEuclideanDistance) { euclideanDistance = sqrt(vtkMath::Distance2BetweenPoints(surfacePoint,centerlinePoint)); euclideanDistanceArray->SetComponent(i,0,euclideanDistance); } if (this->ComputeCenterlineVectors) { centerlineVectorsArray->SetTuple(i,centerlineVector); } } if (this->ComputeCellIds) { cellIdsArray->SetTuple(i,voronoiCellIdsArray->GetTuple(poleId)); } if (this->ComputePCoords) { pcoordsArray->SetTuple(i,voronoiPCoordsArray->GetTuple(poleId)); } } output->CopyStructure(input); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); if (this->ComputePoleVectors) { output->GetPointData()->AddArray(poleVectorsArray); poleVectorsArray->Delete(); } if (this->ComputeGeodesicDistance) { output->GetPointData()->AddArray(geodesicDistanceArray); geodesicDistanceArray->Delete(); } if (this->ComputeNormalizedTangencyDeviation) { output->GetPointData()->AddArray(normalizedTangencyDeviationArray); normalizedTangencyDeviationArray->Delete(); } if (this->ComputeEuclideanDistance) { output->GetPointData()->AddArray(euclideanDistanceArray); euclideanDistanceArray->Delete(); } if (this->ComputeCenterlineVectors) { output->GetPointData()->AddArray(centerlineVectorsArray); centerlineVectorsArray->Delete(); } if (this->ComputeCellIds) { output->GetPointData()->AddArray(cellIdsArray); cellIdsArray->Delete(); } if (this->ComputePCoords) { output->GetPointData()->AddArray(pcoordsArray); pcoordsArray->Delete(); } if (this->AdjustBoundaryValues) { this->AdjustBoundaryQuantities(output); } return 1; } void vtkvmtkPolyDataLocalGeometry::AdjustBoundaryQuantities(vtkPolyData* output) { vtkDataArray* poleVectorsArray = NULL; vtkDataArray* geodesicDistanceArray = NULL; vtkDataArray* euclideanDistanceArray = NULL; vtkDataArray* centerlineVectorsArray = NULL; vtkTriangleFilter* triangleFilter = vtkTriangleFilter::New(); triangleFilter->SetInput(output); triangleFilter->Update(); vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(triangleFilter->GetOutput()); boundaryExtractor->Update(); vtkPolyData* boundaries = boundaryExtractor->GetOutput(); double point[3], barycenter[3]; int numberOfBoundaryPoints; if (this->ComputePoleVectors) { poleVectorsArray = output->GetPointData()->GetArray(this->PoleVectorsArrayName); } if (this->ComputeGeodesicDistance) { geodesicDistanceArray = output->GetPointData()->GetArray(this->GeodesicDistanceArrayName); } if (this->ComputeEuclideanDistance) { euclideanDistanceArray = output->GetPointData()->GetArray(this->EuclideanDistanceArrayName); } if (this->ComputeCenterlineVectors) { centerlineVectorsArray = output->GetPointData()->GetArray(this->CenterlineVectorsArrayName); } double radialVector[3], radialVectorModulus; vtkIdType boundaryPointId; int i, j; for (i=0; iGetNumberOfCells(); i++) { vtkCell* boundary = boundaries->GetCell(i); numberOfBoundaryPoints = boundary->GetPoints()->GetNumberOfPoints(); barycenter[0] = barycenter[1] = barycenter[2] = 0.0; for (j=0; jGetPoints()->GetPoint(j,point); barycenter[0] += point[0]; barycenter[1] += point[1]; barycenter[2] += point[2]; } barycenter[0] /= numberOfBoundaryPoints; barycenter[1] /= numberOfBoundaryPoints; barycenter[2] /= numberOfBoundaryPoints; for (j=0; j(boundaries->GetPointData()->GetScalars()->GetTuple1(boundary->GetPointId(j))); output->GetPoint(boundaryPointId,point); radialVector[0] = barycenter[0] - point[0]; radialVector[1] = barycenter[1] - point[1]; radialVector[2] = barycenter[2] - point[2]; radialVectorModulus = vtkMath::Norm(radialVector); if (this->ComputePoleVectors) { poleVectorsArray->SetTuple(boundaryPointId,radialVector); } if (this->ComputeGeodesicDistance) { geodesicDistanceArray->SetTuple1(boundaryPointId,radialVectorModulus); } if (this->ComputeEuclideanDistance) { euclideanDistanceArray->SetTuple1(boundaryPointId,radialVectorModulus); } if (this->ComputeCenterlineVectors) { centerlineVectorsArray->SetTuple(boundaryPointId,radialVector); } } } triangleFilter->Delete(); boundaryExtractor->Delete(); } void vtkvmtkPolyDataLocalGeometry::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBranchSections.cxx0000664000175000017500000006503311757446472025675 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBranchSections.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataBranchSections.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkPolygon.h" #include "vtkTriangle.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkPlane.h" #include "vtkLine.h" #include "vtkCutter.h" #include "vtkStripper.h" #include "vtkPolyDataConnectivityFilter.h" #include "vtkMath.h" #include "vtkCleanPolyData.h" #include "vtkAppendPolyData.h" #include "vtkvmtkMath.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkPolyDataBranchUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataBranchSections, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkPolyDataBranchSections); vtkvmtkPolyDataBranchSections::vtkvmtkPolyDataBranchSections() { this->GroupIdsArrayName = NULL; this->Centerlines = NULL; this->CenterlineRadiusArrayName = NULL; this->CenterlineGroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->CenterlineTractIdsArrayName = NULL; this->BlankingArrayName = NULL; this->BranchSectionGroupIdsArrayName = NULL; this->BranchSectionAreaArrayName = NULL; this->BranchSectionMinSizeArrayName = NULL; this->BranchSectionMaxSizeArrayName = NULL; this->BranchSectionShapeArrayName = NULL; this->BranchSectionClosedArrayName = NULL; this->BranchSectionDistanceSpheresArrayName = NULL; this->NumberOfDistanceSpheres = 1; this->ReverseDirection = 0; } vtkvmtkPolyDataBranchSections::~vtkvmtkPolyDataBranchSections() { 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->BranchSectionGroupIdsArrayName) { delete[] this->BranchSectionGroupIdsArrayName; this->BranchSectionGroupIdsArrayName = NULL; } if (this->BranchSectionAreaArrayName) { delete[] this->BranchSectionAreaArrayName; this->BranchSectionAreaArrayName = NULL; } if (this->BranchSectionMinSizeArrayName) { delete[] this->BranchSectionMinSizeArrayName; this->BranchSectionMinSizeArrayName = NULL; } if (this->BranchSectionMaxSizeArrayName) { delete[] this->BranchSectionMaxSizeArrayName; this->BranchSectionMaxSizeArrayName = NULL; } if (this->BranchSectionShapeArrayName) { delete[] this->BranchSectionShapeArrayName; this->BranchSectionShapeArrayName = NULL; } if (this->BranchSectionClosedArrayName) { delete[] this->BranchSectionClosedArrayName; this->BranchSectionClosedArrayName = NULL; } if (this->BranchSectionDistanceSpheresArrayName) { delete[] this->BranchSectionDistanceSpheresArrayName; this->BranchSectionDistanceSpheresArrayName = NULL; } } int vtkvmtkPolyDataBranchSections::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->BranchSectionGroupIdsArrayName) { vtkErrorMacro(<<"BranchSectionGroupIdsArrayName not specified"); return 1; } if (!this->BranchSectionAreaArrayName) { vtkErrorMacro(<<"BranchSectionAreaArrayName not specified"); return 1; } if (!BranchSectionMinSizeArrayName) { vtkErrorMacro(<<"BranchSectionMinSizeArrayName not specified"); return 1; } if (!BranchSectionMaxSizeArrayName) { vtkErrorMacro(<<"BranchSectionMaxSizeArrayName not specified"); return 1; } if (!BranchSectionShapeArrayName) { vtkErrorMacro(<<"BranchSectionShapeArrayName not specified"); return 1; } if (!BranchSectionClosedArrayName) { vtkErrorMacro(<<"BranchSectionClosedArrayName not specified"); return 1; } if (!BranchSectionDistanceSpheresArrayName) { vtkErrorMacro(<<"BranchSectionDistanceSpheresArrayName not specified"); return 1; } vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputPolys = vtkCellArray::New(); output->SetPoints(outputPoints); output->SetPolys(outputPolys); vtkIntArray* branchSectionGroupIdsArray = vtkIntArray::New(); branchSectionGroupIdsArray->SetName(this->BranchSectionGroupIdsArrayName); vtkDoubleArray* branchSectionAreaArray = vtkDoubleArray::New(); branchSectionAreaArray->SetName(this->BranchSectionAreaArrayName); vtkDoubleArray* branchSectionShapeArray = vtkDoubleArray::New(); branchSectionShapeArray->SetName(this->BranchSectionShapeArrayName); vtkDoubleArray* branchSectionMinSizeArray = vtkDoubleArray::New(); branchSectionMinSizeArray->SetName(this->BranchSectionMinSizeArrayName); vtkDoubleArray* branchSectionMaxSizeArray = vtkDoubleArray::New(); branchSectionMaxSizeArray->SetName(this->BranchSectionMaxSizeArrayName); vtkIntArray* branchSectionClosedArray = vtkIntArray::New(); branchSectionClosedArray->SetName(this->BranchSectionClosedArrayName); vtkIntArray* branchSectionDistanceSpheresArray = vtkIntArray::New(); branchSectionDistanceSpheresArray->SetName(this->BranchSectionDistanceSpheresArrayName); output->GetCellData()->AddArray(branchSectionGroupIdsArray); output->GetCellData()->AddArray(branchSectionAreaArray); output->GetCellData()->AddArray(branchSectionMinSizeArray); output->GetCellData()->AddArray(branchSectionMaxSizeArray); output->GetCellData()->AddArray(branchSectionShapeArray); output->GetCellData()->AddArray(branchSectionClosedArray); output->GetCellData()->AddArray(branchSectionDistanceSpheresArray); vtkIdList* nonBlankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetNonBlankedGroupsIdList(this->Centerlines,this->CenterlineGroupIdsArrayName,this->BlankingArrayName,nonBlankedGroupIds); int i; for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = nonBlankedGroupIds->GetId(i); this->ComputeBranchSections(input,groupId,output); } nonBlankedGroupIds->Delete(); outputPoints->Delete(); outputPolys->Delete(); branchSectionGroupIdsArray->Delete(); branchSectionAreaArray->Delete(); branchSectionMinSizeArray->Delete(); branchSectionMaxSizeArray->Delete(); branchSectionShapeArray->Delete(); branchSectionClosedArray->Delete(); branchSectionDistanceSpheresArray->Delete(); return 1; } void vtkvmtkPolyDataBranchSections::ComputeBranchSections(vtkPolyData* input, int groupId, vtkPolyData* output) { vtkPoints* branchSectionPoints = output->GetPoints(); vtkCellArray* branchSectionPolys = output->GetPolys(); vtkIntArray* branchSectionGroupIdsArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionGroupIdsArrayName)); vtkDoubleArray* branchSectionAreaArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionAreaArrayName)); vtkDoubleArray* branchSectionMinSizeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionMinSizeArrayName)); vtkDoubleArray* branchSectionMaxSizeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionMaxSizeArrayName)); vtkDoubleArray* branchSectionShapeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionShapeArrayName)); vtkIntArray* branchSectionClosedArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionClosedArrayName)); vtkIntArray* branchSectionDistanceSpheresArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BranchSectionDistanceSpheresArrayName)); int i, j; for (i=0; ; 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 totalNumberOfSpheres = i * this->NumberOfDistanceSpheres; bool anyPoint = false; vtkIdList* groupCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,groupId,groupCellIds); for (j=0; jGetNumberOfIds(); j++) { vtkIdType centerlineCellId = groupCellIds->GetId(j); vtkPoints* centerlineCellPoints = this->Centerlines->GetCell(centerlineCellId)->GetPoints(); vtkIdType firstSubId = 0; double firstPCoord = 0.0; bool reverseTouchingDirection = false; if (this->ReverseDirection) { firstSubId = centerlineCellPoints->GetNumberOfPoints()-2; firstPCoord = 1.0; reverseTouchingDirection = true; } vtkIdType touchingSubId = -1; double touchingPCoord = 0.0; vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(this->Centerlines,this->CenterlineRadiusArrayName,centerlineCellId,firstSubId,firstPCoord,totalNumberOfSpheres,touchingSubId,touchingPCoord,reverseTouchingDirection); if (touchingSubId == -1) { continue; } anyPoint = true; double touchingPoint[3]; vtkvmtkCenterlineUtilities::InterpolatePoint(this->Centerlines,centerlineCellId,touchingSubId,touchingPCoord,touchingPoint); double touchingPoint0[3], touchingPoint1[3]; centerlineCellPoints->GetPoint(touchingSubId,touchingPoint0); centerlineCellPoints->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,centerlineCellId,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) { break; } 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,groupId,false,cylinder); vtkPolyData* section = vtkPolyData::New(); bool closed = false; this->ExtractCylinderSection(cylinder,averagePoint,averageTangent,section,closed); section->BuildCells(); vtkPoints* sectionCellPoints = section->GetCell(0)->GetPoints(); int numberOfSectionCellPoints = sectionCellPoints->GetNumberOfPoints(); branchSectionPolys->InsertNextCell(numberOfSectionCellPoints); int k; for (k=0; kInsertNextPoint(sectionCellPoints->GetPoint(k)); branchSectionPolys->InsertCellPoint(branchPointId); } double area = this->ComputeBranchSectionArea(section); double sizeRange[2]; double shape = this->ComputeBranchSectionShape(section,averagePoint,sizeRange); branchSectionGroupIdsArray->InsertNextValue(groupId); branchSectionAreaArray->InsertNextValue(area); branchSectionMinSizeArray->InsertNextValue(sizeRange[0]); branchSectionMaxSizeArray->InsertNextValue(sizeRange[1]); branchSectionShapeArray->InsertNextValue(shape); branchSectionClosedArray->InsertNextValue(closed); branchSectionDistanceSpheresArray->InsertNextValue(totalNumberOfSpheres); groupCellIds->Delete(); cylinder->Delete(); section->Delete(); } } void vtkvmtkPolyDataBranchSections::ExtractCylinderSection(vtkPolyData* cylinder, double origin[3], double normal[3], vtkPolyData* section, bool & closed) { vtkPlane* plane = vtkPlane::New(); plane->SetOrigin(origin); plane->SetNormal(normal); vtkCutter* cutter = vtkCutter::New(); cutter->SetInput(cylinder); cutter->SetCutFunction(plane); cutter->GenerateCutScalarsOn(); cutter->SetValue(0,0.0); cutter->Update(); vtkCleanPolyData* cleaner = vtkCleanPolyData::New(); cleaner->SetInput(cutter->GetOutput()); cleaner->Update(); if (cleaner->GetOutput()->GetNumberOfPoints() == 0) { return; } vtkPolyDataConnectivityFilter* connectivityFilter = vtkPolyDataConnectivityFilter::New(); connectivityFilter->SetInput(cleaner->GetOutput()); connectivityFilter->SetExtractionModeToClosestPointRegion(); connectivityFilter->SetClosestPoint(origin); connectivityFilter->Update(); section->DeepCopy(connectivityFilter->GetOutput()); section->Update(); // TODO: manually reconstruct single cell line from connectivity output if (section->GetNumberOfCells() == 0) { return; } section->BuildCells(); section->BuildLinks(); // find first point int numberOfLinePoints = section->GetNumberOfPoints(); unsigned short ncells; vtkIdType* cells; vtkIdType npts, *pts; int numberOfSingleCellPoints = 0; vtkIdType firstPointId = -1; for (int i=0; iGetPointCells(i,ncells,cells); if (ncells == 1) { ++numberOfSingleCellPoints; firstPointId = i; } } if (numberOfSingleCellPoints == 0) { firstPointId = section->GetCell(0)->GetPointId(0); } vtkIdList* polygonPointIds = vtkIdList::New(); polygonPointIds->InsertNextId(firstPointId); bool done = false; vtkIdType pointId = firstPointId; closed = false; vtkIdType cellId = -1; while (!done) { section->GetPointCells(pointId,ncells,cells); if (ncells == 1) { if (pointId == firstPointId) { cellId = cells[0]; } else { done = true; break; } } else if (ncells == 2) { if (cells[0] == cellId) { cellId = cells[1]; } else { cellId = cells[0]; } } section->GetCellPoints(cellId,npts,pts); if (pts[0] == pointId) { pointId = pts[1]; } else { pointId = pts[0]; } if (pointId == firstPointId) { closed = true; done = true; break; } polygonPointIds->InsertNextId(pointId); } section->GetLines()->Reset(); section->GetPolys()->Reset(); section->GetPolys()->InsertNextCell(polygonPointIds); section->Update(); cutter->Delete(); connectivityFilter->Delete(); polygonPointIds->Delete(); } double vtkvmtkPolyDataBranchSections::ComputeBranchSectionArea(vtkPolyData* branchSection) { branchSection->BuildCells(); if (branchSection->GetNumberOfCells() == 0) { return 0.0; } vtkPolygon* sectionPolygon = vtkPolygon::SafeDownCast(branchSection->GetCell(0)); vtkIdList* trianglePointIds = vtkIdList::New(); sectionPolygon->Triangulate(trianglePointIds); int numberOfTriangles = trianglePointIds->GetNumberOfIds() / 3; double polygonArea = 0.0; for (int i=0; iGetId(3*i); vtkIdType pointId1 = trianglePointIds->GetId(3*i+1); vtkIdType pointId2 = trianglePointIds->GetId(3*i+2); double point0[3], point1[3], point2[3]; sectionPolygon->GetPoints()->GetPoint(pointId0,point0); sectionPolygon->GetPoints()->GetPoint(pointId1,point1); sectionPolygon->GetPoints()->GetPoint(pointId2,point2); double triangleArea = vtkTriangle::TriangleArea(point0,point1,point2); polygonArea += triangleArea; } trianglePointIds->Delete(); return polygonArea; } #ifdef VMTK_ONE_SIDED_SECTION_SHAPE double vtkvmtkPolyDataBranchSections::ComputeBranchSectionShape(vtkPolyData* branchSection, double center[3], double sizeRange[2]) { branchSection->BuildCells(); if (branchSection->GetNumberOfCells() == 0) { sizeRange[0] = sizeRange[1] = 0.0; return 0.0; } vtkPolygon* sectionPolygon = vtkPolygon::SafeDownCast(branchSection->GetCell(0)); int numberOfSectionPolygonPoints = sectionPolygon->GetNumberOfPoints(); double minDistance = VTK_VMTK_LARGE_DOUBLE; double maxDistance = 0.0; for (int i=0; iGetPoints()->GetPoint(i,point); double distance = sqrt(vtkMath::Distance2BetweenPoints(point,center)); if (distance > maxDistance) { maxDistance = distance; } if (distance < minDistance) { minDistance = distance; } } sizeRange[0] = minDistance; sizeRange[1] = maxDistance; double sectionShape = minDistance / maxDistance; return sectionShape; } #else double vtkvmtkPolyDataBranchSections::ComputeBranchSectionShape(vtkPolyData* branchSection, double center[3], double sizeRange[2]) { branchSection->BuildCells(); if (branchSection->GetNumberOfCells() == 0) { sizeRange[0] = sizeRange[1] = 0.0; return 0.0; } vtkPolygon* sectionPolygon = vtkPolygon::SafeDownCast(branchSection->GetCell(0)); int numberOfSectionPolygonPoints = sectionPolygon->GetNumberOfPoints(); double minDistance = VTK_VMTK_LARGE_DOUBLE; double maxDistance = 0.0; vtkIdType minDistanceId = -1; vtkIdType maxDistanceId = -1; double point[3]; for (int i=0; iGetPoints()->GetPoint(i,point); double distance = sqrt(vtkMath::Distance2BetweenPoints(point,center)); if (distance > maxDistance) { maxDistance = distance; maxDistanceId = i; } if (distance < minDistance) { minDistance = distance; minDistanceId = i; } } if (minDistance == -1 || maxDistance == -1) { sizeRange[0] = 0.0; sizeRange[1] = 0.0; return 0.0; } double point0[3]; double point1[3]; double planeNormal[3]; double radialVector0[3]; double radialVector1[3]; double cross[3]; planeNormal[0] = 0.0; planeNormal[1] = 0.0; planeNormal[2] = 0.0; for (int i=0; iGetPoints()->GetPoint(i,point0); sectionPolygon->GetPoints()->GetPoint((i+numberOfSectionPolygonPoints/4)%numberOfSectionPolygonPoints,point1); radialVector0[0] = point0[0] - center[0]; radialVector0[1] = point0[1] - center[1]; radialVector0[2] = point0[2] - center[2]; radialVector1[0] = point1[0] - center[0]; radialVector1[1] = point1[1] - center[1]; radialVector1[2] = point1[2] - center[2]; vtkMath::Cross(point0,point1,cross); planeNormal[0] += cross[0]; planeNormal[1] += cross[1]; planeNormal[2] += cross[2]; } vtkMath::Normalize(planeNormal); double minDistancePoint[3]; sectionPolygon->GetPoints()->GetPoint(minDistanceId,minDistancePoint); double maxDistancePoint[3]; sectionPolygon->GetPoints()->GetPoint(maxDistanceId,maxDistancePoint); double minDistanceNormal[3]; double maxDistanceNormal[3]; minDistanceNormal[0] = minDistancePoint[0] - center[0]; minDistanceNormal[1] = minDistancePoint[1] - center[1]; minDistanceNormal[2] = minDistancePoint[2] - center[2]; vtkMath::Normalize(minDistanceNormal); maxDistanceNormal[0] = maxDistancePoint[0] - center[0]; maxDistanceNormal[1] = maxDistancePoint[1] - center[1]; maxDistanceNormal[2] = maxDistancePoint[2] - center[2]; vtkMath::Normalize(maxDistanceNormal); double minDistanceOppositePoint[3]; double maxDistanceOppositePoint[3]; minDistanceOppositePoint[0] = center[0] - 2.0 * maxDistance * minDistanceNormal[0]; minDistanceOppositePoint[1] = center[1] - 2.0 * maxDistance * minDistanceNormal[1]; minDistanceOppositePoint[2] = center[2] - 2.0 * maxDistance * minDistanceNormal[2]; maxDistanceOppositePoint[0] = center[0] - 2.0 * maxDistance * maxDistanceNormal[0]; maxDistanceOppositePoint[1] = center[1] - 2.0 * maxDistance * maxDistanceNormal[1]; maxDistanceOppositePoint[2] = center[2] - 2.0 * maxDistance * maxDistanceNormal[2]; double intersectionPoint[3]; double maxIntersectionDistance = 0.0; int intersection; double u,v; for (int i=0; iGetPoints()->GetPoint(i,point0); sectionPolygon->GetPoints()->GetPoint((i+1)%numberOfSectionPolygonPoints,point1); intersection = vtkLine::Intersection(minDistanceOppositePoint,center,point0,point1,u,v); if (intersection == 0) { continue; } intersectionPoint[0] = (1.0 - u) * minDistanceOppositePoint[0] + u * center[0]; intersectionPoint[1] = (1.0 - u) * minDistanceOppositePoint[1] + u * center[1]; intersectionPoint[2] = (1.0 - u) * minDistanceOppositePoint[2] + u * center[2]; double intersectionDistance = sqrt(vtkMath::Distance2BetweenPoints(intersectionPoint,center)); if (intersectionDistance > maxIntersectionDistance) { maxIntersectionDistance = intersectionDistance; } } minDistance += maxIntersectionDistance; maxIntersectionDistance = 0.0; for (int i=0; iGetPoints()->GetPoint(i,point0); sectionPolygon->GetPoints()->GetPoint((i+1)%numberOfSectionPolygonPoints,point1); intersection = vtkLine::Intersection(maxDistanceOppositePoint,center,point0,point1,u,v); if (intersection == 0) { continue; } intersectionPoint[0] = (1.0 - u) * maxDistanceOppositePoint[0] + u * center[0]; intersectionPoint[1] = (1.0 - u) * maxDistanceOppositePoint[1] + u * center[1]; intersectionPoint[2] = (1.0 - u) * maxDistanceOppositePoint[2] + u * center[2]; double intersectionDistance = sqrt(vtkMath::Distance2BetweenPoints(intersectionPoint,center)); if (intersectionDistance > maxIntersectionDistance) { maxIntersectionDistance = intersectionDistance; } } maxDistance += maxIntersectionDistance; sizeRange[0] = minDistance; sizeRange[1] = maxDistance; double sectionShape = minDistance / maxDistance; return sectionShape; } #endif void vtkvmtkPolyDataBranchSections::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataPatchingFilter.h0000664000175000017500000000646611757446472025325 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataPatchingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .SECTION Description // .. #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(); vtkTypeRevisionMacro(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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineProjection.cxx0000664000175000017500000001046311757446472027112 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineProjection.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:07:48 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlineProjection, "$Revision: 1.3 $"); 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; iGetPoint(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; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkSteepestDescentShooter.h0000664000175000017500000000560411757446472025423 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSteepestDescentShooter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSteepestDescentShooter - Shoot Voronoi vertices onto centerlines. // .SECTION Description // ... #ifndef __vtkvmtkSteepestDescentShooter_h #define __vtkvmtkSteepestDescentShooter_h #include "vtkvmtkNonManifoldSteepestDescent.h" #include "vtkPolyData.h" #include "vtkEdgeTable.h" #include "vtkIntArray.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkSteepestDescentShooter : public vtkvmtkNonManifoldSteepestDescent { public: vtkTypeRevisionMacro(vtkvmtkSteepestDescentShooter,vtkvmtkNonManifoldSteepestDescent); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSteepestDescentShooter *New(); vtkSetObjectMacro(Target,vtkPolyData); vtkGetObjectMacro(Target,vtkPolyData); vtkSetObjectMacro(Seeds,vtkIdList); vtkGetObjectMacro(Seeds,vtkIdList); vtkSetStringMacro(EdgeArrayName); vtkGetStringMacro(EdgeArrayName); vtkSetStringMacro(TargetVectorsArrayName); vtkGetStringMacro(TargetVectorsArrayName); vtkSetStringMacro(TargetCellIdsArrayName); vtkGetStringMacro(TargetCellIdsArrayName); vtkSetStringMacro(TargetPCoordsArrayName); vtkGetStringMacro(TargetPCoordsArrayName); protected: vtkvmtkSteepestDescentShooter(); ~vtkvmtkSteepestDescentShooter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void Backtrace(vtkPolyData* input, vtkIdType seedId); void FindNearestPolyLinePoint(double* currentPoint, double* lineClosestPoint, int &lineCellId, int &lineCellSubId, double &linePCoord); vtkPolyData* Target; vtkIdList* Seeds; vtkIntArray* TargetArray; vtkDataArray* EdgeArray; vtkDoubleArray* TargetVectors; vtkIntArray* TargetCellIds; vtkDoubleArray* TargetPCoords; char* EdgeArrayName; char* TargetVectorsArrayName; char* TargetCellIdsArrayName; char* TargetPCoordsArrayName; private: vtkvmtkSteepestDescentShooter(const vtkvmtkSteepestDescentShooter&); // Not implemented. void operator=(const vtkvmtkSteepestDescentShooter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataStretchMappingFilter.h0000664000175000017500000000505711757446472026513 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataStretchMappingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataStretchMappingFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataStretchMappingFilter_h #define __vtkvmtkPolyDataStretchMappingFilter_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataStretchMappingFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataStretchMappingFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataStretchMappingFilter,vtkPolyDataAlgorithm); vtkSetStringMacro(StretchedMappingArrayName); vtkGetStringMacro(StretchedMappingArrayName); vtkSetStringMacro(HarmonicMappingArrayName); vtkGetStringMacro(HarmonicMappingArrayName); vtkSetStringMacro(MetricArrayName); vtkGetStringMacro(MetricArrayName); vtkSetStringMacro(BoundaryMetricArrayName); vtkGetStringMacro(BoundaryMetricArrayName); vtkSetMacro(UseBoundaryMetric,int); vtkGetMacro(UseBoundaryMetric,int); vtkBooleanMacro(UseBoundaryMetric,int); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); vtkSetMacro(MetricBoundsGapFactor,double); vtkGetMacro(MetricBoundsGapFactor,double); protected: vtkvmtkPolyDataStretchMappingFilter(); ~vtkvmtkPolyDataStretchMappingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* StretchedMappingArrayName; char* HarmonicMappingArrayName; char* GroupIdsArrayName; char* MetricArrayName; char* BoundaryMetricArrayName; int UseBoundaryMetric; double MetricBoundsGapFactor; private: vtkvmtkPolyDataStretchMappingFilter(const vtkvmtkPolyDataStretchMappingFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataStretchMappingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkReferenceSystemUtilities.h0000664000175000017500000000326211757446472025752 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkReferenceSystemUtilities.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkReferenceSystemUtilities - ... // .SECTION Description // . #ifndef __vtkvmtkReferenceSystemUtilities_h #define __vtkvmtkReferenceSystemUtilities_h #include "vtkObject.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkReferenceSystemUtilities : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkReferenceSystemUtilities,vtkObject); static vtkvmtkReferenceSystemUtilities* New(); static vtkIdType GetReferenceSystemPointId(vtkPolyData* referenceSystems, const char* groupIdsArrayName, vtkIdType groupId); protected: vtkvmtkReferenceSystemUtilities() {}; ~vtkvmtkReferenceSystemUtilities() {}; private: vtkvmtkReferenceSystemUtilities(const vtkvmtkReferenceSystemUtilities&); // Not implemented. void operator=(const vtkvmtkReferenceSystemUtilities&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyBallLine.cxx0000664000175000017500000001545511757446472023663 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBallLine.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyBallLine.h" #include "vtkvmtkConstants.h" #include "vtkPointData.h" #include "vtkPolyLine.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyBallLine, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyBallLine); vtkvmtkPolyBallLine::vtkvmtkPolyBallLine() { this->Input = NULL; this->InputCellIds = NULL; this->InputCellId = -1; this->PolyBallRadiusArrayName = NULL; this->LastPolyBallCellId = -1; this->LastPolyBallCellSubId = -1; this->LastPolyBallCellPCoord = 0.0; this->LastPolyBallCenter[0] = this->LastPolyBallCenter[1] = this->LastPolyBallCenter[2] = 0.0; this->LastPolyBallCenterRadius = 0.0; this->UseRadiusInformation = 1; } vtkvmtkPolyBallLine::~vtkvmtkPolyBallLine() { if (this->Input) { this->Input->Delete(); this->Input = NULL; } if (this->InputCellIds) { this->InputCellIds->Delete(); this->InputCellIds = NULL; } if (this->PolyBallRadiusArrayName) { delete[] this->PolyBallRadiusArrayName; this->PolyBallRadiusArrayName = NULL; } } double vtkvmtkPolyBallLine::ComplexDot(double x[4], double y[4]) { return x[0]*y[0] + x[1]*y[1] + x[2]*y[2] - x[3]*y[3]; } double vtkvmtkPolyBallLine::EvaluateFunction(double x[3]) { vtkIdType i, k; vtkIdType npts, *pts; double polyballFunctionValue, minPolyBallFunctionValue; double point0[3], point1[3]; double radius0, radius1; double vector0[4], vector1[4], closestPoint[4]; double t; double num, den; vtkDataArray *polyballRadiusArray = NULL; if (!this->Input) { vtkErrorMacro(<<"No Input specified!"); return 0.0; } if (this->Input->GetNumberOfPoints()==0) { vtkWarningMacro(<<"Empty Input specified!"); return 0.0; } if (this->UseRadiusInformation) { if (!this->PolyBallRadiusArrayName) { vtkErrorMacro(<<"No PolyBallRadiusArrayName specified!"); return 0.0; } polyballRadiusArray = this->Input->GetPointData()->GetArray(this->PolyBallRadiusArrayName); if (polyballRadiusArray==NULL) { vtkErrorMacro(<<"PolyBallRadiusArray with name specified does not exist!"); return 0.0; } } if (this->Input->GetLines()==NULL) { vtkWarningMacro(<<"No lines in Input dataset."); return 0.0; } this->Input->BuildCells(); this->Input->Update(); minPolyBallFunctionValue = VTK_VMTK_LARGE_DOUBLE; closestPoint[0] = closestPoint[1] = closestPoint[2] = closestPoint[2] = 0.0; this->LastPolyBallCellId = -1; this->LastPolyBallCellSubId = -1; this->LastPolyBallCellPCoord = 0.0; this->LastPolyBallCenter[0] = this->LastPolyBallCenter[1] = this->LastPolyBallCenter[2] = 0.0; this->LastPolyBallCenterRadius = 0.0; vtkIdList* cellIds = vtkIdList::New(); if (this->InputCellIds) { cellIds->DeepCopy(this->InputCellIds); } else if (this->InputCellId != -1) { cellIds->InsertNextId(this->InputCellId); } else { cellIds->SetNumberOfIds(this->Input->GetNumberOfCells()); for (k=0; kInput->GetNumberOfCells(); k++) { cellIds->SetId(k,k); } } for (k=0; kGetNumberOfIds(); k++) { vtkIdType cellId = cellIds->GetId(k); if (this->Input->GetCellType(cellId)!=VTK_LINE && this->Input->GetCellType(cellId)!=VTK_POLY_LINE) { continue; } this->Input->GetCellPoints(cellId,npts,pts); for (i=0; iInput->GetPoint(pts[i],point0); this->Input->GetPoint(pts[i+1],point1); if (this->UseRadiusInformation) { radius0 = polyballRadiusArray->GetComponent(pts[i],0); radius1 = polyballRadiusArray->GetComponent(pts[i+1],0); } else { radius0 = 0.0; radius1 = 0.0; } vector0[0] = point1[0] - point0[0]; vector0[1] = point1[1] - point0[1]; vector0[2] = point1[2] - point0[2]; vector0[3] = radius1 - radius0; vector1[0] = x[0] - point0[0]; vector1[1] = x[1] - point0[1]; vector1[2] = x[2] - point0[2]; vector1[3] = 0.0 - radius0; // cout<ComplexDot(vector0,vector1); den = this->ComplexDot(vector0,vector0); if (fabs(den)LastPolyBallCellId = cellId; this->LastPolyBallCellSubId = i; this->LastPolyBallCellPCoord = t; this->LastPolyBallCenter[0] = closestPoint[0]; this->LastPolyBallCenter[1] = closestPoint[1]; this->LastPolyBallCenter[2] = closestPoint[2]; this->LastPolyBallCenterRadius = closestPoint[3]; } } } cellIds->Delete(); return minPolyBallFunctionValue; } void vtkvmtkPolyBallLine::EvaluateGradient(double x[3], double n[3]) { vtkWarningMacro("Poly ball gradient computation not yet implemented!"); // TODO } void vtkvmtkPolyBallLine::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataScissors.cxx0000664000175000017500000002552011757446472024575 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataScissors.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataScissors.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkIntArray.h" #include "vtkPolyLine.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataScissors, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataScissors); vtkvmtkPolyDataScissors::vtkvmtkPolyDataScissors() { this->CutLine = NULL; this->CutLinePointIdsArrayName = NULL; } vtkvmtkPolyDataScissors::~vtkvmtkPolyDataScissors() { if (this->CutLine) { this->CutLine->Delete(); this->CutLine = NULL; } } int vtkvmtkPolyDataScissors::IsEdgeInCell(vtkPolyData *input, vtkIdType edgePointId0, vtkIdType edgePointId1, vtkIdType cellId) { vtkIdType npts, *pts; vtkIdType i; input->GetCellPoints(cellId,npts,pts); for (i=0; iGetNumberOfIds()>0) { cellsOnSameSide->Initialize(); } input->GetPointCells(linePointId1,ncells,cells); edge[0] = linePointId1; input->GetCellPoints(referenceCellId,npts,pts); edge[1] = -1; for (i=0; iIsEdgeInCell(input,edge[0],edge[1],cells[i])) { if ((cells[i]==targetCellId0)||(cells[i]==targetCellId1)) { cellsOnSameSide->InsertNextId(cells[i]); return 1; } done = false; cellsOnSameSide->InsertNextId(cells[i]); previousCellId = cells[i]; input->GetCellPoints(cells[i],npts,pts); for (j=0; jGetInformationObject(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 k, i , j; vtkIdType surfacePointId, newPointId; vtkIdType id0, id1, previousId; vtkIdType duplicatePointLocation; vtkIdType numberOfLines, numberOfLinePoints, numberOfInputPoints; vtkIdType cellId, previousCellToEdit; vtkIdType npts, *pts; vtkDataArray *cutLinePointIdsArray; vtkCell *polyLine; vtkPoints *newPoints; vtkCellArray *newPolys; vtkCellArray *editedCells; vtkIdList *duplicatePointIds; vtkIdList *duplicatedPointIds; vtkIdList *cellsToEdit, *editedCellIds; vtkIdList *cellEdgeNeighbors; vtkIdList *cellsOnSameSide; vtkPointData *inputPD = input->GetPointData(); vtkPointData *outputPD = output->GetPointData(); previousCellToEdit = -1; if (this->CutLine==NULL) { vtkErrorMacro(<<"CutLine not specified!"); return 1; } if (this->CutLinePointIdsArrayName==NULL) { vtkErrorMacro(<<"CutLinePointIdsArrayName not specified!"); return 1; } cutLinePointIdsArray = this->CutLine->GetPointData()->GetArray(this->CutLinePointIdsArrayName); if (cutLinePointIdsArray==NULL) { vtkErrorMacro(<<"CutLinePointIdsArray with name specified does not exist!"); return 1; } newPoints = vtkPoints::New(); newPolys = vtkCellArray::New(); editedCells = vtkCellArray::New(); duplicatePointIds = vtkIdList::New(); duplicatedPointIds = vtkIdList::New(); cellsToEdit = vtkIdList::New(); editedCellIds = vtkIdList::New(); cellEdgeNeighbors = vtkIdList::New(); cellsOnSameSide = vtkIdList::New(); numberOfInputPoints = input->GetNumberOfPoints(); newPoints->DeepCopy(input->GetPoints()); numberOfLinePoints = this->CutLine->GetNumberOfPoints(); numberOfLines = this->CutLine->GetNumberOfCells(); input->BuildCells(); input->BuildLinks(); this->CutLine->BuildCells(); for (k=0; kCutLine->GetCell(k); if (polyLine->GetCellType() != VTK_LINE && polyLine->GetCellType() != VTK_POLY_LINE) { continue; } numberOfLinePoints = polyLine->GetNumberOfPoints(); duplicatedPointIds->Initialize(); duplicatePointIds->Initialize(); cellsToEdit->Initialize(); for (i=0; i(cutLinePointIdsArray->GetComponent(polyLine->GetPointId(i),0)); newPointId = newPoints->InsertNextPoint(input->GetPoint(surfacePointId)); duplicatedPointIds->InsertNextId(surfacePointId); duplicatePointIds->InsertNextId(newPointId); } for (i=0; i(cutLinePointIdsArray->GetComponent(polyLine->GetPointId(i),0)); id1 = static_cast(cutLinePointIdsArray->GetComponent(polyLine->GetPointId(i+1),0)); if (id0==id1) { vtkErrorMacro(<<"Coincident points found on CutLine! "); return 1; } if (!input->IsEdge(id0,id1)) { vtkErrorMacro(<<"CutLine is not entirely defined on mesh edges! "); return 1; } cellEdgeNeighbors->Initialize(); input->GetCellEdgeNeighbors(-1,id0,id1,cellEdgeNeighbors); if (cellEdgeNeighbors->GetNumberOfIds()<2) { vtkWarningMacro(<<"Surface boundary or hole found."); continue; } if (cellEdgeNeighbors->GetNumberOfIds()>2) { vtkErrorMacro(<<"Surface is non-manifold! "); return 1; } // try to choose the first cell in order to maintain consistency in the orientation, if at all possible // this is a bit too naive (it basically doesn't work most of the times). TODO: special treatment of joints + consistency. if (i==0) { if (k==0) { cellsToEdit->InsertUniqueId(cellEdgeNeighbors->GetId(0)); previousCellToEdit = cellEdgeNeighbors->GetId(0); } else { if (cellsToEdit->IsId(cellEdgeNeighbors->GetId(0))!=-1) { cellsToEdit->InsertUniqueId(cellEdgeNeighbors->GetId(0)); previousCellToEdit = cellEdgeNeighbors->GetId(0); } else { cellsToEdit->InsertUniqueId(cellEdgeNeighbors->GetId(1)); previousCellToEdit = cellEdgeNeighbors->GetId(1); } } continue; } previousId = static_cast(cutLinePointIdsArray->GetComponent(polyLine->GetPointId(i-1),0)); // select the cells lying on the same side of the cut line. cellsOnSameSide->Initialize(); if (this->GetCellsOnSameSide(input,cellEdgeNeighbors->GetId(0),cellEdgeNeighbors->GetId(1),previousCellToEdit,previousId,id0,id1,cellsOnSameSide)) { for (j=0; jGetNumberOfIds(); j++) { cellsToEdit->InsertUniqueId(cellsOnSameSide->GetId(j)); } previousCellToEdit = cellsOnSameSide->GetId(cellsOnSameSide->GetNumberOfIds()-1); } else { // well, we could try to, going the other way and getting the complementary cells, but there's no time now (this is a TODO) vtkErrorMacro(<<"Hole in the surface found. Can't determine line orientation."); return 1; } } for (i=0; iGetNumberOfIds(); i++) { cellId = cellsToEdit->GetId(i); input->GetCellPoints(cellId,npts,pts); editedCellIds->InsertUniqueId(cellId); editedCells->InsertNextCell(npts); for (j=0; jIsId(pts[j]); if (duplicatePointLocation!=-1) { editedCells->InsertCellPoint(duplicatePointIds->GetId(duplicatePointLocation)); } else { editedCells->InsertCellPoint(pts[j]); } } } } input->GetPolys()->InitTraversal(); for (i=0; iGetPolys()->GetNumberOfCells(); i++) { input->GetPolys()->GetNextCell(npts,pts); if (editedCellIds->IsId(i)==-1) { newPolys->InsertNextCell(npts,pts); } } editedCells->InitTraversal(); for (i=0; iGetNumberOfCells(); i++) { editedCells->GetNextCell(npts,pts); newPolys->InsertNextCell(npts,pts); } output->SetPoints(newPoints); output->SetPolys(newPolys); outputPD->CopyAllocate(inputPD,numberOfInputPoints+numberOfLinePoints); for (i=0; iCopyData(inputPD,i,i); } for (i=0; iGetNumberOfIds(); i++) { outputPD->CopyData(inputPD,duplicatedPointIds->GetId(i),duplicatePointIds->GetId(i)); } duplicatePointIds->Delete(); duplicatedPointIds->Delete(); cellsToEdit->Delete(); cellEdgeNeighbors->Delete(); cellsOnSameSide->Delete(); editedCells->Delete(); editedCellIds->Delete(); newPoints->Delete(); newPolys->Delete(); return 1; } void vtkvmtkPolyDataScissors::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineEndpointExtractor.h0000664000175000017500000000504011757446472026434 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineEndpointExtractor.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkCenterlineEndpointExtractor,vtkvmtkCenterlineSplittingAndGroupingFilter); void PrintSelf(ostream& os, vtkIndent indent); 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); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBifurcationProfiles.cxx0000664000175000017500000003425111757446472026737 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBifurcationProfiles.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataBifurcationProfiles.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkCenterlineBifurcationVectors.h" #include "vtkvmtkPolyDataBranchUtilities.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkvmtkBoundaryReferenceSystems.h" vtkCxxRevisionMacro(vtkvmtkPolyDataBifurcationProfiles, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkPolyDataBifurcationProfiles); vtkvmtkPolyDataBifurcationProfiles::vtkvmtkPolyDataBifurcationProfiles() { this->GroupIdsArrayName = NULL; this->Centerlines = NULL; this->CenterlineRadiusArrayName = NULL; this->CenterlineGroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->CenterlineTractIdsArrayName = NULL; this->BlankingArrayName = NULL; this->BifurcationProfileGroupIdsArrayName = NULL; this->BifurcationProfileBifurcationGroupIdsArrayName = NULL; this->BifurcationProfileOrientationArrayName = NULL; } vtkvmtkPolyDataBifurcationProfiles::~vtkvmtkPolyDataBifurcationProfiles() { 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->BifurcationProfileGroupIdsArrayName) { delete[] this->BifurcationProfileGroupIdsArrayName; this->BifurcationProfileGroupIdsArrayName = NULL; } if (this->BifurcationProfileBifurcationGroupIdsArrayName) { delete[] this->BifurcationProfileBifurcationGroupIdsArrayName; this->BifurcationProfileBifurcationGroupIdsArrayName = NULL; } if (this->BifurcationProfileOrientationArrayName) { delete[] this->BifurcationProfileOrientationArrayName; this->BifurcationProfileOrientationArrayName = NULL; } } int vtkvmtkPolyDataBifurcationProfiles::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->BifurcationProfileGroupIdsArrayName) { vtkErrorMacro(<<"BifurcationProfileGroupIdsArrayName not specified"); return 1; } if (!this->BifurcationProfileBifurcationGroupIdsArrayName) { vtkErrorMacro(<<"BifurcationProfileBifurcationGroupIdsArrayName not specified"); return 1; } if (!BifurcationProfileOrientationArrayName) { vtkErrorMacro(<<"BifurcationProfileOrientationArrayName not specified"); return 1; } vtkIntArray* bifurcationProfileGroupIdsArray = vtkIntArray::New(); bifurcationProfileGroupIdsArray->SetName(this->BifurcationProfileGroupIdsArrayName); vtkIntArray* bifurcationProfileBifurcationGroupIdsArray = vtkIntArray::New(); bifurcationProfileBifurcationGroupIdsArray->SetName(this->BifurcationProfileBifurcationGroupIdsArrayName); vtkIntArray* bifurcationProfileOrientationArray = vtkIntArray::New(); bifurcationProfileOrientationArray->SetName(this->BifurcationProfileOrientationArrayName); output->GetCellData()->AddArray(bifurcationProfileGroupIdsArray); output->GetCellData()->AddArray(bifurcationProfileBifurcationGroupIdsArray); output->GetCellData()->AddArray(bifurcationProfileOrientationArray); vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputLines = vtkCellArray::New(); output->SetPoints(outputPoints); output->SetLines(outputLines); vtkIdList* blankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetBlankedGroupsIdList(this->Centerlines,this->CenterlineGroupIdsArrayName,this->BlankingArrayName,blankedGroupIds); int i; for (i=0; iGetNumberOfIds(); 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->ComputeBifurcationProfiles(input,bifurcationGroupId,upStreamGroupIds,downStreamGroupIds,output); upStreamGroupIds->Delete(); downStreamGroupIds->Delete(); } blankedGroupIds->Delete(); outputPoints->Delete(); outputLines->Delete(); bifurcationProfileGroupIdsArray->Delete(); bifurcationProfileBifurcationGroupIdsArray->Delete(); bifurcationProfileOrientationArray->Delete(); return 1; } void vtkvmtkPolyDataBifurcationProfiles::ComputeBifurcationProfiles(vtkPolyData* input, int bifurcationGroupId, vtkIdList* upStreamGroupIds, vtkIdList* downStreamGroupIds, vtkPolyData* output) { vtkDataArray* radiusArray = this->Centerlines->GetPointData()->GetArray(this->CenterlineRadiusArrayName); vtkPoints* outputPoints = output->GetPoints(); vtkCellArray* outputLines = output->GetLines(); vtkIntArray* bifurcationProfileOrientationArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationProfileOrientationArrayName)); vtkIntArray* bifurcationProfileGroupIdsArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationProfileGroupIdsArrayName)); vtkIntArray* bifurcationProfileBifurcationGroupIdsArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->BifurcationProfileBifurcationGroupIdsArrayName)); vtkIdList* bifurcationProfileGroupIds = vtkIdList::New(); vtkIntArray* bifurcationProfileOrientations = vtkIntArray::New(); int numberOfUpStreamGroupIds = upStreamGroupIds->GetNumberOfIds(); int numberOfDownStreamGroupIds = downStreamGroupIds->GetNumberOfIds(); int i; for (i=0; iInsertNextId(upStreamGroupIds->GetId(i)); bifurcationProfileOrientations->InsertNextValue(vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_UPSTREAM_ORIENTATION); } for (i=0; iInsertNextId(downStreamGroupIds->GetId(i)); bifurcationProfileOrientations->InsertNextValue(vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_DOWNSTREAM_ORIENTATION); } int numberOfBifurcationProfiles = bifurcationProfileGroupIds->GetNumberOfIds(); for (i=0; iGetId(i); int bifurcationProfileOrientation = bifurcationProfileOrientations->GetValue(i); double averagePoint[3]; averagePoint[0] = averagePoint[1] = averagePoint[2] = 0.0; double weightSum = 0.0; int j; vtkIdList* groupCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,bifurcationProfileGroupId,groupCellIds); for (j=0; jGetNumberOfIds(); j++) { vtkIdType cellId = groupCellIds->GetId(j); vtkCell* cell = this->Centerlines->GetCell(cellId); int numberOfCellPoints = cell->GetNumberOfPoints(); double lastPoint[3]; double lastPointRadius = 0.0; if (bifurcationProfileOrientation == vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_UPSTREAM_ORIENTATION) { cell->GetPoints()->GetPoint(numberOfCellPoints-1,lastPoint); lastPointRadius = radiusArray->GetComponent(cell->GetPointId(numberOfCellPoints-1),0); } else if (bifurcationProfileOrientation == vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_DOWNSTREAM_ORIENTATION) { cell->GetPoints()->GetPoint(0,lastPoint); lastPointRadius = radiusArray->GetComponent(cell->GetPointId(0),0); } else { vtkErrorMacro("Error: invalid BifurcationVectorOrientation"); return; } averagePoint[0] += lastPointRadius * lastPointRadius * lastPoint[0]; averagePoint[1] += lastPointRadius * lastPointRadius * lastPoint[1]; averagePoint[2] += lastPointRadius * lastPointRadius * lastPoint[2]; weightSum += lastPointRadius * lastPointRadius; } averagePoint[0] /= weightSum; averagePoint[1] /= weightSum; averagePoint[2] /= weightSum; vtkPolyData* cylinder = vtkPolyData::New(); vtkvmtkPolyDataBranchUtilities::ExtractGroup(input,this->GroupIdsArrayName,bifurcationProfileGroupId,false,cylinder); vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(cylinder); boundaryExtractor->Update(); vtkPolyData* profile = boundaryExtractor->GetOutput(); int numberOfCells = profile->GetNumberOfCells(); int closestCellId = -1; double minDistance = VTK_VMTK_LARGE_DOUBLE; for (j=0; jGetCell(j)->GetPoints(),barycenter); double barycenterDistance = vtkMath::Distance2BetweenPoints(barycenter,averagePoint); if (barycenterDistance < minDistance) { closestCellId = j; minDistance = barycenterDistance; } } vtkPoints* profileCellPoints = profile->GetCell(closestCellId)->GetPoints(); int numberOfProfileCellPoints = profileCellPoints->GetNumberOfPoints(); outputLines->InsertNextCell(numberOfProfileCellPoints); for (j=0; jInsertNextPoint(profileCellPoints->GetPoint(j)); outputLines->InsertCellPoint(pointId); } bifurcationProfileGroupIdsArray->InsertNextValue(bifurcationProfileGroupId); bifurcationProfileBifurcationGroupIdsArray->InsertNextValue(bifurcationGroupId); bifurcationProfileOrientationArray->InsertNextValue(bifurcationProfileOrientation); groupCellIds->Delete(); cylinder->Delete(); boundaryExtractor->Delete(); } bifurcationProfileGroupIds->Delete(); bifurcationProfileOrientations->Delete(); } void vtkvmtkPolyDataBifurcationProfiles::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkMergeCenterlines.h0000664000175000017500000000460111757446472024204 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMergeCenterlines.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - Merge centerlines. // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkMergeCenterlines,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataFlowExtensionsFilter.h0000664000175000017500000001005411757446472026543 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFlowExtensionsFilter.h,v $ Language: C++ Date: $Date: 2006/07/07 10:46:19 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - . // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkPolyDataFlowExtensionsFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkInternalTetrahedraExtractor.h0000664000175000017500000000707111757446472026431 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkInternalTetrahedraExtractor.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkInternalTetrahedraExtractor - Extract internal tetrahedra from a Delaunay tessellation. // .SECTION Description // This class takes in input the Delaunay tessellation of a point set and extracts internal tetrahedra based on outward oriented point normals (to be provided as input point data array). A tetrahedron \f$T_i\f$ is retained if // \f[(x_j - c_i) \cdot n_j \geq 0 \qquad \forall x_j \in T_i \f] // where \f$x_i\f$ are the vertices of \f$T_i\f$, \f$c_i\f$ its circumcenter and \f$n_j\f$ the normals at the vertices. // It is possible to properly handle capped regions (generated with vtkCapPolyData) by activating UseCaps and providing the ids of cap centers. // .SECTION See Also // vtkCapPolyData #ifndef __vtkvmtkInternalTetrahedraExtractor_h #define __vtkvmtkInternalTetrahedraExtractor_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkPolyData.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkInternalTetrahedraExtractor : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkInternalTetrahedraExtractor,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkInternalTetrahedraExtractor *New(); // Description: // Set/Get the name of the array containing outward oriented point normals. vtkSetStringMacro(OutwardNormalsArrayName); vtkGetStringMacro(OutwardNormalsArrayName); // Description: // Turn on/off special handling of caps. vtkSetMacro(UseCaps,int); vtkGetMacro(UseCaps,int); vtkBooleanMacro(UseCaps,int); // Description: // Set/Get the ids of cap centers. vtkSetObjectMacro(CapCenterIds,vtkIdList); vtkGetObjectMacro(CapCenterIds,vtkIdList); vtkSetMacro(Tolerance,double); vtkGetMacro(Tolerance,double); // Description: // Turn on/off removal of surface slivers. vtkSetMacro(RemoveSubresolutionTetrahedra,int); vtkGetMacro(RemoveSubresolutionTetrahedra,int); vtkBooleanMacro(RemoveSubresolutionTetrahedra,int); vtkSetMacro(SubresolutionFactor,double); vtkGetMacro(SubresolutionFactor,double); vtkSetObjectMacro(Surface,vtkPolyData); vtkGetObjectMacro(Surface,vtkPolyData); protected: vtkvmtkInternalTetrahedraExtractor(); ~vtkvmtkInternalTetrahedraExtractor(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int UseCaps; vtkIdList* CapCenterIds; char* OutwardNormalsArrayName; double Tolerance; int RemoveSubresolutionTetrahedra; vtkPolyData* Surface; double SubresolutionFactor; private: vtkvmtkInternalTetrahedraExtractor(const vtkvmtkInternalTetrahedraExtractor&); // Not implemented. void operator=(const vtkvmtkInternalTetrahedraExtractor&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBifurcationSections.h0000664000175000017500000001123011757446472026360 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBifurcationSections.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataBifurcationSections - ... // .SECTION Description // ... #ifndef __vtkvmtkPolyDataBifurcationSections_h #define __vtkvmtkPolyDataBifurcationSections_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataBifurcationSections : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataBifurcationSections,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataBifurcationSections* 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(BifurcationSectionPointArrayName); vtkGetStringMacro(BifurcationSectionPointArrayName); vtkSetStringMacro(BifurcationSectionNormalArrayName); vtkGetStringMacro(BifurcationSectionNormalArrayName); vtkSetStringMacro(BifurcationSectionAreaArrayName); vtkGetStringMacro(BifurcationSectionAreaArrayName); vtkSetStringMacro(BifurcationSectionMinSizeArrayName); vtkGetStringMacro(BifurcationSectionMinSizeArrayName); vtkSetStringMacro(BifurcationSectionMaxSizeArrayName); vtkGetStringMacro(BifurcationSectionMaxSizeArrayName); vtkSetStringMacro(BifurcationSectionShapeArrayName); vtkGetStringMacro(BifurcationSectionShapeArrayName); vtkSetStringMacro(BifurcationSectionGroupIdsArrayName); vtkGetStringMacro(BifurcationSectionGroupIdsArrayName); vtkSetStringMacro(BifurcationSectionBifurcationGroupIdsArrayName); vtkGetStringMacro(BifurcationSectionBifurcationGroupIdsArrayName); vtkSetStringMacro(BifurcationSectionOrientationArrayName); vtkGetStringMacro(BifurcationSectionOrientationArrayName); vtkSetStringMacro(BifurcationSectionDistanceSpheresArrayName); vtkGetStringMacro(BifurcationSectionDistanceSpheresArrayName); vtkSetStringMacro(BifurcationSectionClosedArrayName); vtkGetStringMacro(BifurcationSectionClosedArrayName); vtkSetMacro(NumberOfDistanceSpheres,int); vtkGetMacro(NumberOfDistanceSpheres,int); protected: vtkvmtkPolyDataBifurcationSections(); ~vtkvmtkPolyDataBifurcationSections(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ComputeBifurcationSections(vtkPolyData* input, int bifurcationGroupId, vtkIdList* upStreamGroupIds, vtkIdList* downStreamGroupIds, vtkPolyData* output); vtkPolyData* Centerlines; char* GroupIdsArrayName; char* CenterlineRadiusArrayName; char* CenterlineGroupIdsArrayName; char* CenterlineIdsArrayName; char* CenterlineTractIdsArrayName; char* BlankingArrayName; char* BifurcationSectionGroupIdsArrayName; char* BifurcationSectionBifurcationGroupIdsArrayName; char* BifurcationSectionOrientationArrayName; char* BifurcationSectionDistanceSpheresArrayName; char* BifurcationSectionPointArrayName; char* BifurcationSectionNormalArrayName; char* BifurcationSectionAreaArrayName; char* BifurcationSectionMinSizeArrayName; char* BifurcationSectionMaxSizeArrayName; char* BifurcationSectionShapeArrayName; char* BifurcationSectionClosedArrayName; int NumberOfDistanceSpheres; private: vtkvmtkPolyDataBifurcationSections(const vtkvmtkPolyDataBifurcationSections&); // Not implemented. void operator=(const vtkvmtkPolyDataBifurcationSections&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkNonManifoldFastMarching.h0000664000175000017500000002000711757446472025442 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNonManifoldFastMarching.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkNonManifoldFastMarching - Implementation of the Fast Marching Method on polygonal non-manifolds. // .SECTION Description // This class is used to solve the Eikonal equation \f[|\nabla T(\mathbf{x})| = F(\mathbf{x})\f] on non-manifolds made of convex polygons, using the Fast Marching Method, by J.A. Sethian (see below). The solution to the Eikonal equation represents the arrival times of a wave propagating on a domain with speed \f$F^{-1}(\mathbf{x})\f$ from given seed points (or regions). If F(x)=1, T(x) represents the geodesic distance field to the seed points (Note: F(x) can be equivalently interpreted as a cost function). The Fast Marching Method takes O(N logN). For more insight see J.A. Sethian, Level Set Methods and Fast Marching Methods, Cambridge University Press, 2nd Edition, 1999. // // The implementation given in this class is an extension of the Fast Marching Method for triangulated 2-manifolds proposed by Kimmel et al. (R. Kimmel and J.A. Sethian. Computing geodesic paths on manifolds. PNAS, 95(15): 8431-8435, Jul 1998.) to non-manifolds made of convex polygons, such as the Voronoi diagram. // // The propagation starts from a set of seeds. By default the seed points are given a propagation time of 0.0, but activating InitializeFromScalars and providing the point data array of name InitializationArrayName, it is possible to assign nonzero initialization times (this is useful when the zero propagation time point lies inside a cell). // For the specification of F(x), the user must either provide a point data array of name CostFunctionArrayName, or activate UnitSpeed, which sets F(x)=1 everywhere, thus yielding a geodesic distance field. // The propagation stops when all the points in the domain path-connected to the seeds have been visited. Alternatively it is possible to limit the propagation by setting StopTravelTime or StopNumberOfPoints. // The solution is stored in a point data array of name SolutionArrayName (name provided by the user, "EikonalSolution" by default). // // The Regularization value adds a constant term to F(x), which acts as a regularization term for the minimal cost paths (see L.D. Cohen and R. Kimmel. Global minimum of active contour models: a minimal path approach. IJCV, 24(1): 57-78, Aug 1997). // // .SECTION See Also // vtkVoronoiDiagram3D vtkMinHeap #ifndef __vtkvmtkNonManifoldFastMarching_h #define __vtkvmtkNonManifoldFastMarching_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkIntArray.h" #include "vtkPolyData.h" #include "vtkvmtkMinHeap.h" #include "vtkvmtkConstants.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" const char VTK_VMTK_ACCEPTED_STATUS = 0x01; const char VTK_VMTK_CONSIDERED_STATUS = 0x02; const char VTK_VMTK_FAR_STATUS = 0x04; class vtkDoubleArray; class vtkCharArray; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkNonManifoldFastMarching : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkNonManifoldFastMarching,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkNonManifoldFastMarching *New(); // Description: // Set/Get maximum travel time for travel time-based stop criterion. vtkSetMacro(StopTravelTime,double); vtkGetMacro(StopTravelTime,double); // Description: // Set/Get maximum number of visited points for number of visited points-based stop criterion. vtkSetMacro(StopNumberOfPoints,int); vtkGetMacro(StopNumberOfPoints,int); // Description: // Set/Get minimal cost path regularization amount. vtkSetMacro(Regularization,double); vtkGetMacro(Regularization,double); // Description: // Toggle on/off boundary conditions expressed as a list of seeds. vtkSetMacro(SeedsBoundaryConditions,int); vtkGetMacro(SeedsBoundaryConditions,int); vtkBooleanMacro(SeedsBoundaryConditions,int); // Description: // Toggle on/off boundary conditions expressed as poly data. vtkSetMacro(PolyDataBoundaryConditions,int); vtkGetMacro(PolyDataBoundaryConditions,int); vtkBooleanMacro(PolyDataBoundaryConditions,int); // Description: // Set/Get seeds were boundary conditions are specified. vtkSetObjectMacro(Seeds,vtkIdList); vtkGetObjectMacro(Seeds,vtkIdList); // Description: // Set/Get poly data were boundary conditions are specified. vtkSetObjectMacro(BoundaryPolyData,vtkPolyData); vtkGetObjectMacro(BoundaryPolyData,vtkPolyData); // Description: // Set/Get the name of the 2-component point data array of boundary poly data where point ids of edges of the input intersected by boundary poly data are stored. vtkSetStringMacro(IntersectedEdgesArrayName); vtkGetStringMacro(IntersectedEdgesArrayName); // Description: // Toggle on/off using point data array of name InitializationArrayName for the solution value of seed points. If off, a value of 0.0 is used for all seeds. vtkSetMacro(InitializeFromScalars,int); vtkGetMacro(InitializeFromScalars,int); vtkBooleanMacro(InitializeFromScalars,int); // Description: // Set/Get the name of point data InitializationArray vtkSetStringMacro(InitializationArrayName); vtkGetStringMacro(InitializationArrayName); // Description: // Toggle on/off using a unit speed field over the whole domain (used to obtain geodesic distances). If off, a CostFunctionArray must be provided. vtkSetMacro(UnitSpeed,int); vtkGetMacro(UnitSpeed,int); vtkBooleanMacro(UnitSpeed,int); // Description: // Set/Get the name of point data CostFunctionArray vtkSetStringMacro(CostFunctionArrayName); vtkGetStringMacro(CostFunctionArrayName); // Description: // Set/Get the name of point data SolutionArray vtkSetStringMacro(SolutionArrayName); vtkGetStringMacro(SolutionArrayName); protected: vtkvmtkNonManifoldFastMarching(); ~vtkvmtkNonManifoldFastMarching(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void InitPropagation(vtkPolyData* input); void SolveQuadratic(double a, double b, double c, char &nSol, double &x0, double &x1); void GetNeighbors(vtkPolyData* input, vtkIdType pointId, vtkIdList* neighborIds); double ComputeUpdateFromCellNeighbor(vtkPolyData* input, vtkIdType neighborId, vtkIdType* trianglePts); void UpdateNeighbor(vtkPolyData* input, vtkIdType neighborId); void UpdateNeighborhood(vtkPolyData* input, vtkIdType pointId); void Propagate(vtkPolyData* input); static double Max(double a, double b) { return a-b > VTK_VMTK_DOUBLE_TOL ? a : b; } static double Min(double a, double b) { return a-b < - VTK_VMTK_DOUBLE_TOL ? a : b; } vtkDoubleArray* TScalars; vtkCharArray* StatusScalars; vtkvmtkMinHeap* ConsideredMinHeap; vtkIdList* Seeds; vtkPolyData* BoundaryPolyData; double Regularization; double StopTravelTime; vtkIdType StopNumberOfPoints; int UnitSpeed; int InitializeFromScalars; char* IntersectedEdgesArrayName; char* InitializationArrayName; char* SolutionArrayName; char* CostFunctionArrayName; int SeedsBoundaryConditions; int PolyDataBoundaryConditions; vtkIdType NumberOfAcceptedPoints; int AllowLineUpdate; int UpdateFromConsidered; private: vtkvmtkNonManifoldFastMarching(const vtkvmtkNonManifoldFastMarching&); // Not implemented. void operator=(const vtkvmtkNonManifoldFastMarching&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBranchUtilities.cxx0000664000175000017500000000630011757446472026051 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBranchUtilities.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataBranchUtilities.h" #include "vtkCleanPolyData.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellArray.h" #include "vtkIdList.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataBranchUtilities, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataBranchUtilities); void vtkvmtkPolyDataBranchUtilities::GetGroupsIdList(vtkPolyData* surface, const char* groupIdsArrayName, vtkIdList* groupIds) { vtkDataArray* groupIdsArray = surface->GetPointData()->GetArray(groupIdsArrayName); int numberOfPoints = surface->GetNumberOfPoints(); groupIds->Initialize(); int maxGroupId = 0; int i; for (i=0; i(groupIdsArray->GetComponent(i,0)); if (groupId > maxGroupId) { maxGroupId = groupId; } } vtkIdList* isGroupList = vtkIdList::New(); isGroupList->SetNumberOfIds(maxGroupId+1); for (i=0; iSetId(i,0); } for (i=0; i(groupIdsArray->GetComponent(i,0)); isGroupList->SetId(groupId,1); } for (i=0; iGetId(i); if (isGroup == 1) { groupIds->InsertNextId(i); } } isGroupList->Delete(); } void vtkvmtkPolyDataBranchUtilities::ExtractGroup(vtkPolyData* surface, const char* groupIdsArrayName, vtkIdType groupId, bool cleanGroupSurface, vtkPolyData* groupSurface) { groupSurface->DeepCopy(surface); int numberOfCells = surface->GetPolys()->GetNumberOfCells(); vtkDataArray* groupIdsArray = surface->GetPointData()->GetArray(groupIdsArrayName); surface->BuildCells(); vtkCellArray* polys = groupSurface->GetPolys(); polys->Reset(); vtkIdType npts, *pts; for (int j=0; jGetCellPoints(j,npts,pts); bool insertCell = true; for (int k=0; k(groupIdsArray->GetComponent(pts[k],0) != groupId)) { insertCell = false; break; } } if (!insertCell) { continue; } polys->InsertNextCell(npts,pts); } polys->Squeeze(); if (cleanGroupSurface) { vtkCleanPolyData* cleaner = vtkCleanPolyData::New(); cleaner->SetInput(groupSurface); cleaner->Update(); groupSurface->DeepCopy(cleaner->GetOutput()); cleaner->Delete(); } } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataLineEmbedder.cxx0000664000175000017500000004252711757446472025312 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataLineEmbedder.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataLineEmbedder, "$Revision: 1.5 $"); 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; iGetNumberOfIds(); 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; iLines->GetCellPoints(cells[i],npts,pts); for (j=0; j0) { neighborPointIds->InsertUniqueId(pts[j-1]); } if (jInsertUniqueId(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; jGetNumberOfIds(); j++) { orderedNeighborIds->InsertNextId(cellPointIds->GetId(j)); orderedNeighborPCoordArray->InsertNextValue(0.0); lastCellPointIdId = orderedNeighborIds->GetNumberOfIds()-1; for (k=0; kGetNumberOfIds(); 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 (pCoordGetValue(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; iCopyData(inputPD,i,i); } snapToMeshIds->SetNumberOfIds(lineNumberOfPoints); embeddedPointIds->SetNumberOfIds(lineNumberOfPoints); for (i=0; i(edgeArray->GetComponent(i,0)); edgePointIds0[1] = static_cast(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; kLines->GetCell(k); if (polyLine->GetCellType() != VTK_LINE && polyLine->GetCellType() != VTK_POLY_LINE) { continue; } for (i=1; iGetNumberOfPoints(); i++) { edgePointIds0[0] = static_cast(edgeArray->GetComponent(polyLine->GetPointId(i-1),0)); edgePointIds0[1] = static_cast(edgeArray->GetComponent(polyLine->GetPointId(i-1),1)); edgePointIds1[0] = static_cast(edgeArray->GetComponent(polyLine->GetPointId(i),0)); edgePointIds1[1] = static_cast(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; iGetNumberOfIds(); i++) { cellId = cellsToRemove->GetId(i); cellPointIds->Initialize(); input->GetCellPoints(cellId,cellPointIds); neighborIds->Initialize(); for (k=0; k(edgeArray->GetComponent(k,0)); edgePointIds0[1] = static_cast(edgeArray->GetComponent(k,1)); for (j=0; jGetNumberOfIds(); 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; jGetNumberOfIds(); 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(edgeArray->GetComponent(i,0)); if (edgePointIds0[0]!=-1) { continue; } neighborIds->Initialize(); this->GetNeighbors(i,neighborIds); cellPointIds->Initialize(); for (j=0; jGetNumberOfIds(); j++) { edgePointIds1[0] = static_cast(edgeArray->GetComponent(neighborIds->GetId(j),0)); edgePointIds1[1] = static_cast(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; jGetNumberOfIds(); 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; iGetNumberOfCells(); 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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlines.cxx0000664000175000017500000005225311757446472025243 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlines.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataCenterlines.h" #include "vtkvmtkConstants.h" #include "vtkPolyDataNormals.h" #include "vtkDelaunay3D.h" #include "vtkvmtkInternalTetrahedraExtractor.h" #include "vtkvmtkVoronoiDiagram3D.h" #include "vtkvmtkSimplifyVoronoiDiagram.h" #include "vtkArrayCalculator.h" #include "vtkvmtkNonManifoldFastMarching.h" #include "vtkvmtkSteepestDescentLineTracer.h" #include "vtkMath.h" #include "vtkPolyData.h" #include "vtkUnstructuredGrid.h" #include "vtkTetra.h" #include "vtkPointData.h" #include "vtkIdList.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlines, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkPolyDataCenterlines); vtkCxxSetObjectMacro(vtkvmtkPolyDataCenterlines,SourceSeedIds,vtkIdList); vtkCxxSetObjectMacro(vtkvmtkPolyDataCenterlines,TargetSeedIds,vtkIdList); vtkCxxSetObjectMacro(vtkvmtkPolyDataCenterlines,CapCenterIds,vtkIdList); vtkvmtkPolyDataCenterlines::vtkvmtkPolyDataCenterlines() { this->SourceSeedIds = NULL; this->TargetSeedIds = NULL; this->CapCenterIds = NULL; this->RadiusArrayName = NULL; this->CostFunction = new char[16]; strcpy(this->CostFunction,"1/R"); this->CostFunctionArrayName = new char[256]; strcpy(this->CostFunctionArrayName,"CostFunctionArray"); this->EikonalSolutionArrayName = new char[256]; strcpy(this->EikonalSolutionArrayName,"EikonalSolutionArray"); this->EdgeArrayName = new char[256]; strcpy(this->EdgeArrayName,"EdgeArray"); this->EdgePCoordArrayName = new char[256]; strcpy(this->EdgePCoordArrayName,"EdgePCoordArray"); this->FlipNormals = 0; this->SimplifyVoronoi = 0; this->CenterlineResampling = 0; this->AppendEndPointsToCenterlines = 0; this->ResamplingStepLength = 1.0; this->GenerateDelaunayTessellation = 1; this->DelaunayTessellation = NULL; this->VoronoiDiagram = vtkPolyData::New(); this->PoleIds = vtkIdList::New(); } vtkvmtkPolyDataCenterlines::~vtkvmtkPolyDataCenterlines() { if (this->SourceSeedIds) { this->SourceSeedIds->Delete(); this->SourceSeedIds = NULL; } if (this->TargetSeedIds) { this->TargetSeedIds->Delete(); this->TargetSeedIds = NULL; } if (this->CapCenterIds) { this->CapCenterIds->Delete(); this->CapCenterIds = NULL; } if (this->CostFunction) { delete[] this->CostFunction; this->CostFunction = NULL; } if (this->CostFunctionArrayName) { delete[] this->CostFunctionArrayName; this->CostFunctionArrayName = NULL; } if (this->EikonalSolutionArrayName) { delete[] this->EikonalSolutionArrayName; this->EikonalSolutionArrayName = NULL; } if (this->EdgeArrayName) { delete[] this->EdgeArrayName; this->EdgeArrayName = NULL; } if (this->EdgePCoordArrayName) { delete[] this->EdgePCoordArrayName; this->EdgePCoordArrayName = NULL; } if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->DelaunayTessellation) { this->DelaunayTessellation->Delete(); this->DelaunayTessellation = NULL; } this->VoronoiDiagram->Delete(); this->VoronoiDiagram = NULL; this->PoleIds->Delete(); this->PoleIds = NULL; } int vtkvmtkPolyDataCenterlines::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->SourceSeedIds) { vtkErrorMacro(<< "No SourceSeedIds set."); return 1; } if (!this->TargetSeedIds) { vtkErrorMacro(<< "No TargetSeedIds set."); return 1; } if (!this->RadiusArrayName) { vtkErrorMacro(<< "No RadiusArrayName set."); return 1; } if (!this->GenerateDelaunayTessellation && !this->DelaunayTessellation) { vtkErrorMacro(<< "GenerateDelaunayTessellation is off but a DelaunayTessellation has not been set."); return 1; } vtkPolyDataNormals* surfaceNormals = vtkPolyDataNormals::New(); surfaceNormals->SetInput(input); surfaceNormals->SplittingOff(); surfaceNormals->AutoOrientNormalsOn(); surfaceNormals->SetFlipNormals(this->FlipNormals); surfaceNormals->ComputePointNormalsOn(); surfaceNormals->ConsistencyOn(); surfaceNormals->Update(); if (this->GenerateDelaunayTessellation) { vtkDelaunay3D* delaunayTessellator = vtkDelaunay3D::New(); delaunayTessellator->CreateDefaultLocator(); delaunayTessellator->SetInput(surfaceNormals->GetOutput()); delaunayTessellator->Update(); vtkUnstructuredGrid* delaunay = delaunayTessellator->GetOutput(); delaunay->GetPointData()->AddArray(surfaceNormals->GetOutput()->GetPointData()->GetNormals()); vtkvmtkInternalTetrahedraExtractor* internalTetrahedraExtractor = vtkvmtkInternalTetrahedraExtractor::New(); internalTetrahedraExtractor->SetInput(delaunayTessellator->GetOutput()); internalTetrahedraExtractor->SetOutwardNormalsArrayName(surfaceNormals->GetOutput()->GetPointData()->GetNormals()->GetName()); if (this->CapCenterIds) { internalTetrahedraExtractor->UseCapsOn(); internalTetrahedraExtractor->SetCapCenterIds(this->CapCenterIds); } internalTetrahedraExtractor->Update(); this->DelaunayTessellation = internalTetrahedraExtractor->GetOutput(); this->DelaunayTessellation->Register(this); delaunayTessellator->Delete(); internalTetrahedraExtractor->Delete(); } vtkvmtkVoronoiDiagram3D* voronoiDiagramFilter = vtkvmtkVoronoiDiagram3D::New(); voronoiDiagramFilter->SetInput(this->DelaunayTessellation); voronoiDiagramFilter->SetRadiusArrayName(this->RadiusArrayName); voronoiDiagramFilter->Update(); this->PoleIds->DeepCopy(voronoiDiagramFilter->GetPoleIds()); vtkPolyData* voronoiDiagram = voronoiDiagramFilter->GetOutput(); if (this->SimplifyVoronoi) { vtkvmtkSimplifyVoronoiDiagram* voronoiDiagramSimplifier = vtkvmtkSimplifyVoronoiDiagram::New(); voronoiDiagramSimplifier->SetInput(voronoiDiagramFilter->GetOutput()); voronoiDiagramSimplifier->SetUnremovablePointIds(voronoiDiagramFilter->GetPoleIds()); voronoiDiagramSimplifier->Update(); voronoiDiagram = voronoiDiagramSimplifier->GetOutput(); voronoiDiagram->Register(this); voronoiDiagramSimplifier->Delete(); } vtkArrayCalculator* voronoiCostFunctionCalculator = vtkArrayCalculator::New(); voronoiCostFunctionCalculator->SetInput(voronoiDiagram); voronoiCostFunctionCalculator->SetAttributeModeToUsePointData(); voronoiCostFunctionCalculator->AddScalarVariable("R",this->RadiusArrayName,0); voronoiCostFunctionCalculator->SetFunction(this->CostFunction); voronoiCostFunctionCalculator->SetResultArrayName(this->CostFunctionArrayName); voronoiCostFunctionCalculator->Update(); vtkIdList* voronoiSourceSeedIds = vtkIdList::New(); vtkIdList* voronoiTargetSeedIds = vtkIdList::New(); vtkIdList* voronoiSeeds = vtkIdList::New(); int i; if (this->CapCenterIds) { this->FindVoronoiSeeds(this->DelaunayTessellation,this->CapCenterIds,surfaceNormals->GetOutput()->GetPointData()->GetNormals(),voronoiSeeds); for (i=0; iSourceSeedIds->GetNumberOfIds(); i++) { voronoiSourceSeedIds->InsertNextId(voronoiSeeds->GetId(this->SourceSeedIds->GetId(i))); } for (i=0; iTargetSeedIds->GetNumberOfIds(); i++) { voronoiTargetSeedIds->InsertNextId(voronoiSeeds->GetId(this->TargetSeedIds->GetId(i))); } } else { for (i=0; iSourceSeedIds->GetNumberOfIds(); i++) { voronoiSourceSeedIds->InsertNextId(this->PoleIds->GetId(this->SourceSeedIds->GetId(i))); } for (i=0; iTargetSeedIds->GetNumberOfIds(); i++) { voronoiTargetSeedIds->InsertNextId(this->PoleIds->GetId(this->TargetSeedIds->GetId(i))); } } vtkvmtkNonManifoldFastMarching* voronoiFastMarching = vtkvmtkNonManifoldFastMarching::New(); voronoiFastMarching->SetInput(vtkPolyData::SafeDownCast(voronoiCostFunctionCalculator->GetOutput())); voronoiFastMarching->SetCostFunctionArrayName(this->CostFunctionArrayName); voronoiFastMarching->SetSolutionArrayName(this->EikonalSolutionArrayName); voronoiFastMarching->SeedsBoundaryConditionsOn(); voronoiFastMarching->SetSeeds(voronoiSourceSeedIds); voronoiFastMarching->Update(); this->VoronoiDiagram->ShallowCopy(voronoiFastMarching->GetOutput()); this->VoronoiDiagram->Update(); vtkvmtkSteepestDescentLineTracer* centerlineBacktracing = vtkvmtkSteepestDescentLineTracer::New(); centerlineBacktracing->SetInput(voronoiFastMarching->GetOutput()); centerlineBacktracing->SetDataArrayName(this->RadiusArrayName); centerlineBacktracing->SetDescentArrayName(this->EikonalSolutionArrayName); centerlineBacktracing->SetEdgeArrayName(this->EdgeArrayName); centerlineBacktracing->SetEdgePCoordArrayName(this->EdgePCoordArrayName); centerlineBacktracing->SetSeeds(voronoiTargetSeedIds); centerlineBacktracing->MergePathsOff(); centerlineBacktracing->StopOnTargetsOn(); centerlineBacktracing->SetTargets(voronoiSourceSeedIds); centerlineBacktracing->Update(); output->ShallowCopy(centerlineBacktracing->GetOutput()); vtkIdList* hitTargets = centerlineBacktracing->GetHitTargets(); vtkPoints* endPointPairs = vtkPoints::New(); if (this->AppendEndPointsToCenterlines) { for (i=0; iTargetSeedIds->GetNumberOfIds(); i++) { if (this->CapCenterIds) { vtkIdType endPointId1 = this->CapCenterIds->GetId(this->TargetSeedIds->GetId(i)); vtkIdType hitTargetPointId = hitTargets->GetId(i); vtkIdType targetId = voronoiSourceSeedIds->IsId(hitTargetPointId); vtkIdType endPointId2 = this->CapCenterIds->GetId(this->SourceSeedIds->GetId(targetId)); endPointPairs->InsertNextPoint(input->GetPoint(endPointId1)); endPointPairs->InsertNextPoint(input->GetPoint(endPointId2)); } else { vtkIdType endPointId1 = this->TargetSeedIds->GetId(i); vtkIdType hitTargetPointId = hitTargets->GetId(i); vtkIdType targetId = voronoiSourceSeedIds->IsId(hitTargetPointId); vtkIdType endPointId2 = this->SourceSeedIds->GetId(targetId); endPointPairs->InsertNextPoint(input->GetPoint(endPointId1)); endPointPairs->InsertNextPoint(input->GetPoint(endPointId2)); } } this->AppendEndPoints(endPointPairs); } if (this->CenterlineResampling) { this->ResampleCenterlines(); } this->ReverseCenterlines(); surfaceNormals->Delete(); voronoiDiagramFilter->Delete(); voronoiCostFunctionCalculator->Delete(); voronoiSeeds->Delete(); voronoiSourceSeedIds->Delete(); voronoiTargetSeedIds->Delete(); voronoiFastMarching->Delete(); centerlineBacktracing->Delete(); endPointPairs->Delete(); return 1; } void vtkvmtkPolyDataCenterlines::FindVoronoiSeeds(vtkUnstructuredGrid *delaunay, vtkIdList *boundaryBaricenterIds, vtkDataArray *normals, vtkIdList *seedIds) { vtkIdType i, j; vtkIdList *pointCells; vtkIdType baricenterId; double baricenter[3], normal[3]; double maxRadius, secondMaxRadius; vtkTetra* tetra; double p0[3], p1[3], p2[3], p3[3]; double circumcenter[3], circumradius, tetraRadius; double referenceVector[3]; double pole[3], poleVector[3], secondPole[3], secondPoleVector[3]; pole[0] = pole[1] = pole[2] = 0.0; vtkIdType maxRadiusCellId, secondMaxRadiusCellId; pointCells = vtkIdList::New(); for (i=0; iGetNumberOfIds(); i++) { baricenterId = boundaryBaricenterIds->GetId(i); delaunay->GetPoint(baricenterId,baricenter); normals->GetTuple(baricenterId,normal); pointCells->Initialize(); delaunay->GetPointCells(baricenterId,pointCells); maxRadius = 0.0; maxRadiusCellId = -1; secondMaxRadiusCellId = -1; for (j=0; jGetNumberOfIds(); j++) { tetra = vtkTetra::SafeDownCast(delaunay->GetCell(pointCells->GetId(j))); tetra->GetPoints()->GetPoint(0,p0); tetra->GetPoints()->GetPoint(1,p1); tetra->GetPoints()->GetPoint(2,p2); tetra->GetPoints()->GetPoint(3,p3); circumradius = vtkTetra::Circumsphere(p0,p1,p2,p3,circumcenter); tetraRadius = sqrt(circumradius); if (tetraRadius - maxRadius > VTK_VMTK_DOUBLE_TOL) { maxRadius = tetraRadius; maxRadiusCellId = pointCells->GetId(j); pole[0] = circumcenter[0]; pole[1] = circumcenter[1]; pole[2] = circumcenter[2]; } } poleVector[0] = pole[0] - baricenter[0]; poleVector[1] = pole[1] - baricenter[1]; poleVector[2] = pole[2] - baricenter[2]; secondMaxRadius = 0.0; for (j=0; jGetNumberOfIds(); j++) { tetra = vtkTetra::SafeDownCast(delaunay->GetCell(pointCells->GetId(j))); tetra->GetPoints()->GetPoint(0,p0); tetra->GetPoints()->GetPoint(1,p1); tetra->GetPoints()->GetPoint(2,p2); tetra->GetPoints()->GetPoint(3,p3); circumradius = vtkTetra::Circumsphere(p0,p1,p2,p3,circumcenter); tetraRadius = sqrt(circumradius); referenceVector[0] = circumcenter[0] - baricenter[0]; referenceVector[1] = circumcenter[1] - baricenter[1]; referenceVector[2] = circumcenter[2] - baricenter[2]; if ((tetraRadius - secondMaxRadius > VTK_VMTK_DOUBLE_TOL) && (vtkMath::Dot(poleVector,referenceVector) < VTK_VMTK_DOUBLE_TOL)) { secondMaxRadius = tetraRadius; secondMaxRadiusCellId = pointCells->GetId(j); secondPole[0] = circumcenter[0]; secondPole[1] = circumcenter[1]; secondPole[2] = circumcenter[2]; } } secondPoleVector[0] = secondPole[0] - baricenter[0]; secondPoleVector[1] = secondPole[1] - baricenter[1]; secondPoleVector[2] = secondPole[2] - baricenter[2]; if (vtkMath::Dot(poleVector,normal) < VTK_VMTK_DOUBLE_TOL) { seedIds->InsertNextId(maxRadiusCellId); } else { seedIds->InsertNextId(secondMaxRadiusCellId); } } pointCells->Delete(); } void vtkvmtkPolyDataCenterlines::AppendEndPoints(vtkPoints* endPointPairs) { vtkIdType endPointId1, endPointId2; vtkPolyData* output = this->GetOutput(); vtkPolyData* completeCenterlines = vtkPolyData::New(); vtkPoints* completeCenterlinesPoints = vtkPoints::New(); vtkCellArray* completeCenterlinesCellArray = vtkCellArray::New(); vtkDoubleArray* completeCenterlinesRadiusArray = vtkDoubleArray::New(); completeCenterlinesRadiusArray->SetName(this->RadiusArrayName); vtkIdList* completeCell = vtkIdList::New(); vtkDoubleArray* centerlinesRadiusArray = vtkDoubleArray::SafeDownCast(output->GetPointData()->GetArray(this->RadiusArrayName)); completeCenterlinesPoints->DeepCopy(output->GetPoints()); completeCenterlinesRadiusArray->DeepCopy(centerlinesRadiusArray); for (int k=0; kGetNumberOfCells(); k++) { vtkCell* cell = output->GetCell(k); endPointId1 = completeCenterlinesPoints->InsertNextPoint(endPointPairs->GetPoint(2*k)); endPointId2 = completeCenterlinesPoints->InsertNextPoint(endPointPairs->GetPoint(2*k+1)); completeCell->Initialize(); completeCell->SetNumberOfIds(cell->GetNumberOfPoints()+2); completeCell->SetId(0,endPointId1); for (int i=0; iGetNumberOfPoints(); i++) { completeCell->SetId(i+1,cell->GetPointId(i)); } completeCell->SetId(cell->GetNumberOfPoints()+1,endPointId2); completeCenterlinesCellArray->InsertNextCell(completeCell); completeCenterlinesRadiusArray->InsertNextValue(centerlinesRadiusArray->GetValue(cell->GetPointId(0))); completeCenterlinesRadiusArray->InsertNextValue(centerlinesRadiusArray->GetValue(cell->GetPointId(cell->GetNumberOfPoints()-1))); } completeCenterlines->SetPoints(completeCenterlinesPoints); completeCenterlines->SetLines(completeCenterlinesCellArray); completeCenterlines->GetPointData()->AddArray(completeCenterlinesRadiusArray); completeCenterlines->Update(); output->ShallowCopy(completeCenterlines); completeCell->Delete(); completeCenterlines->Delete(); completeCenterlinesPoints->Delete(); completeCenterlinesCellArray->Delete(); completeCenterlinesRadiusArray->Delete(); } void vtkvmtkPolyDataCenterlines::ResampleCenterlines() { vtkPolyData* output = this->GetOutput(); vtkPolyData* resampledCenterlines = vtkPolyData::New(); vtkPoints* resampledCenterlinesPoints = vtkPoints::New(); vtkCellArray* resampledCenterlinesCellArray = vtkCellArray::New(); vtkDoubleArray* resampledCenterlinesRadiusArray = vtkDoubleArray::New(); resampledCenterlinesRadiusArray->SetName(this->RadiusArrayName); vtkIdList* resampledCell = vtkIdList::New(); vtkDoubleArray* centerlinesRadiusArray = vtkDoubleArray::SafeDownCast(output->GetPointData()->GetArray(this->RadiusArrayName)); for (int k=0; kGetNumberOfCells(); k++) { vtkCell* cell = output->GetCell(k); resampledCell->Initialize(); vtkIdType id = resampledCenterlinesPoints->InsertNextPoint(cell->GetPoints()->GetPoint(0)); resampledCell->InsertNextId(id); resampledCenterlinesRadiusArray->InsertNextValue(centerlinesRadiusArray->GetValue(cell->GetPointId(0))); double point0[3], point1[3], point[3]; double abscissa, lineAbscissa, lineLength, stepAbscissa; abscissa = 0.0; lineAbscissa = 0.0; lineLength = 0.0; stepAbscissa = 0.0; for (int i=0; iGetNumberOfPoints()-1; i++) { cell->GetPoints()->GetPoint(i,point0); cell->GetPoints()->GetPoint(i+1,point1); double scalar0 = centerlinesRadiusArray->GetValue(cell->GetPointId(i)); double scalar1 = centerlinesRadiusArray->GetValue(cell->GetPointId(i+1)); double length = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); if (length < this->ResamplingStepLength - stepAbscissa) { stepAbscissa = stepAbscissa + length; continue; } double pcoord = 0.0; double pcoordStep = this->ResamplingStepLength / length; while (pcoord < 1.0) { point[0] = point0[0] + (point1[0] - point0[0]) * pcoord; point[1] = point0[1] + (point1[1] - point0[1]) * pcoord; point[2] = point0[2] + (point1[2] - point0[2]) * pcoord; double scalar = scalar0 + (scalar1 - scalar0) * pcoord; vtkIdType id = resampledCenterlinesPoints->InsertNextPoint(point); resampledCell->InsertNextId(id); resampledCenterlinesRadiusArray->InsertNextValue(scalar); if (pcoord + pcoordStep > 1.0) { break; } pcoord = pcoord + pcoordStep; } stepAbscissa = (1.0 - pcoord) * length; } id = resampledCenterlinesPoints->InsertNextPoint(cell->GetPoints()->GetPoint(cell->GetNumberOfPoints()-1)); resampledCell->InsertNextId(id); resampledCenterlinesRadiusArray->InsertNextValue(centerlinesRadiusArray->GetValue(cell->GetPointId(cell->GetNumberOfPoints()-1))); resampledCenterlinesCellArray->InsertNextCell(resampledCell); } resampledCenterlines->SetPoints(resampledCenterlinesPoints); resampledCenterlines->SetLines(resampledCenterlinesCellArray); resampledCenterlines->GetPointData()->AddArray(resampledCenterlinesRadiusArray); resampledCenterlines->Update(); output->ShallowCopy(resampledCenterlines); resampledCenterlines->Delete(); resampledCenterlinesPoints->Delete(); resampledCenterlinesCellArray->Delete(); resampledCenterlinesRadiusArray->Delete(); resampledCell->Delete(); } void vtkvmtkPolyDataCenterlines::ReverseCenterlines() { vtkPolyData* output = this->GetOutput(); vtkCellArray* reversedCenterlinesCellArray = vtkCellArray::New(); vtkIdList* reversedCell = vtkIdList::New(); for (int k=0; kGetNumberOfCells(); k++) { vtkCell* cell = output->GetCell(k); reversedCell->Initialize(); vtkIdType numberOfCellPoints = cell->GetNumberOfPoints(); for (int i=0; iGetPointId(numberOfCellPoints-1-i); reversedCell->InsertNextId(id); } reversedCenterlinesCellArray->InsertNextCell(reversedCell); } output->SetLines(reversedCenterlinesCellArray); reversedCell->Delete(); reversedCenterlinesCellArray->Delete(); } void vtkvmtkPolyDataCenterlines::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCapPolyData.h0000664000175000017500000000562311757446472023117 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCapPolyData.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCapPolyData - Add caps to boundaries. // .SECTION Description // This class closes the boundaries of a surface with a cap. Each cap is made of triangles sharing the boundary baricenter. Boundary baricenters are added to the dataset. It is possible to retrieve the ids of the added points with GetCapCenterIds. Boundary baricenters can be displaced along boundary normals through the Displacement parameter. Since this class is used as a preprocessing step for Delaunay tessellation, displacement is meant to avoid the occurence of degenerate tetrahedra on the caps. #ifndef __vtkvmtkCapPolyData_h #define __vtkvmtkCapPolyData_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" #include "vtkPoints.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCapPolyData : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCapPolyData,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCapPolyData *New(); // Description: // Set/Get the ids of the boundaries to cap. vtkSetObjectMacro(BoundaryIds,vtkIdList); vtkGetObjectMacro(BoundaryIds,vtkIdList); // Description: // Set/Get the displacement of boundary baricenters along boundary normals relative to the radius. vtkSetMacro(Displacement,double); vtkGetMacro(Displacement,double); // Description: // Set/Get the displacement of boundary baricenters on the section plane relative to the radius. vtkSetMacro(InPlaneDisplacement,double); vtkGetMacro(InPlaneDisplacement,double); // Description: // Get the ids of the newly inserted boundary baricenters. vtkGetObjectMacro(CapCenterIds,vtkIdList); protected: vtkvmtkCapPolyData(); ~vtkvmtkCapPolyData(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdList* BoundaryIds; double Displacement; double InPlaneDisplacement; vtkIdList* CapCenterIds; private: vtkvmtkCapPolyData(const vtkvmtkCapPolyData&); // Not implemented. void operator=(const vtkvmtkCapPolyData&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineProjection.h0000664000175000017500000000420011757446472026527 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineProjection.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCenterlineProjection - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataCenterlineProjection_h #define __vtkvmtkPolyDataCenterlineProjection_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlineProjection : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataCenterlineProjection* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataCenterlineProjection,vtkPolyDataAlgorithm); vtkSetObjectMacro(Centerlines,vtkPolyData); vtkGetObjectMacro(Centerlines,vtkPolyData); vtkSetMacro(UseRadiusInformation,int); vtkGetMacro(UseRadiusInformation,int); vtkBooleanMacro(UseRadiusInformation,int); vtkSetStringMacro(CenterlineRadiusArrayName); vtkGetStringMacro(CenterlineRadiusArrayName); protected: vtkvmtkPolyDataCenterlineProjection(); ~vtkvmtkPolyDataCenterlineProjection(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* CenterlineRadiusArrayName; vtkPolyData* Centerlines; int UseRadiusInformation; private: vtkvmtkPolyDataCenterlineProjection(const vtkvmtkPolyDataCenterlineProjection&); // Not implemented. void operator=(const vtkvmtkPolyDataCenterlineProjection&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkSteepestDescentLineTracer.h0000664000175000017500000001431611757446472026030 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSteepestDescentLineTracer.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSteepestDescentLineTracer - Trace the steepest descent line over a polygonal non-manifold. // .SECTION Description // This class takes in input a non-manifold surface made of convex polygons (such as a Voronoi diagram) on which a scalar field is defined (as a point data array) and produces steepest descent paths from an id list of seeds to a target, basically solving the ordinary differential equation // \f[\frac{d\gamma(\tau)}{d\tau}=-\nabla T(\mathbf{x})\f] // where \f$\gamma(\tau)\f$ is a path and T(x) is a scalar field defined over the polygonal non-manifold domain. // // The class uses the members of its base class vtkNonManifoldSteepestDescent to compute the steepest descent point at each step. // The computed paths are polylines whose points always lie on input polygon edges. // // This class is meant to be used for backtracing centerlines after solving the Eikonal equation on the Voronoi diagram of a shape (by means of vtkNonManifoldFastMarching). If MergePaths is off, one polyline for each seed point is produced (the cell id of each polyline corresponds to the list id of input seeds). If MergePaths is on, polylines are merged if they intersect the same Voronoi diagram edge and their distance is below a user-defined tolerance. Actually, if a path visits an edge which has already been visited by a previous path, its endpoint is set to the previous path point, so that a T junction is produced. // // The user can specify a point data array whose values are interpolated on path points and presented in output as point data. // // If 1) EdgeArrayName and/or 2) EdgePCoordArrayName are provided, the output will contain 1) a 2-component vtkIntArray in which the point ids of the edges intersected by the paths are stored and 2) a 1-component vtkDoubleArray in which the parametric coordinate of the intersection is stored. // // .SECTION See Also // vtkNonManifoldFastMarching vtkVoronoiDiagram3D #ifndef __vtkvmtkSteepestDescentLineTracer_h #define __vtkvmtkSteepestDescentLineTracer_h #include "vtkvmtkNonManifoldSteepestDescent.h" #include "vtkIntArray.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkSteepestDescentLineTracer : public vtkvmtkNonManifoldSteepestDescent { public: vtkTypeRevisionMacro(vtkvmtkSteepestDescentLineTracer,vtkvmtkNonManifoldSteepestDescent); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSteepestDescentLineTracer *New(); // Description: // Set/Get the id of the seeds from which steepest descent starts. vtkSetObjectMacro(Seeds,vtkIdList); vtkGetObjectMacro(Seeds,vtkIdList); // Description: // Set/Get the id of the point on which steepest descent must terminate. vtkSetObjectMacro(Targets,vtkIdList); vtkGetObjectMacro(Targets,vtkIdList); // Description: // Set/Get the id of the point on which steepest descent has terminated for each seed point. vtkGetObjectMacro(HitTargets,vtkIdList); vtkSetMacro(StopOnTargets,int) vtkGetMacro(StopOnTargets,int) vtkBooleanMacro(StopOnTargets,int) // Description: // Set/Get the name of the point data array from which path point data is generated. vtkSetStringMacro(DataArrayName); vtkGetStringMacro(DataArrayName); // Description: // Set/Get the name of output point data array where the point ids of the edges intersected by the paths are going to be stored. vtkSetStringMacro(EdgeArrayName); vtkGetStringMacro(EdgeArrayName); // Description: // Set/Get the name of output point data array where the parametric coordinate of the intersection point with input edges are going to be stored. vtkSetStringMacro(EdgePCoordArrayName); vtkGetStringMacro(EdgePCoordArrayName); // Description: // Turn on/off merging paths if they intersect the same Voronoi edge. Paths are merged with T junctions in the same order as defined in the seed list. vtkSetMacro(MergePaths,int); vtkGetMacro(MergePaths,int); vtkBooleanMacro(MergePaths,int); // Description: // Set/Get the (absolute) tolerance with which two points intersecting the same Voronoi diagram edge are considered coincident. If set to a large value, two paths are merged if they intersect the same Voronoi diagram edge (default behaviour). vtkSetMacro(MergeTolerance,double); vtkGetMacro(MergeTolerance,double); protected: vtkvmtkSteepestDescentLineTracer(); ~vtkvmtkSteepestDescentLineTracer(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void Backtrace(vtkPolyData* input, vtkIdType seedId); vtkIdList* Seeds; vtkIdList* Targets; vtkIdList* HitTargets; int StopOnTargets; char* DataArrayName; char* EdgeArrayName; char* EdgePCoordArrayName; char* MinDistanceArrayName; int MergePaths; double MergeTolerance; vtkIntArray* Edges; vtkDoubleArray* EdgeParCoords; vtkIdList* EdgePointIds; vtkIntArray* CellIdsArray; vtkDoubleArray* PCoordsArray; vtkDoubleArray* MinDistanceArray; vtkDataArray* LineDataArray; int MergeWithExistingPaths; vtkPolyData* ExistingPaths; char* ExistingPathsEdgeArrayName; char* ExistingPathsEdgePCoordArrayName; vtkIntArray* ExistingPathsEdges; vtkDoubleArray* ExistingPathsEdgeParCoords; private: vtkvmtkSteepestDescentLineTracer(const vtkvmtkSteepestDescentLineTracer&); // Not implemented. void operator=(const vtkvmtkSteepestDescentLineTracer&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkSteepestDescentShooter.cxx0000664000175000017500000002251111757446472025772 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSteepestDescentShooter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSteepestDescentShooter.h" #include "vtkPolyLine.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkLine.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkSteepestDescentShooter, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkSteepestDescentShooter); vtkvmtkSteepestDescentShooter::vtkvmtkSteepestDescentShooter() { this->Seeds = NULL; this->Target = NULL; this->EdgeArrayName = NULL; this->TargetVectorsArrayName = NULL; this->TargetCellIdsArrayName = NULL; this->TargetPCoordsArrayName = NULL; this->TargetVectors = vtkDoubleArray::New(); this->TargetCellIds = vtkIntArray::New(); this->TargetPCoords = vtkDoubleArray::New(); this->TargetArray = vtkIntArray::New(); } vtkvmtkSteepestDescentShooter::~vtkvmtkSteepestDescentShooter() { this->TargetVectors->Delete(); this->TargetCellIds->Delete(); this->TargetPCoords->Delete(); this->TargetArray->Delete(); if (this->Seeds) { this->Seeds->Delete(); this->Seeds = NULL; } if (this->Target) { this->Target->Delete(); this->Target = NULL; } } void vtkvmtkSteepestDescentShooter::FindNearestPolyLinePoint(double* currentPoint, double* lineClosestPoint, int &lineCellId, int &lineCellSubId, double &linePCoord) { vtkIdType i; int subId; double closestPoint[3]; double parCoords[3]; double dist2, minDist2; double* weights; vtkPolyLine* polyLine; minDist2 = VTK_VMTK_LARGE_DOUBLE; for (i=0; iTarget->GetNumberOfCells(); i++) { polyLine = vtkPolyLine::SafeDownCast(this->Target->GetCell(i)); if (!polyLine) { continue; } weights = new double[polyLine->GetNumberOfPoints()]; polyLine->EvaluatePosition(currentPoint,closestPoint,subId,parCoords,dist2,weights); if (dist2 - minDist2 < -VTK_VMTK_DOUBLE_TOL) { minDist2 = dist2; lineCellId = i; lineCellSubId = subId; linePCoord = parCoords[0]; lineClosestPoint[0] = closestPoint[0]; lineClosestPoint[1] = closestPoint[1]; lineClosestPoint[2] = closestPoint[2]; } delete weights; } } void vtkvmtkSteepestDescentShooter::Backtrace(vtkPolyData* input, vtkIdType seedId) { bool done; double seedPoint[3]; double currentPoint[3], currentScalar; double currentS; vtkIdType currentEdge[2], steepestDescentEdge[2]; double steepestDescentS; double previousPoint[3], lineClosestPoint[3]; double vector[3]; int lineCellId, lineCellSubId; double linePCoord; done = false; input->GetPoint(seedId,seedPoint); currentPoint[0] = seedPoint[0]; currentPoint[1] = seedPoint[1]; currentPoint[2] = seedPoint[2]; previousPoint[0] = seedPoint[0]; previousPoint[1] = seedPoint[1]; previousPoint[2] = seedPoint[2]; currentScalar = this->DescentArray->GetTuple1(seedId); currentEdge[0] = seedId; currentEdge[1] = seedId; currentS = 0.0; while (!done) { if (((this->TargetArray->GetValue(currentEdge[0])!=-1) && (this->TargetArray->GetValue(currentEdge[1])!=-1))) { this->FindNearestPolyLinePoint(currentPoint, lineClosestPoint, lineCellId, lineCellSubId, linePCoord); vector[0] = lineClosestPoint[0] - seedPoint[0]; vector[1] = lineClosestPoint[1] - seedPoint[1]; vector[2] = lineClosestPoint[2] - seedPoint[2]; this->TargetVectors->SetTuple(seedId,vector); this->TargetCellIds->SetComponent(seedId,0,lineCellId); this->TargetCellIds->SetComponent(seedId,1,lineCellSubId); this->TargetPCoords->SetTuple1(seedId,linePCoord); done = true; break; } if (currentScalar==0.0) { // THIS MEANS THERE'S SOMETHING WRONG SOMEWHERE! done = true; break; } this->GetSteepestDescent(input,currentEdge,currentS,steepestDescentEdge,steepestDescentS); currentEdge[0] = steepestDescentEdge[0]; currentEdge[1] = steepestDescentEdge[1]; currentS = steepestDescentS; previousPoint[0] = currentPoint[0]; previousPoint[1] = currentPoint[1]; previousPoint[2] = currentPoint[2]; currentPoint[0] = input->GetPoint(currentEdge[0])[0] * (1.0 - currentS) + input->GetPoint(currentEdge[1])[0] * currentS; currentPoint[1] = input->GetPoint(currentEdge[0])[1] * (1.0 - currentS) + input->GetPoint(currentEdge[1])[1] * currentS; currentPoint[2] = input->GetPoint(currentEdge[0])[2] * (1.0 - currentS) + input->GetPoint(currentEdge[1])[2] * currentS; currentScalar = this->DescentArray->GetTuple1(currentEdge[0]) * (1.0 - currentS) + this->DescentArray->GetTuple1(currentEdge[1]) * currentS; } } int vtkvmtkSteepestDescentShooter::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, h, l, m; vtkIdType poleId; vtkIdType npts, *pts, targetNpts, *targetPts, *cells; unsigned short ncells; if (!this->DescentArrayName) { vtkErrorMacro("Descent array name not specified."); return 1; } if (!input->GetPointData()->GetArray(this->DescentArrayName)) { vtkErrorMacro(<< "Descent array with name specified does not exist!"); return 1; } if (!this->Seeds) { vtkErrorMacro(<< "No seeds specified!"); return 1; } if (!this->Target) { vtkErrorMacro(<< "No target specified!"); return 1; } if (!this->EdgeArrayName) { vtkErrorMacro(<< "No edge array name specified!"); return 1; } if (!this->Target->GetPointData()->GetArray(this->EdgeArrayName)) { vtkErrorMacro(<< "Edge array with name specified does not exist in target!"); return 1; } if (this->TargetVectorsArrayName) { this->TargetVectors->SetName(TargetVectorsArrayName); } else { this->TargetVectors->SetName("TargetVectors"); } if (this->TargetCellIdsArrayName) { this->TargetCellIds->SetName(TargetCellIdsArrayName); } else { this->TargetCellIds->SetName("TargetCellIds"); } if (this->TargetPCoordsArrayName) { this->TargetPCoords->SetName(TargetPCoordsArrayName); } else { this->TargetPCoords->SetName("TargetPCoords"); } this->DescentArray = input->GetPointData()->GetArray(this->DescentArrayName); this->EdgeArray = this->Target->GetPointData()->GetArray(this->EdgeArrayName); this->TargetVectors->SetNumberOfComponents(3); this->TargetCellIds->SetNumberOfComponents(2); this->TargetVectors->SetNumberOfTuples(input->GetNumberOfPoints()); this->TargetCellIds->SetNumberOfTuples(input->GetNumberOfPoints()); this->TargetPCoords->SetNumberOfTuples(input->GetNumberOfPoints()); this->TargetVectors->FillComponent(0,0.0); this->TargetVectors->FillComponent(1,0.0); this->TargetVectors->FillComponent(2,0.0); this->TargetCellIds->FillComponent(0,0.0); this->TargetCellIds->FillComponent(1,0.0); this->TargetPCoords->FillComponent(0,0.0); input->BuildCells(); input->BuildLinks(); this->TargetArray->SetNumberOfTuples(input->GetNumberOfPoints()); this->TargetArray->FillComponent(0,-1); this->Target->BuildCells(); for (h=this->Target->GetNumberOfCells()-1; h>=0; h--) { this->Target->GetCellPoints(h,targetNpts,targetPts); for (l=0; lGetPointCells(static_cast(this->EdgeArray->GetComponent(targetPts[l],m)),ncells,cells); for (j=0; jGetCellPoints(cells[j],npts,pts); for (k=0; kTargetArray->SetValue(pts[k],h); } } } } } for (i=0; iSeeds->GetNumberOfIds(); i++) { poleId = this->Seeds->GetId(i); this->Backtrace(input,poleId); } output->CopyStructure(input); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); output->GetPointData()->AddArray(this->TargetVectors); output->GetPointData()->AddArray(this->TargetCellIds); output->GetPointData()->AddArray(this->TargetPCoords); return 1; } void vtkvmtkSteepestDescentShooter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/CMakeLists.txt0000664000175000017500000001405511757446472021715 0ustar lucalucaSET (VTK_VMTK_COMPUTATIONALGEOMETRY_SRCS vtkvmtkAppendFilter.cxx vtkvmtkCapPolyData.cxx vtkvmtkCenterlineAttributesFilter.cxx vtkvmtkCenterlineBifurcationVectors.cxx vtkvmtkCenterlineBifurcationReferenceSystems.cxx vtkvmtkCenterlineBranchExtractor.cxx vtkvmtkCenterlineBranchGeometry.cxx vtkvmtkCenterlineEndpointExtractor.cxx vtkvmtkCenterlineGeometry.cxx vtkvmtkCenterlineReferenceSystemAttributesOffset.cxx vtkvmtkCenterlineSmoothing.cxx vtkvmtkCenterlineSphereDistance.cxx vtkvmtkCenterlineSplitExtractor.cxx vtkvmtkCenterlineSplittingAndGroupingFilter.cxx vtkvmtkCenterlineUtilities.cxx vtkvmtkBoundaryReferenceSystems.cxx vtkvmtkInternalTetrahedraExtractor.cxx vtkvmtkMergeCenterlines.cxx vtkvmtkMinHeap.cxx vtkvmtkNonManifoldFastMarching.cxx vtkvmtkNonManifoldSteepestDescent.cxx vtkvmtkPolyBall.cxx vtkvmtkPolyBallLine.cxx vtkvmtkPolyBallModeller.cxx vtkvmtkPolyDataBifurcationSections.cxx vtkvmtkPolyDataBifurcationProfiles.cxx vtkvmtkPolyDataBoundaryExtractor.cxx vtkvmtkPolyDataBranchSections.cxx vtkvmtkPolyDataBranchUtilities.cxx vtkvmtkPolyDataCenterlines.cxx vtkvmtkPolyDataCenterlineGroupsClipper.cxx vtkvmtkPolyDataCenterlineAbscissaMetricFilter.cxx vtkvmtkPolyDataCenterlineAngularMetricFilter.cxx vtkvmtkPolyDataCenterlineMetricFilter.cxx vtkvmtkPolyDataCenterlineProjection.cxx vtkvmtkPolyDataCenterlineSections.cxx vtkvmtkPolyDataFlowExtensionsFilter.cxx vtkvmtkPolyDataDistanceToCenterlines.cxx vtkvmtkPolyDataLineEmbedder.cxx vtkvmtkPolyDataLocalGeometry.cxx vtkvmtkPolyDataPatchingFilter.cxx vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter.cxx vtkvmtkPolyDataScissors.cxx vtkvmtkPolyDataStretchMappingFilter.cxx vtkvmtkReferenceSystemUtilities.cxx vtkvmtkSimplifyVoronoiDiagram.cxx vtkvmtkSteepestDescentLineTracer.cxx vtkvmtkSteepestDescentShooter.cxx vtkvmtkUnstructuredGridCenterlineGroupsClipper.cxx vtkvmtkUnstructuredGridCenterlineSections.cxx vtkvmtkVoronoiDiagram3D.cxx ) SET_SOURCE_FILES_PROPERTIES ( vtkvmtkCenterlineSplittingAndGroupingFilter.cxx vtkvmtkPolyDataCenterlineMetricFilter.cxx ABSTRACT ) ADD_LIBRARY (vtkvmtkComputationalGeometry ${VTK_VMTK_COMPUTATIONALGEOMETRY_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkComputationalGeometry PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkComputationalGeometry vtkvmtkCommon vtkCommon vtkFiltering vtkGraphics vtkHybrid) INSTALL(TARGETS vtkvmtkComputationalGeometry LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_COMPUTATIONALGEOMETRY_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/ComputationalGeometry/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkComputationalGeometry) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkComputationalGeometryPython VTK_VMTK_COMPUTATIONALGEOMETRY_PYTHON_SRCS "${VTK_VMTK_COMPUTATIONALGEOMETRY_SRCS}") ADD_LIBRARY(vtkvmtkComputationalGeometryPythonD ${VTK_VMTK_COMPUTATIONALGEOMETRY_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkComputationalGeometryPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkComputationalGeometryPython MODULE vtkvmtkComputationalGeometryPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkComputationalGeometryPythonD vtkvmtkComputationalGeometry vtkvmtkCommon vtkvmtkCommonPythonD vtkCommon vtkCommonPythonD vtkFiltering vtkFilteringPythonD vtkGraphics vtkGraphicsPythonD vtkHybrid vtkHybridPythonD) TARGET_LINK_LIBRARIES (vtkvmtkComputationalGeometryPython vtkvmtkComputationalGeometryPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkComputationalGeometryPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkComputationalGeometryPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkComputationalGeometryPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkComputationalGeometryTCL VTK_VMTK_COMPUTATIONALGEOMETRY_TCL_SRCS "${VTK_VMTK_COMPUTATIONALGEOMETRY_SRCS}" "") ADD_LIBRARY(vtkvmtkComputationalGeometryTCL ${VTK_VMTK_COMPUTATIONALGEOMETRY_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkComputationalGeometryTCL vtkvmtkCommonPython PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkComputationalGeometryTCL vtkvmtkComputationalGeometry vtkvmtkCommon vtkvmtkCommonTCL vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkGraphics vtkGraphicsTCL vtkHybrid vtkHybridTCL) INSTALL(TARGETS vtkvmtkComputationalGeometryTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkComputationalGeometryTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCapPolyData.cxx0000664000175000017500000001215511757446472023470 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCapPolyData.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCapPolyData.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkvmtkBoundaryReferenceSystems.h" #include "vtkvmtkConstants.h" #include "vtkCellArray.h" #include "vtkPointData.h" #include "vtkMath.h" #include "vtkPolyLine.h" #include "vtkLine.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCapPolyData, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkCapPolyData); vtkvmtkCapPolyData::vtkvmtkCapPolyData() { this->BoundaryIds = NULL; this->Displacement = 1E-1; this->InPlaneDisplacement = 1E-1; this->CapCenterIds = NULL; } vtkvmtkCapPolyData::~vtkvmtkCapPolyData() { if (this->BoundaryIds) { this->BoundaryIds->Delete(); this->BoundaryIds = NULL; } if (this->CapCenterIds) { this->CapCenterIds->Delete(); this->CapCenterIds = NULL; } } int vtkvmtkCapPolyData::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())); // Declare vtkIdType barycenterId, trianglePoints[3]; vtkIdType i, j; vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor; vtkPolyData* boundaries; vtkPoints* newPoints; vtkCellArray* newPolys; vtkPolyLine* boundary; // Initialize if ( ((input->GetNumberOfPoints()) < 1) ) { //vtkErrorMacro(<< "No input!"); return 1; } input->BuildLinks(); // Allocate newPoints = vtkPoints::New(); newPoints->DeepCopy(input->GetPoints()); newPolys = vtkCellArray::New(); newPolys->DeepCopy(input->GetPolys()); boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); // Execute boundaryExtractor->SetInput(input); boundaryExtractor->Update(); boundaries = boundaryExtractor->GetOutput(); if (this->CapCenterIds) { this->CapCenterIds->Delete(); this->CapCenterIds = NULL; } this->CapCenterIds = vtkIdList::New(); this->CapCenterIds->SetNumberOfIds(boundaries->GetNumberOfCells()); for (i=0; iCapCenterIds->GetNumberOfIds(); i++) { this->CapCenterIds->SetId(i,-1); } double barycenter[3], normal[3], outwardNormal[3], meanRadius; for (i=0; iGetNumberOfCells(); i++) { if (this->BoundaryIds) { if (this->BoundaryIds->IsId(i) == -1) { continue; } } boundary = vtkPolyLine::SafeDownCast(boundaries->GetCell(i)); vtkvmtkBoundaryReferenceSystems::ComputeBoundaryBarycenter(boundary->GetPoints(),barycenter); vtkvmtkBoundaryReferenceSystems::ComputeBoundaryNormal(boundary->GetPoints(),barycenter,normal); vtkvmtkBoundaryReferenceSystems::OrientBoundaryNormalOutwards(input,boundaries,i,normal,outwardNormal); meanRadius = vtkvmtkBoundaryReferenceSystems::ComputeBoundaryMeanRadius(boundary->GetPoints(),barycenter); for (j=0; j<3; j++) { barycenter[j] += meanRadius * this->Displacement * outwardNormal[j]; } double inplane1[3], inplane2[3]; vtkMath::Perpendiculars(outwardNormal,inplane1,inplane2,0.0); for (j=0; j<3; j++) { barycenter[j] += meanRadius * this->InPlaneDisplacement * inplane1[j]; } barycenterId = newPoints->InsertNextPoint(barycenter); this->CapCenterIds->SetId(i,barycenterId); vtkIdType numberOfBoundaryPoints = boundary->GetNumberOfPoints(); for (j=0; j(boundaries->GetPointData()->GetScalars()->GetTuple1(boundary->GetPointId(j))); trianglePoints[1] = barycenterId; trianglePoints[2] = static_cast(boundaries->GetPointData()->GetScalars()->GetTuple1(boundary->GetPointId((j+1)%numberOfBoundaryPoints))); newPolys->InsertNextCell(3,trianglePoints); } } output->SetPoints(newPoints); output->SetPolys(newPolys); // TODO: the filter throws all the point and cell data // Destroy newPoints->Delete(); newPolys->Delete(); boundaryExtractor->Delete(); return 1; } void vtkvmtkCapPolyData::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineGeometry.cxx0000664000175000017500000004372711757446472025144 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineGeometry.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineGeometry.h" #include "vtkvmtkCenterlineSmoothing.h" #include "vtkvmtkConstants.h" #include "vtkPolyData.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyLine.h" #include "vtkMath.h" #include "vtkTransform.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineGeometry, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkCenterlineGeometry); vtkvmtkCenterlineGeometry::vtkvmtkCenterlineGeometry() { this->LengthArrayName = NULL; this->CurvatureArrayName = NULL; this->TorsionArrayName = NULL; this->TortuosityArrayName = NULL; this->FrenetTangentArrayName = NULL; this->FrenetNormalArrayName = NULL; this->FrenetBinormalArrayName = NULL; this->LineSmoothing = 0; this->OutputSmoothedLines = 0; this->SmoothingFactor = 0.01; this->NumberOfSmoothingIterations = 100; } vtkvmtkCenterlineGeometry::~vtkvmtkCenterlineGeometry() { if (this->LengthArrayName) { delete[] this->LengthArrayName; this->LengthArrayName = NULL; } if (this->CurvatureArrayName) { delete[] this->CurvatureArrayName; this->CurvatureArrayName = NULL; } if (this->TorsionArrayName) { delete[] this->TorsionArrayName; this->TorsionArrayName = NULL; } if (this->TortuosityArrayName) { delete[] this->TortuosityArrayName; this->TortuosityArrayName = NULL; } if (this->FrenetTangentArrayName) { delete[] this->FrenetTangentArrayName; this->FrenetTangentArrayName = NULL; } if (this->FrenetNormalArrayName) { delete[] this->FrenetNormalArrayName; this->FrenetNormalArrayName = NULL; } if (this->FrenetBinormalArrayName) { delete[] this->FrenetBinormalArrayName; this->FrenetBinormalArrayName = NULL; } } int vtkvmtkCenterlineGeometry::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())); if (!this->LengthArrayName) { vtkErrorMacro(<<"LengthArrayName not specified"); return 1; } if (!this->CurvatureArrayName) { vtkErrorMacro(<<"CurvatureArrayName not specified"); return 1; } if (!this->TorsionArrayName) { vtkErrorMacro(<<"TorsionArrayName not specified"); return 1; } if (!this->TortuosityArrayName) { vtkErrorMacro(<<"TorsionArrayName not specified"); return 1; } if (!this->FrenetTangentArrayName) { vtkErrorMacro(<<"FrenetTangentArrayName not specified"); return 1; } if (!this->FrenetNormalArrayName) { vtkErrorMacro(<<"FrenetNormalArrayName not specified"); return 1; } if (!this->FrenetBinormalArrayName) { vtkErrorMacro(<<"FrenetBinormalArrayName not specified"); return 1; } output->DeepCopy(input); int numberOfInputPoints = input->GetNumberOfPoints(); int numberOfInputCells = input->GetNumberOfCells(); vtkDoubleArray* lengthArray = vtkDoubleArray::New(); lengthArray->SetName(this->LengthArrayName); lengthArray->SetNumberOfComponents(1); lengthArray->SetNumberOfTuples(numberOfInputCells); lengthArray->FillComponent(0,0.0); output->GetCellData()->AddArray(lengthArray); vtkDoubleArray* curvatureArray = vtkDoubleArray::New(); curvatureArray->SetName(this->CurvatureArrayName); curvatureArray->SetNumberOfComponents(1); curvatureArray->SetNumberOfTuples(numberOfInputPoints); curvatureArray->FillComponent(0,0.0); output->GetPointData()->AddArray(curvatureArray); vtkDoubleArray* torsionArray = vtkDoubleArray::New(); torsionArray->SetName(this->TorsionArrayName); torsionArray->SetNumberOfComponents(1); torsionArray->SetNumberOfTuples(numberOfInputPoints); torsionArray->FillComponent(0,0.0); output->GetPointData()->AddArray(torsionArray); vtkDoubleArray* tortuosityArray = vtkDoubleArray::New(); tortuosityArray->SetName(this->TortuosityArrayName); tortuosityArray->SetNumberOfComponents(1); tortuosityArray->SetNumberOfTuples(numberOfInputCells); tortuosityArray->FillComponent(0,0.0); output->GetCellData()->AddArray(tortuosityArray); vtkDoubleArray* frenetTangentArray = vtkDoubleArray::New(); frenetTangentArray->SetName(this->FrenetTangentArrayName); frenetTangentArray->SetNumberOfComponents(3); frenetTangentArray->SetNumberOfTuples(numberOfInputPoints); frenetTangentArray->FillComponent(0,0.0); frenetTangentArray->FillComponent(1,0.0); frenetTangentArray->FillComponent(2,0.0); output->GetPointData()->AddArray(frenetTangentArray); vtkDoubleArray* frenetNormalArray = vtkDoubleArray::New(); frenetNormalArray->SetName(this->FrenetNormalArrayName); frenetNormalArray->SetNumberOfComponents(3); frenetNormalArray->SetNumberOfTuples(numberOfInputPoints); frenetNormalArray->FillComponent(0,0.0); frenetNormalArray->FillComponent(1,0.0); frenetNormalArray->FillComponent(2,0.0); output->GetPointData()->AddArray(frenetNormalArray); vtkDoubleArray* frenetBinormalArray = vtkDoubleArray::New(); frenetBinormalArray->SetName(this->FrenetBinormalArrayName); frenetBinormalArray->SetNumberOfComponents(3); frenetBinormalArray->SetNumberOfTuples(numberOfInputPoints); frenetBinormalArray->FillComponent(0,0.0); frenetBinormalArray->FillComponent(1,0.0); frenetBinormalArray->FillComponent(2,0.0); output->GetPointData()->AddArray(frenetBinormalArray); for (int i=0; iGetNumberOfCells(); i++) { vtkCell* line = input->GetCell(i); if (line->GetCellType() != VTK_LINE && line->GetCellType() != VTK_POLY_LINE) { continue; } vtkDoubleArray* lineCurvatureArray = vtkDoubleArray::New(); vtkDoubleArray* lineTorsionArray = vtkDoubleArray::New(); vtkDoubleArray* lineTangentArray = vtkDoubleArray::New(); vtkDoubleArray* lineNormalArray = vtkDoubleArray::New(); vtkDoubleArray* lineBinormalArray = vtkDoubleArray::New(); vtkPoints* linePoints = vtkPoints::New(); linePoints->DeepCopy(line->GetPoints()); if (this->LineSmoothing) { vtkPoints* smoothLinePoints = vtkPoints::New(); vtkvmtkCenterlineSmoothing::SmoothLine(linePoints,smoothLinePoints,this->NumberOfSmoothingIterations,this->SmoothingFactor); linePoints->DeepCopy(smoothLinePoints); smoothLinePoints->Delete(); } this->ComputeLineCurvature(linePoints,lineCurvatureArray); this->ComputeLineTorsion(linePoints,lineTorsionArray); this->ComputeLineFrenetReferenceSystem(linePoints,lineTangentArray,lineNormalArray,lineBinormalArray); int numberOfLinePoints = linePoints->GetNumberOfPoints(); double length = 0.0; double point0[3], point1[3]; for (int j=0; jGetPointId(j); if (this->OutputSmoothedLines) { output->GetPoints()->SetPoint(pointId,linePoints->GetPoint(j)); } if (j>0) { linePoints->GetPoint(j-1,point0); linePoints->GetPoint(j,point1); length += sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); } curvatureArray->SetComponent(pointId,0,lineCurvatureArray->GetComponent(j,0)); torsionArray->SetComponent(pointId,0,lineTorsionArray->GetComponent(j,0)); double tuple[3]; lineTangentArray->GetTuple(j,tuple); frenetTangentArray->SetTuple(pointId,tuple); lineNormalArray->GetTuple(j,tuple); frenetNormalArray->SetTuple(pointId,tuple); lineBinormalArray->GetTuple(j,tuple); frenetBinormalArray->SetTuple(pointId,tuple); } linePoints->GetPoint(0,point0); linePoints->GetPoint(numberOfLinePoints-1,point1); double tortuosity = length / sqrt(vtkMath::Distance2BetweenPoints(point0,point1)) - 1.0; lengthArray->SetComponent(i,0,length); tortuosityArray->SetComponent(i,0,tortuosity); lineCurvatureArray->Delete(); lineTorsionArray->Delete(); linePoints->Delete(); lineTangentArray->Delete(); lineNormalArray->Delete(); lineBinormalArray->Delete(); } lengthArray->Delete(); curvatureArray->Delete(); torsionArray->Delete(); tortuosityArray->Delete(); frenetTangentArray->Delete(); frenetNormalArray->Delete(); frenetBinormalArray->Delete(); return 1; } void vtkvmtkCenterlineGeometry::ComputeLineFrenetReferenceSystem(vtkPoints* linePoints, vtkDoubleArray* lineTangentArray, vtkDoubleArray* lineNormalArray, vtkDoubleArray* lineBinormalArray) { int numberOfPoints = linePoints->GetNumberOfPoints(); lineTangentArray->SetNumberOfComponents(3); lineTangentArray->SetNumberOfTuples(numberOfPoints); lineTangentArray->FillComponent(0,0.0); lineTangentArray->FillComponent(1,0.0); lineTangentArray->FillComponent(2,0.0); lineNormalArray->SetNumberOfComponents(3); lineNormalArray->SetNumberOfTuples(numberOfPoints); lineNormalArray->FillComponent(0,0.0); lineNormalArray->FillComponent(1,0.0); lineNormalArray->FillComponent(2,0.0); lineBinormalArray->SetNumberOfComponents(3); lineBinormalArray->SetNumberOfTuples(numberOfPoints); lineBinormalArray->FillComponent(0,0.0); lineBinormalArray->FillComponent(1,0.0); lineBinormalArray->FillComponent(2,0.0); double point0[3], point1[3], point2[3]; double vector0[3], vector1[3]; for (int j=1; jGetPoint(j-1,point0); linePoints->GetPoint(j,point1); linePoints->GetPoint(j+1,point2); vector0[0] = point1[0] - point0[0]; vector0[1] = point1[1] - point0[1]; vector0[2] = point1[2] - point0[2]; vector1[0] = point2[0] - point1[0]; vector1[1] = point2[1] - point1[1]; vector1[2] = point2[2] - point1[2]; double norm0 = vtkMath::Norm(vector0); double norm1 = vtkMath::Norm(vector1); if (norm0 < VTK_VMTK_DOUBLE_TOL || norm1 < VTK_VMTK_DOUBLE_TOL) { continue; } double xp[3]; xp[0] = point2[0] - point0[0]; xp[1] = point2[1] - point0[1]; xp[2] = point2[2] - point0[2]; xp[0] /= norm0 + norm1; xp[1] /= norm0 + norm1; xp[2] /= norm0 + norm1; double xpp[3]; xpp[0] = (point2[0] - point1[0]) / norm1 - (point1[0] - point0[0]) / norm0; xpp[1] = (point2[1] - point1[1]) / norm1 - (point1[1] - point0[1]) / norm0; xpp[2] = (point2[2] - point1[2]) / norm1 - (point1[2] - point0[2]) / norm0; xpp[0] /= (norm0 + norm1) / 2.0; xpp[1] /= (norm0 + norm1) / 2.0; xpp[2] /= (norm0 + norm1) / 2.0; double xpxppcross[3]; vtkMath::Cross(xp,xpp,xpxppcross); double tangent[3], normal[3], binormal[3]; tangent[0] = xp[0]; tangent[1] = xp[1]; tangent[2] = xp[2]; vtkMath::Normalize(tangent); binormal[0] = xpxppcross[0]; binormal[1] = xpxppcross[1]; binormal[2] = xpxppcross[2]; vtkMath::Normalize(binormal); vtkMath::Cross(binormal,tangent,normal); vtkMath::Normalize(normal); lineTangentArray->SetTuple(j,tangent); lineNormalArray->SetTuple(j,normal); lineBinormalArray->SetTuple(j,binormal); } double tuple[3]; lineTangentArray->GetTuple(1,tuple); lineTangentArray->SetTuple(0,tuple); lineNormalArray->GetTuple(1,tuple); lineNormalArray->SetTuple(0,tuple); lineBinormalArray->GetTuple(1,tuple); lineBinormalArray->SetTuple(0,tuple); lineTangentArray->GetTuple(numberOfPoints-2,tuple); lineTangentArray->SetTuple(numberOfPoints-1,tuple); lineNormalArray->GetTuple(numberOfPoints-2,tuple); lineNormalArray->SetTuple(numberOfPoints-1,tuple); lineBinormalArray->GetTuple(numberOfPoints-2,tuple); lineBinormalArray->SetTuple(numberOfPoints-1,tuple); } double vtkvmtkCenterlineGeometry::ComputeLineCurvature(vtkPoints* linePoints, vtkDoubleArray* curvatureArray) { int numberOfPoints = linePoints->GetNumberOfPoints(); curvatureArray->SetNumberOfComponents(1); curvatureArray->SetNumberOfTuples(numberOfPoints); curvatureArray->FillComponent(0,0.0); double point0[3], point1[3], point2[3]; double vector0[3], vector1[3]; double averageCurvature = 0.0; double weightSum = 0.0; for (int j=1; jGetPoint(j-1,point0); linePoints->GetPoint(j,point1); linePoints->GetPoint(j+1,point2); vector0[0] = point1[0] - point0[0]; vector0[1] = point1[1] - point0[1]; vector0[2] = point1[2] - point0[2]; vector1[0] = point2[0] - point1[0]; vector1[1] = point2[1] - point1[1]; vector1[2] = point2[2] - point1[2]; double norm0 = vtkMath::Norm(vector0); double norm1 = vtkMath::Norm(vector1); if (norm0 < VTK_VMTK_DOUBLE_TOL || norm1 < VTK_VMTK_DOUBLE_TOL) { continue; } double xp[3]; xp[0] = point2[0] - point0[0]; xp[1] = point2[1] - point0[1]; xp[2] = point2[2] - point0[2]; xp[0] /= norm0 + norm1; xp[1] /= norm0 + norm1; xp[2] /= norm0 + norm1; double xpp[3]; xpp[0] = (point2[0] - point1[0]) / norm1 - (point1[0] - point0[0]) / norm0; xpp[1] = (point2[1] - point1[1]) / norm1 - (point1[1] - point0[1]) / norm0; xpp[2] = (point2[2] - point1[2]) / norm1 - (point1[2] - point0[2]) / norm0; xpp[0] /= (norm0 + norm1) / 2.0; xpp[1] /= (norm0 + norm1) / 2.0; xpp[2] /= (norm0 + norm1) / 2.0; double xpxppcross[3]; vtkMath::Cross(xp,xpp,xpxppcross); double curvature = vtkMath::Norm(xpxppcross) / pow(vtkMath::Norm(xp),3.0); curvatureArray->SetComponent(j,0,curvature); double weight = (norm0 + norm1) / 2.0; averageCurvature += curvature * weight; weightSum += weight; } if (weightSum>0.0) { averageCurvature /= weightSum; } return averageCurvature; } double vtkvmtkCenterlineGeometry::ComputeLineTorsion(vtkPoints* linePoints, vtkDoubleArray* torsionArray) { int numberOfPoints = linePoints->GetNumberOfPoints(); torsionArray->SetNumberOfComponents(1); torsionArray->SetNumberOfTuples(numberOfPoints); torsionArray->FillComponent(0,0.0); double point0[3], point1[3], point2[3]; double vector0[3], vector1[3]; double averageTorsion = 0.0; double weightSum = 0.0; double* xps = new double[3*numberOfPoints]; double* xpps = new double[3*numberOfPoints]; int j; for (j=0; jGetPoint(j-1,point0); linePoints->GetPoint(j,point1); linePoints->GetPoint(j+1,point2); vector0[0] = point1[0] - point0[0]; vector0[1] = point1[1] - point0[1]; vector0[2] = point1[2] - point0[2]; vector1[0] = point2[0] - point1[0]; vector1[1] = point2[1] - point1[1]; vector1[2] = point2[2] - point1[2]; double norm0 = vtkMath::Norm(vector0); double norm1 = vtkMath::Norm(vector1); if (norm0 < VTK_VMTK_DOUBLE_TOL || norm1 < VTK_VMTK_DOUBLE_TOL) { continue; } xps[3*j+0] = point2[0] - point0[0]; xps[3*j+1] = point2[1] - point0[1]; xps[3*j+2] = point2[2] - point0[2]; xps[3*j+0] /= norm0 + norm1; xps[3*j+1] /= norm0 + norm1; xps[3*j+2] /= norm0 + norm1; xpps[3*j+0] = (point2[0] - point1[0]) / norm1 - (point1[0] - point0[0]) / norm0; xpps[3*j+1] = (point2[1] - point1[1]) / norm1 - (point1[1] - point0[1]) / norm0; xpps[3*j+2] = (point2[2] - point1[2]) / norm1 - (point1[2] - point0[2]) / norm0; xpps[3*j+0] /= (norm0 + norm1) / 2.0; xpps[3*j+1] /= (norm0 + norm1) / 2.0; xpps[3*j+2] /= (norm0 + norm1) / 2.0; } for (j=2; jGetPoint(j-1,point0); linePoints->GetPoint(j,point1); linePoints->GetPoint(j+1,point2); vector0[0] = point1[0] - point0[0]; vector0[1] = point1[1] - point0[1]; vector0[2] = point1[2] - point0[2]; vector1[0] = point2[0] - point1[0]; vector1[1] = point2[1] - point1[1]; vector1[2] = point2[2] - point1[2]; double norm0 = vtkMath::Norm(vector0); double norm1 = vtkMath::Norm(vector1); if (norm0 < VTK_VMTK_DOUBLE_TOL || norm1 < VTK_VMTK_DOUBLE_TOL) { continue; } double xp[3]; xp[0] = xps[3*j+0]; xp[1] = xps[3*j+1]; xp[2] = xps[3*j+2]; double xpp[3]; xpp[0] = xpps[3*j+0]; xpp[1] = xpps[3*j+1]; xpp[2] = xpps[3*j+2]; double xpxppcross[3]; vtkMath::Cross(xp,xpp,xpxppcross); double xppp[3]; xppp[0] = xpps[3*(j+1)+0] - xpps[3*(j-1)+0]; xppp[1] = xpps[3*(j+1)+1] - xpps[3*(j-1)+1]; xppp[2] = xpps[3*(j+1)+2] - xpps[3*(j-1)+2]; xppp[0] /= norm0 + norm1; xppp[1] /= norm0 + norm1; xppp[2] /= norm0 + norm1; double torsion = vtkMath::Dot(xpxppcross,xppp) / pow(vtkMath::Norm(xpxppcross),2.0); torsionArray->SetComponent(j,0,torsion); double weight = (norm0 + norm1) / 2.0; averageTorsion += torsion * weight; weightSum += weight; } delete[] xps; delete[] xpps; if (weightSum>0.0) { averageTorsion /= weightSum; } return averageTorsion; } void vtkvmtkCenterlineGeometry::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineMetricFilter.h0000664000175000017500000000606511757446472027017 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineMetricFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.8 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .SECTION Description // .. #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: vtkTypeRevisionMacro(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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineGroupsClipper.cxx0000664000175000017500000002474111757446472027600 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineGroupsClipper.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.9 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataCenterlineGroupsClipper.h" #include "vtkExecutive.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkIntArray.h" #include "vtkDoubleArray.h" #include "vtkClipPolyData.h" #include "vtkAppendPolyData.h" #include "vtkvmtkPolyBallLine.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlineGroupsClipper, "$Revision: 1.9 $"); vtkStandardNewMacro(vtkvmtkPolyDataCenterlineGroupsClipper); vtkvmtkPolyDataCenterlineGroupsClipper::vtkvmtkPolyDataCenterlineGroupsClipper() { 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; vtkPolyData *output2 = vtkPolyData::New(); this->GetExecutive()->SetOutputData(1, output2); output2->Delete(); } vtkvmtkPolyDataCenterlineGroupsClipper::~vtkvmtkPolyDataCenterlineGroupsClipper() { 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; } } vtkPolyData *vtkvmtkPolyDataCenterlineGroupsClipper::GetClippedOutput() { if (this->GetNumberOfOutputPorts() < 2) { return NULL; } return vtkPolyData::SafeDownCast(this->GetExecutive()->GetOutputData(1)); } int vtkvmtkPolyDataCenterlineGroupsClipper::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())); 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; } vtkAppendPolyData* appendBranches = vtkAppendPolyData::New(); vtkAppendPolyData* appendClippedOutput = NULL; if (this->GenerateClippedOutput) { appendClippedOutput = vtkAppendPolyData::New(); } // 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); vtkPolyData* clippingInput = vtkPolyData::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; iGetNumberOfTuples(); i++) { if (blankingArray->GetValue(i) == 1) { continue; } centerlineGroupIds->InsertUniqueId(static_cast(vtkMath::Round(centerlineGroupIdsArray->GetComponent(i,0)))); } } else { centerlineGroupIds->DeepCopy(this->CenterlineGroupIds); } for (i=0; iGetNumberOfIds(); i++) { groupId = centerlineGroupIds->GetId(i); groupTubesGroupIds->Initialize(); nonGroupTubesGroupIds->Initialize(); for (int j=0; jCenterlines->GetNumberOfCells(); j++) { if (blankingArray->GetValue(j) == 1) { continue; } if (static_cast(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; kGetPoint(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); } vtkClipPolyData* clipper = vtkClipPolyData::New(); clipper->SetInput(clippingInput); clipper->SetValue(this->ClipValue); clipper->GenerateClipScalarsOff(); clipper->SetGenerateClippedOutput(this->GenerateClippedOutput); clipper->Update(); if (clipper->GetOutput()->GetNumberOfPoints()==0) { clipper->Delete(); continue; } vtkPolyData* clippedBranch = vtkPolyData::New(); clippedBranch->DeepCopy(clipper->GetOutput()); if (this->GenerateClippedOutput) { vtkPolyData* clippedOutputBranch = vtkPolyData::New(); clippedOutputBranch->DeepCopy(clipper->GetClippedOutput()); appendClippedOutput->AddInput(clippedOutputBranch); clippedOutputBranch->Delete(); } groupIdsArray = vtkIntArray::New(); groupIdsArray->SetName(this->GroupIdsArrayName); groupIdsArray->SetNumberOfTuples(clippedBranch->GetNumberOfPoints()); groupIdsArray->FillComponent(0,groupId); clippedBranch->GetPointData()->AddArray(groupIdsArray); appendBranches->AddInput(clippedBranch); 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 vtkvmtkPolyDataCenterlineGroupsClipper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataLocalGeometry.h0000664000175000017500000001720711757446472025163 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataLocalGeometry.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataLocalGeometry - Compute shape-related quantities over a surface. // .SECTION Description // This class computes geodesic distance to centerlines and normalized tangency deviation distribution over a surface given the Voronoi diagram of its points, the ids of Voronoi diagram points which are poles of surface points, and the field of the geodesic distance from centerlines computed over the Voronoi diagram. // // Geodesic distance to centerlines field is computed as // \f[ D_g(\mathbf{x}) = T(\mathbf{p}(\mathbf{x})) + |\mathbf{p}(\mathbf{x}) - \mathbf{x}| \f] // where T(x) is the geodesic distance to centerlines field defined on the Voronoi diagram (computed by solving the Eikonal equation with unit speed over the Voronoi diagram by means of vtkNonManifoldFastMarching), and p(x) is the pole associated with surface point x. // // Normalized tangency deviation is a normalized measure of how much a surface point is far from being a tangency point to the evelope of maximal spheres defined on the centerlines (their envelope is the maximal inscribed cylinder), and it is computed as // \f[\mathit{NTD}=\frac{T(\mathbf{p}(\mathbf{x}))}{D_g(\mathbf{x})}\f] // This quantity ranges from 0 to 1, and it is independent from the radius of the maximal inscribed cylinder (on an elliptical base cylinder, NTD only depends on base ellipse eccentricity). // // The description given here is particularly suited for the description of tubular surfaces in terms of centerlines, but this class can be used without this assumption. Whenever a geodesic distance field is computed over the Voronoi diagram associated with a shape from a subset of the Voronoi diagram itself (in this context, the centerlines), the surface geodesic distance field and the normalized tangency deviation can be defined, and this class can be used to compute them. // // .SECTION See Also // vtkNonManifoldFastMarching vtkVoronoiDiagram3D #ifndef __vtkvmtkPolyDataLocalGeometry_h #define __vtkvmtkPolyDataLocalGeometry_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataLocalGeometry : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataLocalGeometry,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataLocalGeometry *New(); // Description: // TODO vtkSetMacro(ComputePoleVectors,int); vtkGetMacro(ComputePoleVectors,int); vtkBooleanMacro(ComputePoleVectors,int); // Description: // Turn on/off the computation of geodesic distance to centerlines. vtkSetMacro(ComputeGeodesicDistance,int); vtkGetMacro(ComputeGeodesicDistance,int); vtkBooleanMacro(ComputeGeodesicDistance,int); // Description: // Set/Get the name of the point data array where geodesic distance to centerlines is stored after execution. vtkSetStringMacro(GeodesicDistanceArrayName); vtkGetStringMacro(GeodesicDistanceArrayName); // Description: // Turn on/off the computation of normalized tangency deviation. vtkSetMacro(ComputeNormalizedTangencyDeviation,int); vtkGetMacro(ComputeNormalizedTangencyDeviation,int); vtkBooleanMacro(ComputeNormalizedTangencyDeviation,int); // Description: // Set/Get the name of the point data array where normalized tangency deviation is stored after execution. vtkSetStringMacro(NormalizedTangencyDeviationArrayName); vtkGetStringMacro(NormalizedTangencyDeviationArrayName); // Description: // TODO vtkSetMacro(ComputeEuclideanDistance,int); vtkGetMacro(ComputeEuclideanDistance,int); vtkBooleanMacro(ComputeEuclideanDistance,int); // Description: // TODO vtkSetStringMacro(EuclideanDistanceArrayName); vtkGetStringMacro(EuclideanDistanceArrayName); // Description: // TODO vtkSetMacro(ComputeCenterlineVectors,int); vtkGetMacro(ComputeCenterlineVectors,int); vtkBooleanMacro(ComputeCenterlineVectors,int); // Description: // TODO vtkSetStringMacro(CenterlineVectorsArrayName); vtkGetStringMacro(CenterlineVectorsArrayName); // Description: // TODO vtkSetMacro(ComputeCellIds,int); vtkGetMacro(ComputeCellIds,int); vtkBooleanMacro(ComputeCellIds,int); // Description: // TODO vtkSetStringMacro(CellIdsArrayName); vtkGetStringMacro(CellIdsArrayName); // Description: // TODO vtkSetMacro(ComputePCoords,int); vtkGetMacro(ComputePCoords,int); vtkBooleanMacro(ComputePCoords,int); vtkSetMacro(AdjustBoundaryValues,int); vtkGetMacro(AdjustBoundaryValues,int); vtkBooleanMacro(AdjustBoundaryValues,int); // Description: // TODO vtkSetStringMacro(PCoordsArrayName); vtkGetStringMacro(PCoordsArrayName); // Description: // Set/Get the Voronoi diagram associated with the input. vtkSetObjectMacro(VoronoiDiagram,vtkPolyData); vtkGetObjectMacro(VoronoiDiagram,vtkPolyData); // Description: // Set/Get the name of the Voronoi diagram point data array where geodesic distance to centerlines is stored. vtkSetStringMacro(VoronoiGeodesicDistanceArrayName); vtkGetStringMacro(VoronoiGeodesicDistanceArrayName); // Description: // TODO. vtkSetStringMacro(VoronoiPoleCenterlineVectorsArrayName); vtkGetStringMacro(VoronoiPoleCenterlineVectorsArrayName); // Description: // TODO. vtkSetStringMacro(VoronoiCellIdsArrayName); vtkGetStringMacro(VoronoiCellIdsArrayName); // Description: // TODO. vtkSetStringMacro(VoronoiPCoordsArrayName); vtkGetStringMacro(VoronoiPCoordsArrayName); // Description: // Set/Get the id list of the Voronoi diagram points which are the poles of surface points. vtkSetObjectMacro(PoleIds,vtkIdList); vtkGetObjectMacro(PoleIds,vtkIdList); // Description: // TODO vtkSetStringMacro(PoleVectorsArrayName); vtkGetStringMacro(PoleVectorsArrayName); protected: vtkvmtkPolyDataLocalGeometry(); ~vtkvmtkPolyDataLocalGeometry(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void AdjustBoundaryQuantities(vtkPolyData* output); int ComputePoleVectors; int ComputeGeodesicDistance; int ComputeNormalizedTangencyDeviation; int ComputeEuclideanDistance; int ComputeCenterlineVectors; int ComputeCellIds; int ComputePCoords; int AdjustBoundaryValues; char* PoleVectorsArrayName; char* GeodesicDistanceArrayName; char* NormalizedTangencyDeviationArrayName; char* EuclideanDistanceArrayName; char* CenterlineVectorsArrayName; char* CellIdsArrayName; char* PCoordsArrayName; char* VoronoiGeodesicDistanceArrayName; char* VoronoiPoleCenterlineVectorsArrayName; char* VoronoiCellIdsArrayName; char* VoronoiPCoordsArrayName; vtkPolyData* VoronoiDiagram; vtkIdList* PoleIds; private: vtkvmtkPolyDataLocalGeometry(const vtkvmtkPolyDataLocalGeometry&); // Not implemented. void operator=(const vtkvmtkPolyDataLocalGeometry&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkUnstructuredGridCenterlineSections.cxx0000664000175000017500000004725411757446472030375 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridCenterlineSections.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridCenterlineSections.h" #include "vtkUnstructuredGrid.h" #include "vtkPolyLine.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkPlane.h" #include "vtkCutter.h" #include "vtkStripper.h" #include "vtkPolyDataConnectivityFilter.h" #include "vtkMath.h" #include "vtkCleanPolyData.h" #include "vtkAppendPolyData.h" #include "vtkTransform.h" #include "vtkTransformPolyDataFilter.h" #include "vtkDoubleArray.h" #include "vtkvmtkMath.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkProbeFilter.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkPolyDataBranchUtilities.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridCenterlineSections, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridCenterlineSections); vtkvmtkUnstructuredGridCenterlineSections::vtkvmtkUnstructuredGridCenterlineSections() { this->Centerlines = NULL; this->SectionSource = NULL; this->SectionPointsPolyData = NULL; this->SectionUpNormalsArrayName = NULL; this->SectionNormalsArrayName = NULL; this->AdditionalNormalsArrayName = NULL; this->AdditionalScalarsArrayName = NULL; this->SectionIdsArrayName = NULL; this->TransformSections = 0; this->UseSectionSource = 0; this->SourceScaling = 0; this->OriginOffset[0] = this->OriginOffset[1] = this->OriginOffset[2] = 0.0; this->VectorsArrayName = NULL; } vtkvmtkUnstructuredGridCenterlineSections::~vtkvmtkUnstructuredGridCenterlineSections() { if (this->Centerlines) { this->Centerlines->Delete(); this->Centerlines = NULL; } if (this->SectionSource) { this->SectionSource->Delete(); this->SectionSource = NULL; } if (this->SectionPointsPolyData) { this->SectionPointsPolyData->Delete(); this->SectionPointsPolyData = NULL; } if (this->SectionUpNormalsArrayName) { delete[] this->SectionUpNormalsArrayName; this->SectionUpNormalsArrayName = NULL; } if (this->SectionNormalsArrayName) { delete[] this->SectionNormalsArrayName; this->SectionNormalsArrayName = NULL; } if (this->AdditionalNormalsArrayName) { delete[] this->AdditionalNormalsArrayName; this->AdditionalNormalsArrayName = NULL; } if (this->AdditionalScalarsArrayName) { delete[] this->AdditionalScalarsArrayName; this->AdditionalScalarsArrayName = NULL; } if (this->VectorsArrayName) { delete[] this->VectorsArrayName; this->VectorsArrayName = NULL; } if (this->SectionIdsArrayName) { delete[] this->SectionIdsArrayName; this->SectionIdsArrayName = NULL; } } int vtkvmtkUnstructuredGridCenterlineSections::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkUnstructuredGrid"); return 1; } double vtkvmtkUnstructuredGridCenterlineSections::ComputeAngle(double vector0[3], double vector1[3]) { double normal0[3], normal1[3]; normal0[0] = vector0[0]; normal0[1] = vector0[1]; normal0[2] = vector0[2]; normal1[0] = vector1[0]; normal1[1] = vector1[1]; normal1[2] = vector1[2]; vtkMath::Normalize(normal0); vtkMath::Normalize(normal1); double sum[3], difference[3]; sum[0] = normal0[0] + normal1[0]; sum[1] = normal0[1] + normal1[1]; sum[2] = normal0[2] + normal1[2]; difference[0] = normal0[0] - normal1[0]; difference[1] = normal0[1] - normal1[1]; difference[2] = normal0[2] - normal1[2]; double sumNorm = vtkMath::Norm(sum); double differenceNorm = vtkMath::Norm(difference); double angle = 2.0 * atan2(differenceNorm,sumNorm); return angle; } void vtkvmtkUnstructuredGridCenterlineSections::CreateTransform(vtkTransform* transform, double currentOrigin[3], double currentNormal[3], double currentUpNormal[3], double targetOrigin[3], double targetNormal[3], double targetUpNormal[3]) { transform->PostMultiply(); double translation0[3]; translation0[0] = 0.0 - currentOrigin[0]; translation0[1] = 0.0 - currentOrigin[1]; translation0[2] = 0.0 - currentOrigin[2]; double translation1[3]; translation1[0] = targetOrigin[0] - 0.0; translation1[1] = targetOrigin[1] - 0.0; translation1[2] = targetOrigin[2] - 0.0; transform->Translate(translation0); double cross0[3]; vtkMath::Cross(currentNormal,targetNormal,cross0); vtkMath::Normalize(cross0); double angle0 = this->ComputeAngle(currentNormal,targetNormal); angle0 = angle0 / (2.0*vtkMath::Pi()) * 360.0; transform->RotateWXYZ(angle0,cross0); double dot = vtkMath::Dot(currentUpNormal,currentNormal); double currentProjectedUpNormal[3]; currentProjectedUpNormal[0] = currentUpNormal[0] - dot * currentNormal[0]; currentProjectedUpNormal[1] = currentUpNormal[1] - dot * currentNormal[1]; currentProjectedUpNormal[2] = currentUpNormal[2] - dot * currentNormal[2]; vtkMath::Normalize(currentProjectedUpNormal); double transformedUpNormal[3]; transform->TransformNormal(currentProjectedUpNormal,transformedUpNormal); double cross1[3]; vtkMath::Cross(transformedUpNormal,targetUpNormal,cross1); vtkMath::Normalize(cross1); double angle1 = this->ComputeAngle(transformedUpNormal,targetUpNormal); angle1 = angle1 / (2.0*vtkMath::Pi()) * 360.0; transform->RotateWXYZ(angle1,cross1); transform->Translate(translation1); } int vtkvmtkUnstructuredGridCenterlineSections::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())); vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); if (!this->Centerlines) { vtkErrorMacro(<<"Centerlines not set"); return 1; } if (this->UseSectionSource && !this->SectionSource) { vtkErrorMacro(<<"SectionSource not set"); return 1; } vtkDataArray* upNormalsArray = NULL; if (this->TransformSections && !this->SectionUpNormalsArrayName) { vtkErrorMacro(<<"TransformSection is On and no SectionUpNormalsArrayName specified!"); return 1; } if (this->SectionUpNormalsArrayName) { upNormalsArray = this->Centerlines->GetPointData()->GetArray(this->SectionUpNormalsArrayName); if (!upNormalsArray) { vtkErrorMacro(<<"UpNormalsArray with name specified does not exist!"); return 1; } if (upNormalsArray->GetNumberOfComponents() != 3) { vtkErrorMacro(<<"UpNormalsArray does not have 3 components!"); return 1; } } if (!this->SectionNormalsArrayName) { vtkErrorMacro(<<"SectionNormalsArrayName not specified!"); return 1; } if (!this->SectionIdsArrayName) { vtkErrorMacro(<<"SectionIdsArrayName not specified!"); return 1; } vtkDataArray* additionalNormalsArray = NULL; vtkDataArray* additionalScalarsArray = NULL; if (this->AdditionalNormalsArrayName) { additionalNormalsArray = this->Centerlines->GetPointData()->GetArray(this->AdditionalNormalsArrayName); if (!additionalNormalsArray) { vtkErrorMacro(<<"AdditionalNormalsArray with name specified does not exist!"); } if (additionalNormalsArray->GetNumberOfComponents() != 3) { vtkErrorMacro(<<"AdditionalNormalsArray does not have 3 components!"); additionalNormalsArray = NULL; } } if (this->AdditionalScalarsArrayName) { additionalScalarsArray = this->Centerlines->GetPointData()->GetArray(this->AdditionalScalarsArrayName); if (!additionalScalarsArray) { vtkErrorMacro(<<"AdditionalScalarsArray with name specified does not exist!"); } } if (this->SectionPointsPolyData) { this->SectionPointsPolyData->Delete(); this->SectionPointsPolyData = NULL; } this->SectionPointsPolyData = vtkPolyData::New(); vtkPoints* sectionPointsPoints = vtkPoints::New(); vtkCellArray* sectionPointsVerts = vtkCellArray::New(); vtkDoubleArray* sectionPointsUpNormals = vtkDoubleArray::New(); sectionPointsUpNormals->SetNumberOfComponents(3); sectionPointsUpNormals->SetName(this->SectionUpNormalsArrayName); vtkDoubleArray* sectionPointsNormals = vtkDoubleArray::New(); sectionPointsNormals->SetNumberOfComponents(3); sectionPointsNormals->SetName(this->SectionNormalsArrayName); vtkDoubleArray* sectionPointsAdditionalNormals = vtkDoubleArray::New(); sectionPointsAdditionalNormals->SetNumberOfComponents(3); sectionPointsAdditionalNormals->SetName(this->AdditionalNormalsArrayName); vtkDoubleArray* sectionPointsAdditionalScalars = vtkDoubleArray::New(); sectionPointsAdditionalScalars->SetNumberOfComponents(1); sectionPointsAdditionalScalars->SetName(this->AdditionalScalarsArrayName); this->SectionPointsPolyData->SetPoints(sectionPointsPoints); this->SectionPointsPolyData->SetVerts(sectionPointsVerts); if (upNormalsArray) { this->SectionPointsPolyData->GetPointData()->AddArray(sectionPointsUpNormals); } this->SectionPointsPolyData->GetPointData()->AddArray(sectionPointsNormals); if (additionalNormalsArray) { this->SectionPointsPolyData->GetPointData()->AddArray(sectionPointsAdditionalNormals); } if (additionalScalarsArray) { this->SectionPointsPolyData->GetPointData()->AddArray(sectionPointsAdditionalScalars); } vtkIdType sectionId = 0; vtkAppendPolyData* appendFilter = vtkAppendPolyData::New(); int numberOfCenterlineCells = this->Centerlines->GetNumberOfCells(); int i; for (i=0; iCenterlines->GetCell(i); vtkPoints* centerlineCellPoints = centerlineCell->GetPoints(); int numberOfCellPoints = centerlineCellPoints->GetNumberOfPoints(); int j; for (j=0; jGetPoint(j,point); double tangent[3]; tangent[0] = tangent[1] = tangent[2] = 0.0; double upNormal[3]; upNormal[0] = upNormal[1] = upNormal[2] = 0.0; double weightSum = 0.0; if (j>0) { double point0[3], point1[3]; centerlineCellPoints->GetPoint(j-1,point0); centerlineCellPoints->GetPoint(j,point1); double distance = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); tangent[0] += (point1[0] - point0[0]) / distance; tangent[1] += (point1[1] - point0[1]) / distance; tangent[2] += (point1[2] - point0[2]) / distance; weightSum += 1.0; } if (jGetPoint(j,point0); centerlineCellPoints->GetPoint(j+1,point1); double distance = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); tangent[0] += (point1[0] - point0[0]) / distance; tangent[1] += (point1[1] - point0[1]) / distance; tangent[2] += (point1[2] - point0[2]) / distance; weightSum += 1.0; } tangent[0] /= weightSum; tangent[1] /= weightSum; tangent[2] /= weightSum; vtkMath::Normalize(tangent); if (upNormalsArray) { upNormalsArray->GetTuple(centerlineCell->GetPointId(j),upNormal); vtkMath::Normalize(upNormal); } vtkPolyData* section = vtkPolyData::New(); if (!this->UseSectionSource) { vtkPlane* plane = vtkPlane::New(); plane->SetOrigin(point); plane->SetNormal(tangent); vtkCutter* cutter = vtkCutter::New(); cutter->SetInput(input); cutter->SetCutFunction(plane); cutter->GenerateCutScalarsOff(); cutter->SetValue(0,0.0); cutter->Update(); vtkCleanPolyData* cleaner = vtkCleanPolyData::New(); cleaner->SetInput(cutter->GetOutput()); cleaner->Update(); if (cleaner->GetOutput()->GetNumberOfPoints() == 0) { plane->Delete(); cutter->Delete(); cleaner->Delete(); continue; } vtkPolyDataConnectivityFilter* connectivityFilter = vtkPolyDataConnectivityFilter::New(); connectivityFilter->SetInput(cleaner->GetOutput()); connectivityFilter->SetExtractionModeToClosestPointRegion(); connectivityFilter->SetClosestPoint(point); connectivityFilter->Update(); section->DeepCopy(connectivityFilter->GetOutput()); section->GetPointData()->SetActiveVectors(this->VectorsArrayName); plane->Delete(); cutter->Delete(); cleaner->Delete(); connectivityFilter->Delete(); } else { double currentOrigin[3]; currentOrigin[0] = 0.0; currentOrigin[1] = 0.0; currentOrigin[2] = 0.0; double currentNormal[3]; currentNormal[0] = 0.0; currentNormal[1] = 0.0; currentNormal[2] = 1.0; double currentUpNormal[3]; currentUpNormal[0] = 0.0; currentUpNormal[1] = 1.0; currentUpNormal[2] = 0.0; double targetOrigin[3]; targetOrigin[0] = point[0]; targetOrigin[1] = point[1]; targetOrigin[2] = point[2]; double targetNormal[3]; targetNormal[0] = tangent[0]; targetNormal[1] = tangent[1]; targetNormal[2] = tangent[2]; double targetUpNormal[3]; targetUpNormal[0] = upNormal[0]; targetUpNormal[1] = upNormal[1]; targetUpNormal[2] = upNormal[2]; vtkTransform* transform = vtkTransform::New(); this->CreateTransform(transform,currentOrigin,currentNormal,currentUpNormal,targetOrigin,targetNormal,targetUpNormal); vtkTransformPolyDataFilter* transformFilter = vtkTransformPolyDataFilter::New(); transformFilter->SetInput(this->SectionSource); transformFilter->SetTransform(transform); transformFilter->Update(); vtkProbeFilter* probeFilter = vtkProbeFilter::New(); probeFilter->SetInput(transformFilter->GetOutput()); probeFilter->SetSource(input); probeFilter->Update(); section->DeepCopy(probeFilter->GetOutput()); section->GetPointData()->SetActiveVectors(this->VectorsArrayName); probeFilter->Delete(); transformFilter->Delete(); transform->Delete(); } vtkIdType numberOfSectionPoints = section->GetNumberOfPoints(); vtkIdTypeArray* sectionIdsArray = vtkIdTypeArray::New(); sectionIdsArray->SetName(this->SectionIdsArrayName); sectionIdsArray->SetNumberOfTuples(numberOfSectionPoints); vtkIdType pointId; for (pointId=0; pointIdSetValue(pointId,sectionId); } sectionId += 1; section->GetPointData()->AddArray(sectionIdsArray); if (!this->TransformSections) { appendFilter->AddInput(section); vtkIdType pointId = sectionPointsPoints->InsertNextPoint(point); sectionPointsVerts->InsertNextCell(1); sectionPointsVerts->InsertCellPoint(pointId); sectionPointsNormals->InsertNextTuple(tangent); if (upNormalsArray) { sectionPointsUpNormals->InsertNextTuple(upNormal); } if (additionalNormalsArray) { double additionalNormal[3]; additionalNormalsArray->GetTuple(centerlineCell->GetPointId(j),additionalNormal); sectionPointsAdditionalNormals->InsertNextTuple(additionalNormal); } if (additionalScalarsArray) { double scalar = additionalScalarsArray->GetTuple1(centerlineCell->GetPointId(j)); sectionPointsAdditionalScalars->InsertNextTuple1(scalar); } } else { double currentOrigin[3]; currentOrigin[0] = point[0]; currentOrigin[1] = point[1]; currentOrigin[2] = point[2]; double currentNormal[3]; currentNormal[0] = tangent[0]; currentNormal[1] = tangent[1]; currentNormal[2] = tangent[2]; double currentUpNormal[3]; currentUpNormal[0] = upNormal[0]; currentUpNormal[1] = upNormal[1]; currentUpNormal[2] = upNormal[2]; double targetOrigin[3]; targetOrigin[0] = j * this->OriginOffset[0]; targetOrigin[1] = j * this->OriginOffset[1]; targetOrigin[2] = j * this->OriginOffset[2]; double targetNormal[3]; targetNormal[0] = 0.0; targetNormal[1] = 0.0; targetNormal[2] = 1.0; double targetUpNormal[3]; targetUpNormal[0] = 0.0; targetUpNormal[1] = 1.0; targetUpNormal[2] = 0.0; vtkTransform* transform = vtkTransform::New(); this->CreateTransform(transform,currentOrigin,currentNormal,currentUpNormal,targetOrigin,targetNormal,targetUpNormal); vtkTransformPolyDataFilter* transformFilter = vtkTransformPolyDataFilter::New(); transformFilter->SetInput(section); transformFilter->SetTransform(transform); transformFilter->Update(); appendFilter->AddInput(transformFilter->GetOutput()); vtkIdType pointId = sectionPointsPoints->InsertNextPoint(targetOrigin); sectionPointsVerts->InsertNextCell(1); sectionPointsVerts->InsertCellPoint(pointId); sectionPointsNormals->InsertNextTuple(targetNormal); sectionPointsUpNormals->InsertNextTuple(targetUpNormal); if (additionalNormalsArray) { double additionalNormal[3], projectedAdditionalNormal[3], transformedAdditionalNormal[3]; additionalNormalsArray->GetTuple(centerlineCell->GetPointId(j),additionalNormal); double dot = vtkMath::Dot(additionalNormal,currentNormal); projectedAdditionalNormal[0] = additionalNormal[0] - dot * currentNormal[0]; projectedAdditionalNormal[1] = additionalNormal[1] - dot * currentNormal[1]; projectedAdditionalNormal[2] = additionalNormal[2] - dot * currentNormal[2]; vtkMath::Normalize(projectedAdditionalNormal); transform->TransformNormal(projectedAdditionalNormal,transformedAdditionalNormal); sectionPointsAdditionalNormals->InsertNextTuple(transformedAdditionalNormal); } if (additionalScalarsArray) { double scalar = additionalScalarsArray->GetTuple1(centerlineCell->GetPointId(j)); sectionPointsAdditionalScalars->InsertNextTuple1(scalar); } transform->Delete(); transformFilter->Delete(); } section->Delete(); } } appendFilter->Update(); output->DeepCopy(appendFilter->GetOutput()); appendFilter->Delete(); sectionPointsPoints->Delete(); sectionPointsVerts->Delete(); sectionPointsAdditionalNormals->Delete(); sectionPointsAdditionalScalars->Delete(); return 1; } void vtkvmtkUnstructuredGridCenterlineSections::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBranchGeometry.cxx0000664000175000017500000004123611757446472026253 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBranchGeometry.cxx,v $ Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.12 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineBranchGeometry.h" #include "vtkvmtkCenterlineGeometry.h" #include "vtkvmtkCenterlineSmoothing.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkvmtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" // #define SPIRAL_TEST vtkCxxRevisionMacro(vtkvmtkCenterlineBranchGeometry, "$Revision: 1.12 $"); vtkStandardNewMacro(vtkvmtkCenterlineBranchGeometry); vtkvmtkCenterlineBranchGeometry::vtkvmtkCenterlineBranchGeometry() { this->RadiusArrayName = NULL; this->GroupIdsArrayName = NULL; this->BlankingArrayName = NULL; this->LengthArrayName = NULL; this->CurvatureArrayName = NULL; this->TorsionArrayName = NULL; this->TortuosityArrayName = NULL; this->MinSubsamplingSpacing = 0.1; this->SmoothingFactor = 0.01; this->NumberOfSmoothingIterations = 10; this->LineSubsampling = 1; this->SphereSubsampling = 1; this->LineSmoothing = 0; } vtkvmtkCenterlineBranchGeometry::~vtkvmtkCenterlineBranchGeometry() { if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->BlankingArrayName) { delete[] this->BlankingArrayName; this->BlankingArrayName = NULL; } if (this->LengthArrayName) { delete[] this->LengthArrayName; this->LengthArrayName = NULL; } if (this->CurvatureArrayName) { delete[] this->CurvatureArrayName; this->CurvatureArrayName = NULL; } if (this->TorsionArrayName) { delete[] this->TorsionArrayName; this->TorsionArrayName = NULL; } if (this->TortuosityArrayName) { delete[] this->TortuosityArrayName; this->TortuosityArrayName = NULL; } } int vtkvmtkCenterlineBranchGeometry::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->RadiusArrayName) { vtkErrorMacro(<<"RadiusArrayName not specified"); return 1; } vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { vtkErrorMacro(<<"RadiusArray 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->BlankingArrayName) { vtkErrorMacro(<<"BlankingArrayName not specified"); return 1; } vtkDataArray* blankingArray = input->GetCellData()->GetArray(this->BlankingArrayName); if (!blankingArray) { vtkErrorMacro(<<"BlankingArray with name specified does not exist"); return 1; } if (!this->LengthArrayName) { vtkErrorMacro(<<"LengthArrayName not specified"); return 1; } if (!this->CurvatureArrayName) { vtkErrorMacro(<<"CurvatureArrayName not specified"); return 1; } if (!this->TorsionArrayName) { vtkErrorMacro(<<"TorsionArrayName not specified"); return 1; } if (!this->TortuosityArrayName) { vtkErrorMacro(<<"TortuosityArrayName not specified"); return 1; } vtkDoubleArray* lengthArray = vtkDoubleArray::New(); lengthArray->SetName(this->LengthArrayName); vtkDoubleArray* curvatureArray = vtkDoubleArray::New(); curvatureArray->SetName(this->CurvatureArrayName); vtkDoubleArray* torsionArray = vtkDoubleArray::New(); torsionArray->SetName(this->TorsionArrayName); vtkDoubleArray* tortuosityArray = vtkDoubleArray::New(); tortuosityArray->SetName(this->TortuosityArrayName); vtkDoubleArray* branchGroupIdsArray = vtkDoubleArray::New(); branchGroupIdsArray->SetName(this->GroupIdsArrayName); output->GetPointData()->AddArray(lengthArray); output->GetPointData()->AddArray(curvatureArray); output->GetPointData()->AddArray(torsionArray); output->GetPointData()->AddArray(tortuosityArray); output->GetPointData()->AddArray(branchGroupIdsArray); vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputVerts = vtkCellArray::New(); output->SetPoints(outputPoints); output->SetVerts(outputVerts); vtkIdList* nonBlankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetNonBlankedGroupsIdList(input,this->GroupIdsArrayName,this->BlankingArrayName,nonBlankedGroupIds); for (int i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = nonBlankedGroupIds->GetId(i); double groupLength = this->ComputeGroupLength(input,groupId); double groupCurvature = this->ComputeGroupCurvature(input,groupId); double groupTorsion = this->ComputeGroupTorsion(input,groupId); double groupTortuosity = this->ComputeGroupTortuosity(input,groupId,groupLength); branchGroupIdsArray->InsertNextTuple1(groupId); lengthArray->InsertNextTuple1(groupLength); curvatureArray->InsertNextTuple1(groupCurvature); torsionArray->InsertNextTuple1(groupTorsion); tortuosityArray->InsertNextTuple1(groupTortuosity); double zeroPoint[3]; zeroPoint[0] = zeroPoint[1] = zeroPoint[2] = 0.0; vtkIdType pointId = outputPoints->InsertNextPoint(zeroPoint); outputVerts->InsertNextCell(1); outputVerts->InsertCellPoint(pointId); } nonBlankedGroupIds->Delete(); outputPoints->Delete(); outputVerts->Delete(); lengthArray->Delete(); curvatureArray->Delete(); torsionArray->Delete(); tortuosityArray->Delete(); branchGroupIdsArray->Delete(); return 1; } double vtkvmtkCenterlineBranchGeometry::ComputeGroupLength(vtkPolyData* input, int branchGroupId) { double groupLength = 0.0; vtkDataArray* groupIdsArray = input->GetCellData()->GetArray(this->GroupIdsArrayName); int numberOfCells = input->GetNumberOfCells(); double lengthWeightSum = 0.0; for (int i=0; i(groupIdsArray->GetComponent(i,0)); if (groupId != branchGroupId) { continue; } int numberOfCellPoints = input->GetCell(i)->GetNumberOfPoints(); double length = 0.0; double point0[3], point1[3]; for (int j=0; jGetCell(i)->GetPoints()->GetPoint(j,point0); input->GetCell(i)->GetPoints()->GetPoint(j+1,point1); length += sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); } groupLength += length; lengthWeightSum += 1.0; } groupLength /= lengthWeightSum; return groupLength; } double vtkvmtkCenterlineBranchGeometry::ComputeGroupCurvature(vtkPolyData* input, int branchGroupId) { double groupCurvature = 0.0; vtkDataArray* groupIdsArray = input->GetCellData()->GetArray(this->GroupIdsArrayName); int numberOfCells = input->GetNumberOfCells(); double groupCurvatureWeightSum = 0.0; for (int i=0; i(groupIdsArray->GetComponent(i,0)); if (groupId != branchGroupId) { continue; } vtkPoints* linePoints = vtkPoints::New(); #ifndef SPIRAL_TEST linePoints->DeepCopy(input->GetCell(i)->GetPoints()); #else int numberOfSectors = 5; for (int j=0; jInsertNextPoint(point); } #endif if (this->LineSmoothing) { vtkPoints* smoothLinePoints = vtkPoints::New(); vtkvmtkCenterlineSmoothing::SmoothLine(linePoints,smoothLinePoints,this->NumberOfSmoothingIterations,this->SmoothingFactor); linePoints->DeepCopy(smoothLinePoints); smoothLinePoints->Delete(); } if (this->LineSubsampling) { vtkPoints* subsampledLinePoints = vtkPoints::New(); if (this->SphereSubsampling) { this->SphereSubsampleLine(input,i,subsampledLinePoints); } else { this->SubsampleLine(linePoints,subsampledLinePoints,this->MinSubsamplingSpacing); } linePoints->DeepCopy(subsampledLinePoints); subsampledLinePoints->Delete(); } vtkDoubleArray* curvatureArray = vtkDoubleArray::New(); double curvature = vtkvmtkCenterlineGeometry::ComputeLineCurvature(linePoints,curvatureArray); curvatureArray->Delete(); groupCurvature += curvature; groupCurvatureWeightSum += 1.0; } groupCurvature /= groupCurvatureWeightSum; // cout<<"Group curvature:"<GetCellData()->GetArray(this->GroupIdsArrayName); int numberOfCells = input->GetNumberOfCells(); double groupTorsionWeightSum = 0.0; for (int i=0; i(groupIdsArray->GetComponent(i,0)); if (groupId != branchGroupId) { continue; } vtkPoints* linePoints = vtkPoints::New(); #ifndef SPIRAL_TEST linePoints->DeepCopy(input->GetCell(i)->GetPoints()); #else int numberOfSectors = 5; for (int j=0; jInsertNextPoint(point); } #endif if (this->LineSmoothing) { vtkPoints* smoothLinePoints = vtkPoints::New(); vtkvmtkCenterlineSmoothing::SmoothLine(linePoints,smoothLinePoints,this->NumberOfSmoothingIterations,this->SmoothingFactor); linePoints->DeepCopy(smoothLinePoints); smoothLinePoints->Delete(); } if (this->LineSubsampling) { vtkPoints* subsampledLinePoints = vtkPoints::New(); if (this->SphereSubsampling) { this->SphereSubsampleLine(input,i,subsampledLinePoints); } else { this->SubsampleLine(linePoints,subsampledLinePoints,this->MinSubsamplingSpacing); } linePoints->DeepCopy(subsampledLinePoints); subsampledLinePoints->Delete(); } vtkDoubleArray* torsionArray = vtkDoubleArray::New(); double torsion = vtkvmtkCenterlineGeometry::ComputeLineTorsion(linePoints,torsionArray); torsionArray->Delete(); linePoints->Delete(); groupTorsion += torsion; groupTorsionWeightSum += 1.0; } groupTorsion /= groupTorsionWeightSum; // cout<<"Group torsion:"<GetNumberOfPoints(); double point0[3]; double point1[3]; double spacing = 0.0; linePoints->GetPoint(0,point0); subsampledLinePoints->InsertNextPoint(point0); for (int j=1; jGetPoint(j,point1); spacing += sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); if (spacing < minSpacing) { continue; } subsampledLinePoints->InsertNextPoint(point1); linePoints->GetPoint(j,point0); spacing = 0.0; } linePoints->GetPoint(numberOfPoints-1,point1); spacing = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); if (spacingGetNumberOfPoints(); subsampledLinePoints->InsertPoint(numberOfSubsampledPoints-1,point1); } else { subsampledLinePoints->InsertNextPoint(point1); } } void vtkvmtkCenterlineBranchGeometry::SphereSubsampleLine(vtkPolyData* input, vtkIdType cellId, vtkPoints* subsampledLinePoints) { vtkIdType subId = 0; double pcoord = 0.0; vtkIdType touchingSubId = 0; double touchingPCoord = 0.0; double point[3]; double point0[3]; double point1[3]; subsampledLinePoints->InsertNextPoint(input->GetCell(cellId)->GetPoints()->GetPoint(0)); while (touchingSubId != -1) { vtkvmtkCenterlineSphereDistance::FindTouchingSphereCenter(input, this->RadiusArrayName, cellId, subId, pcoord, touchingSubId, touchingPCoord, false); if (touchingSubId == -1) { break; } input->GetCell(cellId)->GetPoints()->GetPoint(touchingSubId,point0); input->GetCell(cellId)->GetPoints()->GetPoint(touchingSubId+1,point1); point[0] = (1.0 - touchingPCoord) * point0[0] + touchingPCoord * point1[0]; point[1] = (1.0 - touchingPCoord) * point0[1] + touchingPCoord * point1[1]; point[2] = (1.0 - touchingPCoord) * point0[2] + touchingPCoord * point1[2]; subsampledLinePoints->InsertNextPoint(point); subId = touchingSubId; pcoord = touchingPCoord; } subsampledLinePoints->InsertNextPoint(input->GetCell(cellId)->GetPoints()->GetPoint(input->GetCell(cellId)->GetNumberOfPoints()-1)); } double vtkvmtkCenterlineBranchGeometry::ComputeGroupTortuosity(vtkPolyData* input, int branchGroupId, double groupLength) { double groupTortuosity = 0.0; vtkDataArray* groupIdsArray = input->GetCellData()->GetArray(this->GroupIdsArrayName); vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); int numberOfCells = input->GetNumberOfCells(); double averageFirstPoint[3], averageLastPoint[3]; averageFirstPoint[0] = averageFirstPoint[1] = averageFirstPoint[2] = 0.0; averageLastPoint[0] = averageLastPoint[1] = averageLastPoint[2] = 0.0; double firstPointWeightSum = 0.0; double lastPointWeightSum = 0.0; for (int i=0; i(groupIdsArray->GetComponent(i,0)); if (groupId != branchGroupId) { continue; } int numberOfCellPoints = input->GetCell(i)->GetNumberOfPoints(); double firstPoint[3], lastPoint[3]; input->GetCell(i)->GetPoints()->GetPoint(0,firstPoint); input->GetCell(i)->GetPoints()->GetPoint(numberOfCellPoints-1,lastPoint); double firstPointRadius = radiusArray->GetComponent(input->GetCell(i)->GetPointId(0),0); double lastPointRadius = radiusArray->GetComponent(input->GetCell(i)->GetPointId(numberOfCellPoints-1),0); averageFirstPoint[0] += firstPointRadius * firstPointRadius * firstPoint[0]; averageFirstPoint[1] += firstPointRadius * firstPointRadius * firstPoint[1]; averageFirstPoint[2] += firstPointRadius * firstPointRadius * firstPoint[2]; firstPointWeightSum += firstPointRadius * firstPointRadius; averageLastPoint[0] += lastPointRadius * lastPointRadius * lastPoint[0]; averageLastPoint[1] += lastPointRadius * lastPointRadius * lastPoint[1]; averageLastPoint[2] += lastPointRadius * lastPointRadius * lastPoint[2]; lastPointWeightSum += lastPointRadius * lastPointRadius; } averageFirstPoint[0] /= firstPointWeightSum; averageFirstPoint[1] /= firstPointWeightSum; averageFirstPoint[2] /= firstPointWeightSum; averageLastPoint[0] /= lastPointWeightSum; averageLastPoint[1] /= lastPointWeightSum; averageLastPoint[2] /= lastPointWeightSum; groupTortuosity = groupLength / sqrt(vtkMath::Distance2BetweenPoints(averageFirstPoint,averageLastPoint)) - 1.0; return groupTortuosity; } void vtkvmtkCenterlineBranchGeometry::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkMinHeap.h0000664000175000017500000000744211757446472022300 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkMinHeap.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkMinHeap - Implementation of the min heap data structure. // .SECTION Description // This class is an implementation of the min heap data structure, used to handle a set of values in such a way that the retrieval of the minimum element takes constant time. A min heap is a complete binary tree where the value at each node is equal or less than the value at its children, and it is represented as an array where the children of a node stored at location k are at location 2k and 2k+1 (so that the parent of k is located at k/2). Keeping the min heap ordered after a value is updated or an id is inserted in teh heap takes O(log N). // // In the present implementation, values are provided in a vtkDoubleArray, and element ids are inserted in the heap. Backpointers are used to access the heap by id. This class is optimized for working in conjunction with vtkNonManifoldFastMarching. // // For more insight see J.A. Sethian, Level Set Methods and Fast Marching Methods, Cambridge University Press, 2nd Edition, 1999. // .SECTION Caveats // Be sure to call Initialize() after defining MinHeapScalars. // .SECTION See Also // vtkNonManifoldFastMarching #ifndef __vtkvmtkMinHeap_h #define __vtkvmtkMinHeap_h #include "vtkObject.h" #include "vtkDoubleArray.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkMinHeap : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkMinHeap,vtkObject); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkMinHeap *New(); // Description: // Initializes the heap to an empty state and prepares back pointers. Calls this method before using the min heap once MinHeapScalars have been defined. void Initialize(); // Description: // Set/Get the array containing the values indexed by the min heap. vtkSetObjectMacro(MinHeapScalars,vtkDoubleArray); vtkGetObjectMacro(MinHeapScalars,vtkDoubleArray); // Description: // Get heap size. int GetSize(); // Description: // Insert an index to a value in HeapScalars in the min heap. void InsertNextId(vtkIdType id); // Description: // Tells the min heap that the value indexed by id has changed in MinHeapScalars array. void UpdateId(vtkIdType id); // Description: // Gets the id of the minimum value in the min heap. vtkIdType GetMin(); // Description: // Gets the id of the minimum value in the min heap and removes it from the min heap. vtkIdType RemoveMin(); protected: vtkvmtkMinHeap(); ~vtkvmtkMinHeap(); void Swap(vtkIdType loc0, vtkIdType loc1); int IsLeaf(vtkIdType loc); vtkIdType GetLeftChild(vtkIdType loc); vtkIdType GetRightChild(vtkIdType loc); vtkIdType GetParent(vtkIdType loc); void SiftUp(vtkIdType loc); void SiftDown(vtkIdType loc); vtkIdType RemoveAt(vtkIdType loc); vtkIdList* Heap; vtkIdList* BackPointers; vtkDoubleArray* MinHeapScalars; private: vtkvmtkMinHeap(const vtkvmtkMinHeap&); // Not implemented. void operator=(const vtkvmtkMinHeap&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSplittingAndGroupingFilter.cxx0000664000175000017500000006336611757446472030633 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineSplittingAndGroupingFilter.cxx,v $ Language: C++ Date: $Date: 2006/07/07 10:46:19 $ Version: $Revision: 1.11 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineSplittingAndGroupingFilter.h" #include "vtkvmtkPolyBallLine.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkLine.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkIdList.h" #include "vtkIntArray.h" #include "vtkDoubleArray.h" #include "vtkAppendPolyData.h" #include "vtkvmtkConstants.h" #include "vtkMath.h" #include "vtkvmtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineSplittingAndGroupingFilter, "$Revision: 1.11 $"); vtkvmtkCenterlineSplittingAndGroupingFilter::vtkvmtkCenterlineSplittingAndGroupingFilter() { this->RadiusArrayName = NULL; this->GroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->BlankingArrayName = NULL; this->TractIdsArrayName = NULL; this->NumberOfSplittingPoints = 0; this->SubIds = NULL; this->PCoords = NULL; this->TractBlanking = NULL; this->GroupingMode = POINTINTUBE; } vtkvmtkCenterlineSplittingAndGroupingFilter::~vtkvmtkCenterlineSplittingAndGroupingFilter() { if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->CenterlineIdsArrayName) { delete[] this->CenterlineIdsArrayName; this->CenterlineIdsArrayName = NULL; } if (this->BlankingArrayName) { delete[] this->BlankingArrayName; this->BlankingArrayName = NULL; } if (this->TractIdsArrayName) { delete[] this->TractIdsArrayName; this->TractIdsArrayName = NULL; } if (this->SubIds) { delete[] this->SubIds; this->SubIds = NULL; } if (this->PCoords) { delete[] this->PCoords; this->PCoords = NULL; } if (this->TractBlanking) { delete[] this->TractBlanking; this->TractBlanking = NULL; } } int vtkvmtkCenterlineSplittingAndGroupingFilter::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 numberOfInputCells; if (!this->RadiusArrayName) { vtkErrorMacro(<<"RadiusArrayName not specified"); return 1; } if (!input->GetPointData()->GetArray(this->RadiusArrayName)) { vtkErrorMacro(<<"RadiusArray with name specified does not exist"); return 1; } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not specified"); return 1; } if (!this->CenterlineIdsArrayName) { vtkErrorMacro(<<"CenterlineIdsArrayName not specified"); return 1; } if (!this->BlankingArrayName) { vtkErrorMacro(<<"BlankingArrayName not specified"); return 1; } if (!this->TractIdsArrayName) { vtkErrorMacro(<<"TractIdsArrayName not specified"); return 1; } numberOfInputCells = input->GetNumberOfCells(); vtkAppendPolyData* appendCenterlinesFilter = vtkAppendPolyData::New(); for (int i=0; iComputeCenterlineSplitting(input,i); vtkPolyData* splitCenterline = vtkPolyData::New(); this->SplitCenterline(input,i,this->NumberOfSplittingPoints,this->SubIds,this->PCoords,this->TractBlanking,splitCenterline); appendCenterlinesFilter->AddInput(splitCenterline); splitCenterline->Delete(); } appendCenterlinesFilter->Update(); vtkPolyData* centerlineTracts = vtkPolyData::New(); centerlineTracts->DeepCopy(appendCenterlinesFilter->GetOutput()); appendCenterlinesFilter->Delete(); this->GroupTracts(input,centerlineTracts); this->MergeTracts(centerlineTracts); //FIXME: now, ill situations may still occour after merging: a branch that was inbetween two same-group and has been merged, might have had a buddy that didn't need to be merged on another centerline. In that case ehat should we do? Leave the other one alone? Or rething the whole thing once for all? this->MakeGroupIdsAdjacent(centerlineTracts); this->MakeTractIdsAdjacent(centerlineTracts); output->DeepCopy(centerlineTracts); centerlineTracts->Delete(); return 1; } void vtkvmtkCenterlineSplittingAndGroupingFilter::MergeTracts(vtkPolyData* centerlineTracts) { int numberOfCenterlineCells = centerlineTracts->GetNumberOfCells(); vtkPolyData* mergedCenterlineTracts = vtkPolyData::New(); vtkPoints* mergedCenterlineTractsPoints = vtkPoints::New(); mergedCenterlineTractsPoints->DeepCopy(centerlineTracts->GetPoints()); mergedCenterlineTracts->SetPoints(mergedCenterlineTractsPoints); mergedCenterlineTracts->GetPointData()->DeepCopy(centerlineTracts->GetPointData()); mergedCenterlineTracts->GetCellData()->CopyAllocate(centerlineTracts->GetCellData()); vtkCellArray* mergedCellArray = vtkCellArray::New(); vtkIntArray* groupIdsArray = vtkIntArray::SafeDownCast(centerlineTracts->GetCellData()->GetArray(this->GroupIdsArrayName)); vtkIdList* centerlineCellIds = vtkIdList::New(); int i; for (i=0; iInitialize(); vtkvmtkCenterlineUtilities::GetCenterlineCellIds(centerlineTracts,this->CenterlineIdsArrayName,this->TractIdsArrayName,i,centerlineCellIds); int numberOfCenterlineTracts = centerlineCellIds->GetNumberOfIds(); //loop over groupids and keep track of merges (a bit redundant, but clearer) int j; for (j=0; jGetId(j); int groupId = groupIdsArray->GetValue(tractCellId); int k; for (k=numberOfCenterlineTracts-1; k > j; k--) { int downstreamTractCellId = centerlineCellIds->GetId(k); if (groupId == groupIdsArray->GetValue(downstreamTractCellId)) { //merge from j to k int l; for (l=j+1; lSetValue(centerlineCellIds->GetId(l),groupId); } } } } // at this point we have to merge based on the repeated groupIds (which are now adjacent) vtkIdList* tractCellPointIds = vtkIdList::New(); vtkIdList* mergedCellPointIds = vtkIdList::New(); int previousGroupId = -1; int currentMergedCellId = -1; int firstTractCellId = 0; for (j=0; jGetId(j); centerlineTracts->GetCellPoints(tractCellId,tractCellPointIds); int groupId = groupIdsArray->GetValue(tractCellId); if ((groupId != previousGroupId) || (j == numberOfCenterlineTracts-1)) { if (previousGroupId != -1) { currentMergedCellId = mergedCellArray->InsertNextCell(mergedCellPointIds); mergedCenterlineTracts->GetCellData()->CopyData(centerlineTracts->GetCellData(),firstTractCellId,currentMergedCellId); } firstTractCellId = tractCellId; mergedCellPointIds->DeepCopy(tractCellPointIds); if (j == numberOfCenterlineTracts-1) { currentMergedCellId = mergedCellArray->InsertNextCell(mergedCellPointIds); mergedCenterlineTracts->GetCellData()->CopyData(centerlineTracts->GetCellData(),firstTractCellId,currentMergedCellId); } } else { int numberOfTractCellPoints = tractCellPointIds->GetNumberOfIds(); int k; for (k=1; kInsertNextId(tractCellPointIds->GetId(k)); } } previousGroupId = groupId; } tractCellPointIds->Delete(); mergedCellPointIds->Delete(); } mergedCenterlineTracts->SetLines(mergedCellArray); centerlineTracts->DeepCopy(mergedCenterlineTracts); mergedCellArray->Delete(); mergedCenterlineTracts->Delete(); mergedCenterlineTractsPoints->Delete(); centerlineCellIds->Delete(); } void vtkvmtkCenterlineSplittingAndGroupingFilter::GroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts) { switch (this->GroupingMode) { case FIRSTPOINT: this->CoincidentExtremePointGroupTracts(input,centerlineTracts,true); break; case LASTPOINT: this->CoincidentExtremePointGroupTracts(input,centerlineTracts,false); break; case POINTINTUBE: this->PointInTubeGroupTracts(input,centerlineTracts); break; default: vtkErrorMacro("Unknown GroupingMode"); } } void vtkvmtkCenterlineSplittingAndGroupingFilter::CoincidentExtremePointGroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts, bool first) { vtkIntArray* groupIdsArray = vtkIntArray::New(); groupIdsArray->SetName(this->GroupIdsArrayName); int numberOfCells = centerlineTracts->GetNumberOfCells(); groupIdsArray->SetNumberOfComponents(1); groupIdsArray->SetNumberOfTuples(numberOfCells); int i; for (i=0; iSetValue(i,i); } // group based on point-in-tube criterion for (i=0; iGetCell(i)->GetCellType() != VTK_LINE && centerlineTracts->GetCell(i)->GetCellType() != VTK_POLY_LINE) { continue; } int tractGroupId = groupIdsArray->GetValue(i); double point[3]; if (first) { centerlineTracts->GetCell(i)->GetPoints()->GetPoint(0,point); } else { int numberOfCellPoints = centerlineTracts->GetCell(i)->GetNumberOfPoints(); centerlineTracts->GetCell(i)->GetPoints()->GetPoint(numberOfCellPoints-1,point); } int j; for (j=i; jGetCell(j)->GetPoints()->GetPoint(0,currentPoint); } else { int numberOfCellPoints = centerlineTracts->GetCell(j)->GetNumberOfPoints(); centerlineTracts->GetCell(j)->GetPoints()->GetPoint(numberOfCellPoints-1,currentPoint); } if (sqrt(vtkMath::Distance2BetweenPoints(point,currentPoint)) < VTK_VMTK_DOUBLE_TOL) { groupIdsArray->SetValue(j,tractGroupId); } } } centerlineTracts->GetCellData()->AddArray(groupIdsArray); groupIdsArray->Delete(); } void vtkvmtkCenterlineSplittingAndGroupingFilter::PointInTubeGroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts) { vtkIntArray* blankingArray = vtkIntArray::SafeDownCast(centerlineTracts->GetCellData()->GetArray(this->BlankingArrayName)); vtkIntArray* centerlineIdsArray = vtkIntArray::SafeDownCast(centerlineTracts->GetCellData()->GetArray(this->CenterlineIdsArrayName)); vtkIntArray* groupIdsArray = vtkIntArray::New(); groupIdsArray->SetName(this->GroupIdsArrayName); int numberOfCells = centerlineTracts->GetNumberOfCells(); groupIdsArray->SetNumberOfComponents(1); groupIdsArray->SetNumberOfTuples(numberOfCells); int i; for (i=0; iSetValue(i,i); } vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New(); tube->SetInput(centerlineTracts); tube->SetPolyBallRadiusArrayName(this->RadiusArrayName); vtkIdList* tubeCellIds = vtkIdList::New(); vtkvmtkPolyBallLine* centerlineTube = vtkvmtkPolyBallLine::New(); centerlineTube->SetInput(centerlineTracts); centerlineTube->SetPolyBallRadiusArrayName(this->RadiusArrayName); vtkIdList* centerlineTubeCellIds = vtkIdList::New(); int numberOfCenterlineCells = input->GetNumberOfCells(); // group based on point-in-tube criterion for (i=0; iGetCell(i)->GetCellType() != VTK_LINE && centerlineTracts->GetCell(i)->GetCellType() != VTK_POLY_LINE) { continue; } centerlineTubeCellIds->Initialize(); centerlineTubeCellIds->InsertNextId(i); centerlineTube->SetInputCellIds(centerlineTubeCellIds); int centerlineGroupId = groupIdsArray->GetValue(i); int centerlineId = centerlineIdsArray->GetValue(i); for (int k=0; kGetValue(j); if (tubeCenterlineId != k) { continue; } int tubeCenterlineGroupId = groupIdsArray->GetValue(j); if (tubeCenterlineGroupId == centerlineGroupId) { centerlineTractAlreadyInGroup = true; } } if (centerlineTractAlreadyInGroup) { continue; } int sameGroupTubeGroupId = -1; for (j=0; jGetValue(j); if (tubeCenterlineId != k) { continue; } // don't group blanked tracts with non-blanked ones and vice-versa if (blankingArray->GetValue(i) != blankingArray->GetValue(j)) { continue; } if ((centerlineTracts->GetCell(j)->GetCellType() != VTK_POLY_LINE) && (centerlineTracts->GetCell(j)->GetCellType() != VTK_LINE)) { continue; } int tubeGroupId = groupIdsArray->GetValue(j); if (tubeGroupId == centerlineGroupId) { continue; } tubeCellIds->Initialize(); tubeCellIds->InsertNextId(j); tube->SetInputCellIds(tubeCellIds); bool pointInTube = false; double minTubeValue = VTK_VMTK_LARGE_DOUBLE; double minCenterlineTubeValue = VTK_VMTK_LARGE_DOUBLE; int l; // for (l=0; lGetCell(i)->GetNumberOfPoints(); l++) // any point in tube criterion for (l=0; l<=0; l++) // first point in tube criterion (divergent networks only) { double tubeValue = tube->EvaluateFunction(centerlineTracts->GetCell(i)->GetPoints()->GetPoint(l)); double centerlineTubeValue = centerlineTube->EvaluateFunction(tube->GetLastPolyBallCenter()); if ((tubeValue < -VTK_VMTK_DOUBLE_TOL) && (centerlineTubeValue < -VTK_VMTK_DOUBLE_TOL)) { pointInTube = true; if (tubeValue < minTubeValue) { minTubeValue = tubeValue; } if (centerlineTubeValue < minCenterlineTubeValue) { minCenterlineTubeValue = centerlineTubeValue; sameGroupTubeGroupId = tubeGroupId; } } } } if (sameGroupTubeGroupId == -1) { continue; } for (j=0; jGetNumberOfTuples(); j++) { if (groupIdsArray->GetValue(j) == sameGroupTubeGroupId) { groupIdsArray->SetValue(j,centerlineGroupId); } } } } centerlineTracts->GetCellData()->AddArray(groupIdsArray); groupIdsArray->Delete(); tube->Delete(); tubeCellIds->Delete(); } void vtkvmtkCenterlineSplittingAndGroupingFilter::MakeGroupIdsAdjacent(vtkPolyData* centerlineTracts) { vtkIntArray* groupIdsArray = vtkIntArray::SafeDownCast(centerlineTracts->GetCellData()->GetArray(this->GroupIdsArrayName)); int currentGroupId = 0; for (int i=0; iGetNumberOfTuples(); i++) { int minGroupId = VTK_VMTK_LARGE_INTEGER; int j; for (j=0; jGetNumberOfTuples(); j++) { int groupId = groupIdsArray->GetValue(j); if ((groupId= currentGroupId)) { minGroupId = groupId; } } for (j=0; jGetNumberOfTuples(); j++) { if (groupIdsArray->GetValue(j)==minGroupId) { groupIdsArray->SetValue(j,currentGroupId); } } ++currentGroupId; } } void vtkvmtkCenterlineSplittingAndGroupingFilter::MakeTractIdsAdjacent(vtkPolyData* centerlineTracts) { vtkIntArray* centerlineIdsArray = vtkIntArray::SafeDownCast(centerlineTracts->GetCellData()->GetArray(this->CenterlineIdsArrayName)); vtkIntArray* tractIdsArray = vtkIntArray::SafeDownCast(centerlineTracts->GetCellData()->GetArray(this->TractIdsArrayName)); vtkIdList* centerlineIds = vtkIdList::New(); for (int i=0; iGetNumberOfTuples(); i++) { int centerlineId = centerlineIdsArray->GetValue(i); centerlineIds->InsertUniqueId(centerlineId); } for (int i=0; iGetNumberOfIds(); i++) { int centerlineId = centerlineIds->GetId(i); vtkIdList* tractIdsMap = vtkIdList::New(); int maxTractId = -1; for (int j=0; jGetNumberOfTuples(); j++) { if (centerlineIdsArray->GetValue(j) != centerlineId) { continue; } int tractId = tractIdsArray->GetValue(j); if (tractId > maxTractId) { maxTractId = tractId; } } tractIdsMap->SetNumberOfIds(maxTractId+1); for (int j=0; jGetNumberOfIds(); j++) { tractIdsMap->SetId(j,0); } for (int j=0; jGetNumberOfTuples(); j++) { if (centerlineIdsArray->GetValue(j) != centerlineId) { continue; } int tractId = tractIdsArray->GetValue(j); tractIdsMap->SetId(tractId,1); } int currentTractId = 0; for (int j=0; jGetNumberOfIds(); j++) { if (tractIdsMap->GetId(j) == 0) { continue; } tractIdsMap->SetId(j,currentTractId); currentTractId += 1; } for (int j=0; jGetNumberOfTuples(); j++) { if (centerlineIdsArray->GetValue(j) != centerlineId) { continue; } int tractId = tractIdsArray->GetValue(j); tractIdsArray->SetValue(j,tractIdsMap->GetId(tractId)); } tractIdsMap->Delete(); } centerlineIds->Delete(); } void vtkvmtkCenterlineSplittingAndGroupingFilter::SplitCenterline(vtkPolyData* input, vtkIdType cellId, int numberOfSplittingPoints, const vtkIdType* subIds, const double* pcoords, const int* tractBlanking, vtkPolyData* splitCenterline) { vtkPointData* inputPD = input->GetPointData(); vtkCell* centerline = input->GetCell(cellId); if (centerline->GetCellType() != VTK_POLY_LINE && centerline->GetCellType() != VTK_LINE) { return; } vtkIdType numberOfCenterlinePoints = centerline->GetNumberOfPoints(); int numberOfTractPoints; splitCenterline->Initialize(); vtkPoints* splitCenterlinePoints = vtkPoints::New(); vtkCellArray* splitCenterlineCellArray = vtkCellArray::New(); vtkIdList* splitCenterlineCellPointIds = vtkIdList::New(); vtkPointData* splitCenterlinePD = splitCenterline->GetPointData(); vtkIntArray* centerlineIdsArray = vtkIntArray::New(); centerlineIdsArray->SetNumberOfComponents(1); centerlineIdsArray->SetName(this->CenterlineIdsArrayName); vtkIntArray* tractIdsArray = vtkIntArray::New(); tractIdsArray->SetNumberOfComponents(1); tractIdsArray->SetName(this->TractIdsArrayName); vtkIntArray* blankingArray = vtkIntArray::New(); blankingArray->SetNumberOfComponents(1); blankingArray->SetName(this->BlankingArrayName); int i; if (numberOfSplittingPoints == 0) { splitCenterlinePoints->DeepCopy(centerline->GetPoints()); splitCenterlineCellArray->InsertNextCell(numberOfCenterlinePoints); splitCenterlinePD->CopyAllocate(inputPD,numberOfCenterlinePoints); for (i=0; iCopyData(inputPD,centerline->GetPointId(i),i); splitCenterlineCellArray->InsertCellPoint(i); } centerlineIdsArray->InsertNextValue(cellId); tractIdsArray->InsertNextValue(0); blankingArray->InsertNextValue(0); splitCenterline->SetPoints(splitCenterlinePoints); splitCenterline->SetLines(splitCenterlineCellArray); splitCenterline->GetCellData()->CopyAllocate(input->GetCellData(),1); splitCenterline->GetCellData()->CopyData(input->GetCellData(),cellId,0); splitCenterline->GetCellData()->AddArray(centerlineIdsArray); splitCenterline->GetCellData()->AddArray(tractIdsArray); splitCenterline->GetCellData()->AddArray(blankingArray); splitCenterlinePoints->Delete(); splitCenterlineCellArray->Delete(); splitCenterlineCellPointIds->Delete(); centerlineIdsArray->Delete(); blankingArray->Delete(); return; } int numberOfSplitCenterlinePoints = 0; for (i=0; i<=numberOfSplittingPoints; i++) { if (tractBlanking[i] == 1) { continue; } vtkIdType lowerId, higherId; numberOfTractPoints = 0; if (i==0) { lowerId = 0; } else { lowerId = subIds[i-1]+1; numberOfTractPoints += 1; } if (i==numberOfSplittingPoints) { higherId = numberOfCenterlinePoints-1; } else { higherId = subIds[i]; numberOfTractPoints += 1; } if (higherId - lowerId > 0) { numberOfTractPoints += higherId - lowerId; } numberOfSplitCenterlinePoints += numberOfTractPoints; } splitCenterlinePD->InterpolateAllocate(inputPD,numberOfSplitCenterlinePoints); splitCenterline->GetCellData()->CopyAllocate(input->GetCellData(),numberOfSplittingPoints+1); for (i=0; i<=numberOfSplittingPoints; i++) { // if (tractBlanking[i] == 1) // { // // don't skip here! [Kept as a caveat!] // continue; // } splitCenterlineCellPointIds->Initialize(); vtkIdType lowerId, higherId; lowerId = (i == 0) ? 0 : subIds[i-1]+1; higherId = (i == numberOfSplittingPoints) ? numberOfCenterlinePoints-1 : subIds[i]; double point[3], point0[3], point1[3]; vtkIdType pointId; // insert first interpolated point if necessary int j, k; if (i>0) { centerline->GetPoints()->GetPoint(subIds[i-1],point0); centerline->GetPoints()->GetPoint(subIds[i-1]+1,point1); for (k=0; k<3; k++) { point[k] = point0[k] + pcoords[i-1]*(point1[k] - point0[k]); } if (vtkMath::Distance2BetweenPoints(point,centerline->GetPoints()->GetPoint(lowerId))>VTK_VMTK_FLOAT_TOL) { pointId = splitCenterlinePoints->InsertNextPoint(point); splitCenterlineCellPointIds->InsertNextId(pointId); splitCenterlinePD->InterpolateEdge(inputPD,pointId,centerline->GetPointId(subIds[i-1]),centerline->GetPointId(subIds[i-1]+1),pcoords[i-1]); } } for (j=lowerId; j<=higherId; j++) { pointId = splitCenterlinePoints->InsertNextPoint(centerline->GetPoints()->GetPoint(j)); splitCenterlineCellPointIds->InsertNextId(pointId); splitCenterlinePD->CopyData(inputPD,centerline->GetPointId(j),pointId); } // insert last interpolated point if necessary if (iGetPoints()->GetPoint(subIds[i],point0); centerline->GetPoints()->GetPoint(subIds[i]+1,point1); for (k=0; k<3; k++) { point[k] = point0[k] + pcoords[i]*(point1[k] - point0[k]); } if (vtkMath::Distance2BetweenPoints(point,centerline->GetPoints()->GetPoint(higherId))>VTK_VMTK_FLOAT_TOL) { pointId = splitCenterlinePoints->InsertNextPoint(point); splitCenterlineCellPointIds->InsertNextId(pointId); splitCenterlinePD->InterpolateEdge(inputPD,pointId,centerline->GetPointId(subIds[i]),centerline->GetPointId(subIds[i]+1),pcoords[i]); } } splitCenterlineCellArray->InsertNextCell(splitCenterlineCellPointIds); centerlineIdsArray->InsertNextValue(cellId); tractIdsArray->InsertNextValue(i); blankingArray->InsertNextValue(tractBlanking[i]); splitCenterline->GetCellData()->CopyData(input->GetCellData(),cellId,i); } splitCenterline->SetPoints(splitCenterlinePoints); splitCenterline->SetLines(splitCenterlineCellArray); splitCenterline->GetCellData()->AddArray(centerlineIdsArray); splitCenterline->GetCellData()->AddArray(tractIdsArray); splitCenterline->GetCellData()->AddArray(blankingArray); splitCenterlinePoints->Delete(); splitCenterlineCellArray->Delete(); splitCenterlineCellPointIds->Delete(); centerlineIdsArray->Delete(); blankingArray->Delete(); } void vtkvmtkCenterlineSplittingAndGroupingFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineAngularMetricFilter.h0000664000175000017500000000403611757446472030325 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineAngularMetricFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCenterlineAngularMetricFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataCenterlineAngularMetricFilter_h #define __vtkvmtkPolyDataCenterlineAngularMetricFilter_h #include "vtkvmtkPolyDataCenterlineMetricFilter.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlineAngularMetricFilter : public vtkvmtkPolyDataCenterlineMetricFilter { public: static vtkvmtkPolyDataCenterlineAngularMetricFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataCenterlineAngularMetricFilter,vtkvmtkPolyDataCenterlineMetricFilter); vtkSetStringMacro(CenterlineNormalsArrayName); vtkGetStringMacro(CenterlineNormalsArrayName); protected: vtkvmtkPolyDataCenterlineAngularMetricFilter(); ~vtkvmtkPolyDataCenterlineAngularMetricFilter(); virtual void EvaluateMetric(vtkIdType pointId, double point[3], vtkIdType groupId, vtkDataArray* metricArray); char* CenterlineNormalsArrayName; private: vtkvmtkPolyDataCenterlineAngularMetricFilter(const vtkvmtkPolyDataCenterlineAngularMetricFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataCenterlineAngularMetricFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineReferenceSystemAttributesOffset.h0000664000175000017500000000625511757446472031312 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineReferenceSystemAttributesOffset.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCenterlineReferenceSystemAttributesOffset - ... // .SECTION Description // ... #ifndef __vtkvmtkCenterlineReferenceSystemAttributesOffset_h #define __vtkvmtkCenterlineReferenceSystemAttributesOffset_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class vtkDoubleArray; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineReferenceSystemAttributesOffset : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCenterlineReferenceSystemAttributesOffset,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineReferenceSystemAttributesOffset* New(); vtkSetStringMacro(OffsetAbscissasArrayName); vtkGetStringMacro(OffsetAbscissasArrayName); vtkSetStringMacro(OffsetNormalsArrayName); vtkGetStringMacro(OffsetNormalsArrayName); vtkSetStringMacro(AbscissasArrayName); vtkGetStringMacro(AbscissasArrayName); vtkSetStringMacro(NormalsArrayName); vtkGetStringMacro(NormalsArrayName); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); vtkSetStringMacro(CenterlineIdsArrayName); vtkGetStringMacro(CenterlineIdsArrayName); vtkSetObjectMacro(ReferenceSystems,vtkPolyData); vtkGetObjectMacro(ReferenceSystems,vtkPolyData); vtkSetStringMacro(ReferenceSystemsNormalArrayName); vtkGetStringMacro(ReferenceSystemsNormalArrayName); vtkSetStringMacro(ReferenceSystemsGroupIdsArrayName); vtkGetStringMacro(ReferenceSystemsGroupIdsArrayName); vtkSetMacro(ReferenceGroupId,int); vtkGetMacro(ReferenceGroupId,int); protected: vtkvmtkCenterlineReferenceSystemAttributesOffset(); ~vtkvmtkCenterlineReferenceSystemAttributesOffset(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* OffsetAbscissasArrayName; char* OffsetNormalsArrayName; char* AbscissasArrayName; char* NormalsArrayName; char* GroupIdsArrayName; char* CenterlineIdsArrayName; vtkPolyData* ReferenceSystems; char* ReferenceSystemsNormalArrayName; char* ReferenceSystemsGroupIdsArrayName; int ReferenceGroupId; private: vtkvmtkCenterlineReferenceSystemAttributesOffset(const vtkvmtkCenterlineReferenceSystemAttributesOffset&); // Not implemented. void operator=(const vtkvmtkCenterlineReferenceSystemAttributesOffset&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBifurcationVectors.h0000664000175000017500000001206211757446472026575 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBifurcationVectors.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCenterlineBifurcationVectors - ... // .SECTION Description // ... #ifndef __vtkvmtkCenterlineBifurcationVectors_h #define __vtkvmtkCenterlineBifurcationVectors_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 vtkvmtkCenterlineBifurcationVectors : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCenterlineBifurcationVectors,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineBifurcationVectors* New(); vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); vtkSetStringMacro(CenterlineIdsArrayName); vtkGetStringMacro(CenterlineIdsArrayName); vtkSetStringMacro(TractIdsArrayName); vtkGetStringMacro(TractIdsArrayName); vtkSetStringMacro(BlankingArrayName); vtkGetStringMacro(BlankingArrayName); vtkSetObjectMacro(ReferenceSystems,vtkPolyData); vtkGetObjectMacro(ReferenceSystems,vtkPolyData); vtkSetStringMacro(ReferenceSystemGroupIdsArrayName); vtkGetStringMacro(ReferenceSystemGroupIdsArrayName); vtkSetStringMacro(ReferenceSystemNormalArrayName); vtkGetStringMacro(ReferenceSystemNormalArrayName); vtkSetStringMacro(ReferenceSystemUpNormalArrayName); vtkGetStringMacro(ReferenceSystemUpNormalArrayName); vtkSetStringMacro(BifurcationVectorsArrayName); vtkGetStringMacro(BifurcationVectorsArrayName); vtkSetStringMacro(InPlaneBifurcationVectorsArrayName); vtkGetStringMacro(InPlaneBifurcationVectorsArrayName); vtkSetStringMacro(OutOfPlaneBifurcationVectorsArrayName); vtkGetStringMacro(OutOfPlaneBifurcationVectorsArrayName); vtkSetStringMacro(InPlaneBifurcationVectorAnglesArrayName); vtkGetStringMacro(InPlaneBifurcationVectorAnglesArrayName); vtkSetStringMacro(OutOfPlaneBifurcationVectorAnglesArrayName); vtkGetStringMacro(OutOfPlaneBifurcationVectorAnglesArrayName); vtkSetStringMacro(BifurcationVectorsOrientationArrayName); vtkGetStringMacro(BifurcationVectorsOrientationArrayName); vtkSetStringMacro(BifurcationGroupIdsArrayName); vtkGetStringMacro(BifurcationGroupIdsArrayName); vtkSetMacro(NormalizeBifurcationVectors,int); vtkGetMacro(NormalizeBifurcationVectors,int); vtkBooleanMacro(NormalizeBifurcationVectors,int); //BTX enum { VTK_VMTK_UPSTREAM_ORIENTATION = 0, VTK_VMTK_DOWNSTREAM_ORIENTATION }; //ETX protected: vtkvmtkCenterlineBifurcationVectors(); ~vtkvmtkCenterlineBifurcationVectors(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ComputeBifurcationVectors(vtkPolyData* input, int bifurcationGroupId, vtkIdList* bifurcationVectorsGroupIds, vtkIntArray* bifurcationVectorsOrientation, vtkDoubleArray* bifurcationVectors, vtkPoints* bifurcationVectorsPoints); void ComputeBifurcationVectorComponents(int bifurcationGroupId, vtkDoubleArray* bifurcationVectors, vtkDoubleArray* inPlaneBifurcationVectors, vtkDoubleArray* outOfPlaneBifurcationVectors); void ComputeBifurcationVectorAngles(int bifurcationGroupId, vtkDoubleArray* bifurcationVectors, vtkDoubleArray* inPlaneBifurcationVectors, vtkDoubleArray* outOfPlaneBifurcationVectors, vtkDoubleArray* inPlaneBifurcationVectorAngles, vtkDoubleArray* outOfPlaneBifurcationVectorAngles); char* RadiusArrayName; char* GroupIdsArrayName; char* CenterlineIdsArrayName; char* TractIdsArrayName; char* BlankingArrayName; vtkPolyData* ReferenceSystems; char* ReferenceSystemGroupIdsArrayName; char* ReferenceSystemNormalArrayName; char* ReferenceSystemUpNormalArrayName; char* BifurcationVectorsArrayName; char* InPlaneBifurcationVectorsArrayName; char* OutOfPlaneBifurcationVectorsArrayName; char* BifurcationVectorsOrientationArrayName; char* InPlaneBifurcationVectorAnglesArrayName; char* OutOfPlaneBifurcationVectorAnglesArrayName; char* BifurcationGroupIdsArrayName; int NormalizeBifurcationVectors; private: vtkvmtkCenterlineBifurcationVectors(const vtkvmtkCenterlineBifurcationVectors&); // Not implemented. void operator=(const vtkvmtkCenterlineBifurcationVectors&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBranchGeometry.h0000664000175000017500000000743311757446472025701 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBranchGeometry.h,v $ Language: C++ Date: $Date: 2006/07/17 09:52:56 $ Version: $Revision: 1.8 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkCenterlineBranchGeometry,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter.cxx0000664000175000017500000004033411757446472032106 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkvmtkPolyBallLine.h" #include "vtkPolyLine.h" #include "vtkCellArray.h" #include "vtkObjectFactory.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkvmtkPolyBallLine.h" #include "vtkvmtkPolyDataBranchUtilities.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkReferenceSystemUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter); vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter::vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter() { this->BoundaryMetricArrayName = NULL; this->GroupIdsArrayName = NULL; this->Centerlines = NULL; this->CenterlineAbscissasArrayName = NULL; this->CenterlineRadiusArrayName = NULL; this->CenterlineGroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->CenterlineTractIdsArrayName = NULL; this->ReferenceSystems = NULL; this->ReferenceSystemGroupIdsArrayName = NULL; } vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter::~vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter() { if (this->BoundaryMetricArrayName) { delete[] this->BoundaryMetricArrayName; this->BoundaryMetricArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->Centerlines) { this->Centerlines->Delete(); this->Centerlines = NULL; } if (this->CenterlineAbscissasArrayName) { delete[] this->CenterlineAbscissasArrayName; this->CenterlineAbscissasArrayName = 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->ReferenceSystems) { this->ReferenceSystems->Delete(); this->ReferenceSystems = NULL; } if (this->ReferenceSystemGroupIdsArrayName) { delete[] this->ReferenceSystemGroupIdsArrayName; this->ReferenceSystemGroupIdsArrayName = NULL; } } int vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter::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->BoundaryMetricArrayName) { vtkErrorMacro(<<"BoundaryMetricArrayName not set."); return 1; } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not set."); 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->CenterlineAbscissasArrayName) { vtkErrorMacro(<<"CenterlineAbscissasArrayName not set."); return 1; } vtkDataArray* centerlineAbscissasArray = this->Centerlines->GetPointData()->GetArray(this->CenterlineAbscissasArrayName); if (!centerlineAbscissasArray) { vtkErrorMacro(<<"CenterlineAbscissasArray with name specified does not exist."); return 1; } if (!this->CenterlineRadiusArrayName) { vtkErrorMacro(<<"CenterlineRadiusArrayName not set."); 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 set."); return 1; } vtkDataArray* centerlineGroupIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineGroupIdsArrayName); if (!centerlineGroupIdsArray) { vtkErrorMacro(<<"CenterlineGroupIdsArrayName with name specified does not exist."); return 1; } if (!this->CenterlineIdsArrayName) { vtkErrorMacro(<<"CenterlineIdsArrayName not set."); return 1; } vtkDataArray* centerlineIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineIdsArrayName); if (!centerlineIdsArray) { vtkErrorMacro(<<"CenterlineIdsArrayName with name specified does not exist."); return 1; } if (!this->CenterlineTractIdsArrayName) { vtkErrorMacro(<<"CenterlineTractIdsArrayName not set."); return 1; } vtkDataArray* centerlineTractIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineTractIdsArrayName); if (!centerlineTractIdsArray) { vtkErrorMacro(<<"CenterlineTractIdsArrayName with name specified does not exist."); return 1; } if (!this->ReferenceSystems) { vtkErrorMacro(<<"ReferenceSystems not set"); return 1; } if (!this->ReferenceSystemGroupIdsArrayName) { vtkErrorMacro(<<"ReferenceSystemGroupIdsArrayName not set."); return 1; } vtkDataArray* referenceSystemGroupIdsArray = this->ReferenceSystems->GetPointData()->GetArray(this->ReferenceSystemGroupIdsArrayName); if (!referenceSystemGroupIdsArray) { vtkErrorMacro(<<"ReferenceSystemGroupIdsArrayName with name specified does not exist."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkDoubleArray* boundaryMetricArray = vtkDoubleArray::New(); boundaryMetricArray->SetName(this->BoundaryMetricArrayName); boundaryMetricArray->SetNumberOfComponents(1); boundaryMetricArray->SetNumberOfTuples(numberOfInputPoints); boundaryMetricArray->FillComponent(0,0.0); output->GetPointData()->AddArray(boundaryMetricArray); // for each group, find boundaries, find centerline group, see if it's adjacent to a bifurcation, get correspondent reference system origin, evaluate mean abscissa and put value on right boundary; if not adjacent to bifucation, just put extremal centerline abscissa. vtkIdList* groupIds = vtkIdList::New(); vtkvmtkPolyDataBranchUtilities::GetGroupsIdList(input,this->GroupIdsArrayName,groupIds); int i; for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = groupIds->GetId(i); vtkPolyData* cylinder = vtkPolyData::New(); vtkvmtkPolyDataBranchUtilities::ExtractGroup(input,this->GroupIdsArrayName,groupId,false,cylinder); vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(cylinder); boundaryExtractor->Update(); int numberOfBoundaries = boundaryExtractor->GetOutput()->GetNumberOfCells(); if (numberOfBoundaries != 2) { vtkErrorMacro(<<"Branch is not topologically a cylinder"); return 1; } vtkIdList* centerlineGroupCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,groupId,centerlineGroupCellIds); vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New(); tube->SetInput(this->Centerlines); tube->SetInputCellIds(centerlineGroupCellIds); tube->UseRadiusInformationOn(); tube->SetPolyBallRadiusArrayName(this->CenterlineRadiusArrayName); double boundaryAbscissa[2]; int j; for (j=0; jGetOutput()->GetCell(j)); if (boundary->GetNumberOfPoints() == 0) { vtkErrorMacro(<<"Zero-length boundary found"); return 1; } tube->EvaluateFunction(boundary->GetPoints()->GetPoint(0)); vtkIdType centerlineCellId = tube->GetLastPolyBallCellId(); vtkIdType centerlineSubId = tube->GetLastPolyBallCellSubId(); double centerlinePCoord = tube->GetLastPolyBallCellPCoord(); double abscissa = 0.0; vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->CenterlineAbscissasArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,abscissa); boundaryAbscissa[j] = abscissa; } int boundaryOrderedIds[2]; boundaryOrderedIds[0] = 0; boundaryOrderedIds[1] = 1; if (boundaryAbscissa[0] > boundaryAbscissa[1]) { boundaryOrderedIds[0] = 1; boundaryOrderedIds[1] = 0; } // see if centerline group is adjacent to a bifurcation, get correspondent reference system origin, evaluate mean abscissa and put value on boundary; if not adjacent to bifucation, just put extremal centerline abscissa. vtkIdList* upStreamGroupIds = vtkIdList::New(); vtkIdList* downStreamGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::FindAdjacentCenterlineGroupIds(this->Centerlines,this->CenterlineGroupIdsArrayName,this->CenterlineIdsArrayName,this->CenterlineTractIdsArrayName,groupId,upStreamGroupIds,downStreamGroupIds); if ((upStreamGroupIds->GetNumberOfIds() > 1) || (downStreamGroupIds->GetNumberOfIds() > 1)) { vtkErrorMacro(<<"More than one adjacent group found for current group. Not topologically a cylinder."); return 1; } vtkIdType referenceSystemGroupIds[2]; referenceSystemGroupIds[0] = -1; referenceSystemGroupIds[1] = -1; vtkIdType referenceSystemPointIds[2]; referenceSystemPointIds[0] = -1; referenceSystemPointIds[1] = -1; if (upStreamGroupIds->GetNumberOfIds() > 0) { referenceSystemGroupIds[0] = upStreamGroupIds->GetId(0); } if (downStreamGroupIds->GetNumberOfIds() > 0) { referenceSystemGroupIds[1] = downStreamGroupIds->GetId(0); } int n; for (n=0; n<2; n++) { if (referenceSystemGroupIds[n] == -1) { continue; } referenceSystemPointIds[n] = vtkvmtkReferenceSystemUtilities::GetReferenceSystemPointId(this->ReferenceSystems,this->ReferenceSystemGroupIdsArrayName,referenceSystemGroupIds[n]); if (referenceSystemPointIds[n] == -1) { vtkErrorMacro(<<"Centerline group ids and reference system group ids are inconsistent."); return 1; } } // now, we have the origins and the corresponding boundaries. Compute average origin abscissa and put it in on the right boundary. // if no boundary, put minimal abscissa in group double referenceSystemAbscissas[2]; referenceSystemAbscissas[0] = 0.0; referenceSystemAbscissas[1] = 0.0; for (n=0; n<2; n++) { if (referenceSystemGroupIds[n] != -1) { // Compute average origin abscissa and store it in referenceSystemAbscissas[n]. TODO: this one could be stored in ReferenceSystems as Abscissas array tube->UseRadiusInformationOff(); double weightSum = 0.0; vtkIdList* centerlineGroupAllCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,referenceSystemGroupIds[n],centerlineGroupAllCellIds); for (j=0; jGetNumberOfIds(); j++) { centerlineGroupCellIds->Initialize(); centerlineGroupCellIds->InsertNextId(centerlineGroupAllCellIds->GetId(j)); tube->SetInputCellIds(centerlineGroupCellIds); tube->EvaluateFunction(this->ReferenceSystems->GetPoint(referenceSystemPointIds[n])); vtkIdType centerlineCellId = tube->GetLastPolyBallCellId(); vtkIdType centerlineSubId = tube->GetLastPolyBallCellSubId(); double centerlinePCoord = tube->GetLastPolyBallCellPCoord(); double radius = 0.0; vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->CenterlineRadiusArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,radius); double weight = radius * radius; double abscissa = 0.0; vtkvmtkCenterlineUtilities::InterpolateTuple1(this->Centerlines,this->CenterlineAbscissasArrayName,centerlineCellId,centerlineSubId,centerlinePCoord,abscissa); referenceSystemAbscissas[n] += weight * abscissa; weightSum += weight; } referenceSystemAbscissas[n] /= weightSum; } else { // Compute extremal abscissa in group and store it in referenceSystemAbscissas[n] if (n==0) { referenceSystemAbscissas[n] = VTK_DOUBLE_MAX; vtkIdList* centerlineGroupCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,groupId,centerlineGroupCellIds); for (j=0; jGetNumberOfIds(); j++) { vtkIdType centerlineCellId = centerlineGroupCellIds->GetId(j); double abscissa = centerlineAbscissasArray->GetComponent(this->Centerlines->GetCell(centerlineCellId)->GetPointId(0),0); if (abscissa < referenceSystemAbscissas[n]) { referenceSystemAbscissas[n] = abscissa; } } centerlineGroupCellIds->Delete(); } else if (n==1) { referenceSystemAbscissas[n] = VTK_DOUBLE_MIN; vtkIdList* centerlineGroupCellIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetGroupCellIds(this->Centerlines,this->CenterlineGroupIdsArrayName,groupId,centerlineGroupCellIds); for (j=0; jGetNumberOfIds(); j++) { vtkIdType centerlineCellId = centerlineGroupCellIds->GetId(j); int numberOfCellPoints = this->Centerlines->GetCell(centerlineCellId)->GetNumberOfPoints(); double abscissa = centerlineAbscissasArray->GetComponent(this->Centerlines->GetCell(centerlineCellId)->GetPointId(numberOfCellPoints-1),0); if (abscissa > referenceSystemAbscissas[n]) { referenceSystemAbscissas[n] = abscissa; } } } } } // put abscissas in the right place for (n=0; n<2; n++) { vtkCell* boundary = boundaryExtractor->GetOutput()->GetCell(boundaryOrderedIds[n]); vtkDataArray* boundaryPointIds = boundaryExtractor->GetOutput()->GetPointData()->GetScalars(); int numberOfBoundaryPoints = boundary->GetNumberOfPoints(); for (j=0; j(boundaryPointIds->GetComponent(boundary->GetPointId(j),0)); boundaryMetricArray->SetComponent(boundaryPointId,0,referenceSystemAbscissas[n]); } } tube->Delete(); centerlineGroupCellIds->Delete(); boundaryExtractor->Delete(); cylinder->Delete(); upStreamGroupIds->Delete(); downStreamGroupIds->Delete(); } groupIds->Delete(); boundaryMetricArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkAppendFilter.h0000664000175000017500000000467711757446472023343 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkAppendFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:48 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkAppendFilter - ... // .SECTION Description // . // The RequestData method implementation is heavily based on the same method in vtkAppendFilter, // which is covered by the following copyright notice. /*========================================================================= Program: Visualization Toolkit Module: $RCSfile: vtkAppendFilter.h,v $ Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 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. =========================================================================*/ #ifndef __vtkvmtkAppendFilter_h #define __vtkvmtkAppendFilter_h #include "vtkAppendFilter.h" #include "vtkvmtkWin32Header.h" class vtkDataSetCollection; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkAppendFilter : public vtkAppendFilter { public: static vtkvmtkAppendFilter *New(); vtkTypeRevisionMacro(vtkvmtkAppendFilter,vtkAppendFilter); void PrintSelf(ostream& os, vtkIndent indent); vtkSetMacro(MergeDuplicatePoints,int); vtkGetMacro(MergeDuplicatePoints,int); vtkBooleanMacro(MergeDuplicatePoints,int); protected: vtkvmtkAppendFilter(); ~vtkvmtkAppendFilter(); // Usual data generation method virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); int MergeDuplicatePoints; private: vtkvmtkAppendFilter(const vtkvmtkAppendFilter&); // Not implemented. void operator=(const vtkvmtkAppendFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineSections.cxx0000664000175000017500000003052311757446472026564 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineSections.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataCenterlineSections.h" #include "vtkvmtkPolyDataBranchSections.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkPolygon.h" #include "vtkTriangle.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkPlane.h" #include "vtkCutter.h" #include "vtkStripper.h" #include "vtkPolyDataConnectivityFilter.h" #include "vtkMath.h" #include "vtkCleanPolyData.h" #include "vtkAppendPolyData.h" #include "vtkvmtkMath.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" #include "vtkvmtkPolyDataBranchUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlineSections, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkPolyDataCenterlineSections); vtkvmtkPolyDataCenterlineSections::vtkvmtkPolyDataCenterlineSections() { this->Centerlines = NULL; this->CenterlineSectionAreaArrayName = NULL; this->CenterlineSectionMinSizeArrayName = NULL; this->CenterlineSectionMaxSizeArrayName = NULL; this->CenterlineSectionShapeArrayName = NULL; this->CenterlineSectionClosedArrayName = NULL; } vtkvmtkPolyDataCenterlineSections::~vtkvmtkPolyDataCenterlineSections() { if (this->Centerlines) { this->Centerlines->Delete(); this->Centerlines = NULL; } if (this->CenterlineSectionAreaArrayName) { delete[] this->CenterlineSectionAreaArrayName; this->CenterlineSectionAreaArrayName = NULL; } if (this->CenterlineSectionMinSizeArrayName) { delete[] this->CenterlineSectionMinSizeArrayName; this->CenterlineSectionMinSizeArrayName = NULL; } if (this->CenterlineSectionMaxSizeArrayName) { delete[] this->CenterlineSectionMaxSizeArrayName; this->CenterlineSectionMaxSizeArrayName = NULL; } if (this->CenterlineSectionShapeArrayName) { delete[] this->CenterlineSectionShapeArrayName; this->CenterlineSectionShapeArrayName = NULL; } if (this->CenterlineSectionClosedArrayName) { delete[] this->CenterlineSectionClosedArrayName; this->CenterlineSectionClosedArrayName = NULL; } } int vtkvmtkPolyDataCenterlineSections::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->CenterlineSectionAreaArrayName) { vtkErrorMacro(<<"CenterlineSectionAreaArrayName not specified"); return 1; } if (!CenterlineSectionMinSizeArrayName) { vtkErrorMacro(<<"CenterlineSectionMinSizeArrayName not specified"); return 1; } if (!CenterlineSectionMaxSizeArrayName) { vtkErrorMacro(<<"CenterlineSectionMaxSizeArrayName not specified"); return 1; } if (!CenterlineSectionShapeArrayName) { vtkErrorMacro(<<"CenterlineSectionShapeArrayName not specified"); return 1; } if (!CenterlineSectionClosedArrayName) { vtkErrorMacro(<<"CenterlineSectionClosedArrayName not specified"); return 1; } vtkPoints* outputPoints = vtkPoints::New(); vtkCellArray* outputPolys = vtkCellArray::New(); output->SetPoints(outputPoints); output->SetPolys(outputPolys); vtkDoubleArray* centerlineSectionAreaArray = vtkDoubleArray::New(); centerlineSectionAreaArray->SetName(this->CenterlineSectionAreaArrayName); vtkDoubleArray* centerlineSectionShapeArray = vtkDoubleArray::New(); centerlineSectionShapeArray->SetName(this->CenterlineSectionShapeArrayName); vtkDoubleArray* centerlineSectionMinSizeArray = vtkDoubleArray::New(); centerlineSectionMinSizeArray->SetName(this->CenterlineSectionMinSizeArrayName); vtkDoubleArray* centerlineSectionMaxSizeArray = vtkDoubleArray::New(); centerlineSectionMaxSizeArray->SetName(this->CenterlineSectionMaxSizeArrayName); vtkIntArray* centerlineSectionClosedArray = vtkIntArray::New(); centerlineSectionClosedArray->SetName(this->CenterlineSectionClosedArrayName); vtkDoubleArray* centerlineAreaArray = vtkDoubleArray::New(); centerlineAreaArray->SetName(this->CenterlineSectionAreaArrayName); vtkDoubleArray* centerlineShapeArray = vtkDoubleArray::New(); centerlineShapeArray->SetName(this->CenterlineSectionShapeArrayName); vtkDoubleArray* centerlineMinSizeArray = vtkDoubleArray::New(); centerlineMinSizeArray->SetName(this->CenterlineSectionMinSizeArrayName); vtkDoubleArray* centerlineMaxSizeArray = vtkDoubleArray::New(); centerlineMaxSizeArray->SetName(this->CenterlineSectionMaxSizeArrayName); vtkIntArray* centerlineClosedArray = vtkIntArray::New(); centerlineClosedArray->SetName(this->CenterlineSectionClosedArrayName); output->GetCellData()->AddArray(centerlineSectionAreaArray); output->GetCellData()->AddArray(centerlineSectionMinSizeArray); output->GetCellData()->AddArray(centerlineSectionMaxSizeArray); output->GetCellData()->AddArray(centerlineSectionShapeArray); output->GetCellData()->AddArray(centerlineSectionClosedArray); this->Centerlines->GetPointData()->AddArray(centerlineAreaArray); this->Centerlines->GetPointData()->AddArray(centerlineMinSizeArray); this->Centerlines->GetPointData()->AddArray(centerlineMaxSizeArray); this->Centerlines->GetPointData()->AddArray(centerlineShapeArray); this->Centerlines->GetPointData()->AddArray(centerlineClosedArray); int numberOfCenterlinePoints = this->Centerlines->GetNumberOfPoints(); centerlineAreaArray->SetNumberOfTuples(numberOfCenterlinePoints); centerlineMinSizeArray->SetNumberOfTuples(numberOfCenterlinePoints); centerlineMaxSizeArray->SetNumberOfTuples(numberOfCenterlinePoints); centerlineShapeArray->SetNumberOfTuples(numberOfCenterlinePoints); centerlineClosedArray->SetNumberOfTuples(numberOfCenterlinePoints); int numberOfCenterlineCells = this->Centerlines->GetNumberOfCells(); int i; for (i=0; iComputeCenterlineSections(input,i,output); } outputPoints->Delete(); outputPolys->Delete(); centerlineSectionAreaArray->Delete(); centerlineSectionMinSizeArray->Delete(); centerlineSectionMaxSizeArray->Delete(); centerlineSectionShapeArray->Delete(); centerlineSectionClosedArray->Delete(); centerlineAreaArray->Delete(); centerlineMinSizeArray->Delete(); centerlineMaxSizeArray->Delete(); centerlineShapeArray->Delete(); centerlineClosedArray->Delete(); return 1; } void vtkvmtkPolyDataCenterlineSections::ComputeCenterlineSections(vtkPolyData* input, int cellId, vtkPolyData* output) { vtkPoints* centerlineSectionPoints = output->GetPoints(); vtkCellArray* centerlineSectionPolys = output->GetPolys(); vtkDoubleArray* centerlineSectionAreaArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->CenterlineSectionAreaArrayName)); vtkDoubleArray* centerlineSectionMinSizeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->CenterlineSectionMinSizeArrayName)); vtkDoubleArray* centerlineSectionMaxSizeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->CenterlineSectionMaxSizeArrayName)); vtkDoubleArray* centerlineSectionShapeArray = vtkDoubleArray::SafeDownCast(output->GetCellData()->GetArray(this->CenterlineSectionShapeArrayName)); vtkIntArray* centerlineSectionClosedArray = vtkIntArray::SafeDownCast(output->GetCellData()->GetArray(this->CenterlineSectionClosedArrayName)); vtkDoubleArray* centerlineAreaArray = vtkDoubleArray::SafeDownCast(this->Centerlines->GetPointData()->GetArray(this->CenterlineSectionAreaArrayName)); vtkDoubleArray* centerlineMinSizeArray = vtkDoubleArray::SafeDownCast(this->Centerlines->GetPointData()->GetArray(this->CenterlineSectionMinSizeArrayName)); vtkDoubleArray* centerlineMaxSizeArray = vtkDoubleArray::SafeDownCast(this->Centerlines->GetPointData()->GetArray(this->CenterlineSectionMaxSizeArrayName)); vtkDoubleArray* centerlineShapeArray = vtkDoubleArray::SafeDownCast(this->Centerlines->GetPointData()->GetArray(this->CenterlineSectionShapeArrayName)); vtkIntArray* centerlineClosedArray = vtkIntArray::SafeDownCast(this->Centerlines->GetPointData()->GetArray(this->CenterlineSectionClosedArrayName)); vtkCell* centerlineCell = this->Centerlines->GetCell(cellId); vtkPoints* centerlineCellPoints = centerlineCell->GetPoints(); int numberOfCellPoints = centerlineCellPoints->GetNumberOfPoints(); int i; for (i=0; iGetPoint(i,point); double tangent[3]; tangent[0] = tangent[1] = tangent[2] = 0.0; double weightSum = 0.0; if (i>0) { double point0[3], point1[3]; centerlineCellPoints->GetPoint(i-1,point0); centerlineCellPoints->GetPoint(i,point1); double distance = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); tangent[0] += (point1[0] - point0[0]) / distance; tangent[1] += (point1[1] - point0[1]) / distance; tangent[2] += (point1[2] - point0[2]) / distance; weightSum += 1.0; } if (iGetPoint(i,point0); centerlineCellPoints->GetPoint(i+1,point1); double distance = sqrt(vtkMath::Distance2BetweenPoints(point0,point1)); tangent[0] += (point1[0] - point0[0]) / distance; tangent[1] += (point1[1] - point0[1]) / distance; tangent[2] += (point1[2] - point0[2]) / distance; weightSum += 1.0; } tangent[0] /= weightSum; tangent[1] /= weightSum; tangent[2] /= weightSum; vtkMath::Normalize(tangent); //now cut branch with plane and get section. Compute section properties and store them. vtkPolyData* section = vtkPolyData::New(); bool closed = false; vtkvmtkPolyDataBranchSections::ExtractCylinderSection(input,point,tangent,section,closed); section->BuildCells(); vtkPoints* sectionCellPoints = section->GetCell(0)->GetPoints(); int numberOfSectionCellPoints = sectionCellPoints->GetNumberOfPoints(); centerlineSectionPolys->InsertNextCell(numberOfSectionCellPoints); int k; for (k=0; kInsertNextPoint(sectionCellPoints->GetPoint(k)); centerlineSectionPolys->InsertCellPoint(branchPointId); } double area = vtkvmtkPolyDataBranchSections::ComputeBranchSectionArea(section); double sizeRange[2]; double shape = vtkvmtkPolyDataBranchSections::ComputeBranchSectionShape(section,point,sizeRange); centerlineSectionAreaArray->InsertNextValue(area); centerlineSectionMinSizeArray->InsertNextValue(sizeRange[0]); centerlineSectionMaxSizeArray->InsertNextValue(sizeRange[1]); centerlineSectionShapeArray->InsertNextValue(shape); centerlineSectionClosedArray->InsertNextValue(closed); vtkIdType pointId = centerlineCell->GetPointId(i); centerlineAreaArray->InsertValue(pointId,area); centerlineMinSizeArray->InsertValue(pointId,sizeRange[0]); centerlineMaxSizeArray->InsertValue(pointId,sizeRange[1]); centerlineShapeArray->InsertValue(pointId,shape); centerlineClosedArray->InsertValue(pointId,closed); section->Delete(); } } void vtkvmtkPolyDataCenterlineSections::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSplittingAndGroupingFilter.h0000664000175000017500000000703211757446472030244 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineSplittingAndGroupingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkCenterlineSplittingAndGroupingFilter - ... // .SECTION Description // ... #ifndef __vtkvmtkCenterlineSplittingAndGroupingFilter_h #define __vtkvmtkCenterlineSplittingAndGroupingFilter_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkCenterlineSplittingAndGroupingFilter : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCenterlineSplittingAndGroupingFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); vtkSetStringMacro(CenterlineIdsArrayName); vtkGetStringMacro(CenterlineIdsArrayName); vtkSetStringMacro(BlankingArrayName); vtkGetStringMacro(BlankingArrayName); vtkSetStringMacro(TractIdsArrayName); vtkGetStringMacro(TractIdsArrayName); vtkSetMacro(GroupingMode,int); vtkGetMacro(GroupingMode,int); void SetGroupingModeToFirstPoint() { this->SetGroupingMode(FIRSTPOINT); } void SetGroupingModeToLastPoint() { this->SetGroupingMode(LASTPOINT); } void SetGroupingModeToPointInTube() { this->SetGroupingMode(POINTINTUBE); } //BTX enum { FIRSTPOINT, LASTPOINT, POINTINTUBE }; //ETX protected: vtkvmtkCenterlineSplittingAndGroupingFilter(); ~vtkvmtkCenterlineSplittingAndGroupingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); virtual void ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) = 0; virtual void GroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts); void CoincidentExtremePointGroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts, bool first = true); void PointInTubeGroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts); virtual void MergeTracts(vtkPolyData* centerlineTracts); void SplitCenterline(vtkPolyData* input, vtkIdType cellId, int numberOfSplittingPoints, const vtkIdType* subIds, const double* pcoords, const int* tractBlanking, vtkPolyData* splitCenterline); void MakeGroupIdsAdjacent(vtkPolyData* centerlineTracts); void MakeTractIdsAdjacent(vtkPolyData* centerlineTracts); char* RadiusArrayName; char* GroupIdsArrayName; char* CenterlineIdsArrayName; char* BlankingArrayName; char* TractIdsArrayName; int NumberOfSplittingPoints; vtkIdType* SubIds; double* PCoords; int* TractBlanking; int GroupingMode; private: vtkvmtkCenterlineSplittingAndGroupingFilter(const vtkvmtkCenterlineSplittingAndGroupingFilter&); // Not implemented. void operator=(const vtkvmtkCenterlineSplittingAndGroupingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBoundaryExtractor.cxx0000664000175000017500000001327411757446472026447 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBoundaryExtractor.cxx,v $ Language: C++ Date: $Date: 2006/07/27 08:27:26 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataBoundaryExtractor, "$Revision: 1.6 $"); 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; iGetNumberOfCells(); 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; iGetNumberOfIds(); 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; jGetNumberOfIds(); 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; nGetNumberOfIds(); 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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineAbscissaMetricFilter.cxx0000664000175000017500000001204011757446472031031 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineAbscissaMetricFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlineAbscissaMetricFilter, "$Revision: 1.7 $"); 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(centerlineGroupIdsArray->GetComponent(i,0)); if (centerlineGroupId != groupId) { continue; } centerlineGroupCellIds->Initialize(); centerlineGroupCellIds->InsertNextId(i); if (this->IncludeBifurcations) { int centerlineId = static_cast(centerlineIdsArray->GetComponent(i,0)); int centerlineTractId = static_cast(centerlineTractIdsArray->GetComponent(i,0)); for (int j=0; j(centerlineGroupIdsArray->GetComponent(j,0)); int adjacentCenterlineId = static_cast(centerlineIdsArray->GetComponent(j,0)); int adjacentCenterlineTractId = static_cast(centerlineTractIdsArray->GetComponent(j,0)); int adjacentBlanking = static_cast(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(); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkSimplifyVoronoiDiagram.cxx0000664000175000017500000002013611757446472025762 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSimplifyVoronoiDiagram.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSimplifyVoronoiDiagram.h" #include "vtkCellArray.h" #include "vtkCellTypes.h" #include "vtkCellLinks.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSimplifyVoronoiDiagram, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkSimplifyVoronoiDiagram); vtkvmtkSimplifyVoronoiDiagram::vtkvmtkSimplifyVoronoiDiagram() { this->UnremovablePointIds = NULL; this->UnremovableCellIds = NULL; this->Simplification = VTK_VMTK_REMOVE_BOUNDARY_POINTS; this->IncludeUnremovable = 1; this->OnePassOnly = 0; } vtkvmtkSimplifyVoronoiDiagram::~vtkvmtkSimplifyVoronoiDiagram() { if (this->UnremovablePointIds) { this->UnremovablePointIds->Delete(); this->UnremovablePointIds = NULL; } if (this->UnremovableCellIds) { this->UnremovableCellIds->Delete(); this->UnremovableCellIds = NULL; } } vtkIdType vtkvmtkSimplifyVoronoiDiagram::IsBoundaryEdge(vtkCellLinks* links, vtkIdType* edge) { vtkIdType j, k; vtkIdType cellId, ncells0, *cells0, ncells1, *cells1; ncells0 = links->GetNcells(edge[0]); cells0 = links->GetCells(edge[0]); ncells1 = links->GetNcells(edge[1]); cells1 = links->GetCells(edge[1]); cellId = -1; for (j=0; jGetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); vtkPolyData *input = vtkPolyData::SafeDownCast( inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); bool anyRemoved, removeCell, considerPoint; bool* isUnremovable; vtkIdType i, j, id; vtkIdType n; vtkIdType npts, *pts, ncells; npts = 0; pts = NULL; vtkIdType edge[2]; vtkCellArray *currentPolys; vtkCellLinks* currentLinks; vtkIdType newCellId; vtkCellArray* inputPolys = input->GetPolys(); currentPolys = vtkCellArray::New(); currentLinks = vtkCellLinks::New(); n = 0; if (this->Simplification==VTK_VMTK_REMOVE_BOUNDARY_POINTS) { n = input->GetNumberOfPoints(); } else if (this->Simplification==VTK_VMTK_REMOVE_BOUNDARY_CELLS) { n = inputPolys->GetNumberOfCells(); } isUnremovable = new bool[n]; bool anyUnremovable = false; for (i=0; iSimplification==VTK_VMTK_REMOVE_BOUNDARY_POINTS) { if (this->UnremovablePointIds) { for (i=0; iUnremovablePointIds->GetNumberOfIds(); i++) { id = this->UnremovablePointIds->GetId(i); if ((id >= 0) && (id < n)) { anyUnremovable = true; isUnremovable[id] = true; } else { vtkErrorMacro(<< "Out of range id found among UnremovablePointIds!"); } } } } else if (this->Simplification==VTK_VMTK_REMOVE_BOUNDARY_CELLS) { if (this->UnremovableCellIds) { for (i=0; iUnremovableCellIds->GetNumberOfIds(); i++) { id = this->UnremovableCellIds->GetId(i); if ((id >= 0) && (id < n)) { anyUnremovable = true; isUnremovable[id] = true; } else if (id<0) { vtkErrorMacro(<< "Out of range id found among UnremovableCellIds!"); } } } } currentPolys->DeepCopy(inputPolys); currentLinks->Allocate(input->GetNumberOfPoints()); currentLinks->BuildLinks(input,currentPolys); anyRemoved = true; while (anyRemoved) { anyRemoved = false; vtkCellArray* newPolys = vtkCellArray::New(); vtkIdList* newCell = vtkIdList::New(); currentPolys->InitTraversal(); for (i=0; iGetNumberOfCells(); i++) { currentPolys->GetNextCell(npts,pts); if (npts==0) { continue; } newCell->Initialize(); if (this->Simplification==VTK_VMTK_REMOVE_BOUNDARY_POINTS) { for (j=0; jGetNcells(pts[j]); if (ncells==1) { considerPoint = true; } if (considerPoint) { if (isUnremovable[pts[j]]) { newCell->InsertNextId(pts[j]); } else { anyRemoved = true; } } else { newCell->InsertNextId(pts[j]); } } } else if (this->Simplification==VTK_VMTK_REMOVE_BOUNDARY_CELLS) { removeCell = false; if (!isUnremovable[i]) { for (j=0; jIsBoundaryEdge(currentLinks,edge)>0) { removeCell = true; break; } } } if (removeCell) { anyRemoved = true; } else { for (j=0; jInsertNextId(pts[j]); } } } if (newCell->GetNumberOfIds() > 2) { newCellId = newPolys->InsertNextCell(newCell); } } currentPolys->DeepCopy(newPolys); currentLinks->Delete(); currentLinks = vtkCellLinks::New(); currentLinks->Allocate(input->GetNumberOfPoints()); currentLinks->BuildLinks(input,currentPolys); newPolys->Delete(); newCell->Delete(); if (this->OnePassOnly) { break; } } if (anyUnremovable && !this->IncludeUnremovable) { vtkCellArray* newPolys = vtkCellArray::New(); vtkIdList* newCell = vtkIdList::New(); currentPolys->InitTraversal(); for (i=0; iGetNumberOfCells(); i++) { currentPolys->GetNextCell(npts,pts); newCell->Initialize(); if (npts==0) { newPolys->InsertNextCell(npts,pts); continue; } if (!isUnremovable[i]) { for (j=0; jInsertNextId(pts[j]); } } if (newCell->GetNumberOfIds() > 2) { newPolys->InsertNextCell(newCell); } } currentPolys->DeepCopy(newPolys); newPolys->Delete(); newCell->Delete(); } // simply passes points and point data (eventually vtkCleanPolyData) output->SetPoints(input->GetPoints()); output->GetPointData()->PassData(input->GetPointData()); // WARNING: cell data are thrown away in the current version output->SetPolys(currentPolys); currentLinks->Delete(); currentPolys->Delete(); delete[] isUnremovable; return 1; } void vtkvmtkSimplifyVoronoiDiagram::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSphereDistance.cxx0000664000175000017500000001644411757446472026246 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineSphereDistance.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineSphereDistance.h" #include "vtkvmtkPolyBallLine.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkCellArray.h" #include "vtkIdList.h" #include "vtkIntArray.h" #include "vtkDoubleArray.h" #include "vtkAppendPolyData.h" #include "vtkvmtkConstants.h" #include "vtkMath.h" #include "vtkvmtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineSphereDistance, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkCenterlineSphereDistance); void vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(vtkPolyData* centerlines, const char* radiusArrayName, vtkIdType cellId, vtkIdType subId, double pcoord, int numberOfTouchingSpheres, vtkIdType& touchingSubId, double& touchingPCoord, bool forward) { vtkIdType dummySubId0, dummySubId1; double dummyPCoord0, dummyPCoord1; if (numberOfTouchingSpheres == 0) { touchingSubId = subId; touchingPCoord = pcoord; return; } dummySubId0 = subId; dummyPCoord0 = pcoord; for (int i=0; iGetCell(cellId); if (centerline->GetCellType() != VTK_LINE && centerline->GetCellType() != VTK_POLY_LINE) { return; } if (!radiusArrayName) { return; } vtkDataArray* radiusArray = centerlines->GetPointData()->GetArray(radiusArrayName); if (!radiusArray) { return; } vtkIdList* subIds = vtkIdList::New(); int k; if (forward) { for (k=0; kInsertNextId(k); } } else { for (k=centerline->GetNumberOfPoints()-2; k>subId; k--) { subIds->InsertNextId(k); } } double point[3], point0[3], point1[3]; centerline->GetPoints()->GetPoint(subId,point0); centerline->GetPoints()->GetPoint(subId+1,point1); for (k=0; k<3; k++) { point[k] = point0[k] + pcoord*(point1[k] - point0[k]); } vtkIdType centerId0, centerId1; double center0[3], center1[3], radius0, radius1; vtkIdType currentSubId; double currentPCoord; double sphereDistance0, sphereDistance1; touchingSubId = -1; touchingPCoord = 0.0; int i; for (i=0; iGetNumberOfIds(); i++) { currentSubId = subIds->GetId(i); centerId0 = centerline->GetPointId(currentSubId); centerId1 = centerline->GetPointId(currentSubId+1); centerlines->GetPoint(centerId0,center0); centerlines->GetPoint(centerId1,center1); radius0 = radiusArray->GetComponent(centerId0,0); radius1 = radiusArray->GetComponent(centerId1,0); sphereDistance0 = vtkvmtkMath::EvaluateSphereFunction(center0,radius0,point); sphereDistance1 = vtkvmtkMath::EvaluateSphereFunction(center1,radius1,point); if (forward) { if ((sphereDistance0 > 0.0) && (sphereDistance1 <= 0.0)) { touchingSubId = currentSubId; break; } } else { if ((sphereDistance0 <= 0.0) && (sphereDistance1 > 0.0)) { touchingSubId = currentSubId; break; } } } if (touchingSubId == -1) { centerId0 = centerline->GetPointId(subId); centerId1 = centerline->GetPointId(subId+1); centerlines->GetPoint(centerId0,center0); centerlines->GetPoint(centerId1,center1); radius0 = radiusArray->GetComponent(centerId0,0); radius1 = radiusArray->GetComponent(centerId1,0); sphereDistance0 = vtkvmtkMath::EvaluateSphereFunction(center0,radius0,point); sphereDistance1 = vtkvmtkMath::EvaluateSphereFunction(center1,radius1,point); if ((sphereDistance0<=0.0) && (sphereDistance1<=0.0)) { touchingSubId = -1; return; } touchingSubId = subId; } // optimize between (touchingSubId, touchingSubId+1) // linear search, step proportional to sphere radius. centerId0 = centerline->GetPointId(touchingSubId); centerId1 = centerline->GetPointId(touchingSubId+1); centerlines->GetPoint(centerId0,center0); centerlines->GetPoint(centerId1,center1); radius0 = radiusArray->GetComponent(centerId0,0); radius1 = radiusArray->GetComponent(centerId1,0); double segmentLength, stepSize, pcoordStepSize; int numberOfSteps; double subCenter0[3], subCenter1[3], subRadius0, subRadius1; segmentLength = vtkMath::Distance2BetweenPoints(center0,center1); stepSize = 1E-6 * (radius0 + radius1) / 2.0; numberOfSteps = (int)ceil(segmentLength / stepSize); stepSize = segmentLength / numberOfSteps; pcoordStepSize = 1.0 / (double)numberOfSteps; touchingPCoord = 0.0; currentPCoord = 0.0; for (i=0; i 0.0) && (sphereDistance1 <= 0.0)) { touchingPCoord = currentPCoord; break; } } else { if ((sphereDistance0 <= 0.0) && (sphereDistance1 > 0.0)) { touchingPCoord = currentPCoord+pcoordStepSize; break; } } currentPCoord += pcoordStepSize; } if (forward) { if ((touchingSubId == subId) && (touchingPCoord > pcoord)) { touchingSubId = -1; touchingPCoord = 0.0; } } else { if ((touchingSubId == subId) && (touchingPCoord < pcoord)) { touchingSubId = -1; touchingPCoord = 0.0; } } subIds->Delete(); } void vtkvmtkCenterlineSphereDistance::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter.h0000664000175000017500000000634611757446472031540 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter_h #define __vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class vtkDataArray; class vtkIdList; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter,vtkPolyDataAlgorithm); vtkSetStringMacro(BoundaryMetricArrayName); vtkGetStringMacro(BoundaryMetricArrayName); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); vtkSetObjectMacro(Centerlines,vtkPolyData); vtkGetObjectMacro(Centerlines,vtkPolyData); vtkSetStringMacro(CenterlineAbscissasArrayName); vtkGetStringMacro(CenterlineAbscissasArrayName); vtkSetStringMacro(CenterlineRadiusArrayName); vtkGetStringMacro(CenterlineRadiusArrayName); vtkSetStringMacro(CenterlineGroupIdsArrayName); vtkGetStringMacro(CenterlineGroupIdsArrayName); vtkSetStringMacro(CenterlineIdsArrayName); vtkGetStringMacro(CenterlineIdsArrayName); vtkSetStringMacro(CenterlineTractIdsArrayName); vtkGetStringMacro(CenterlineTractIdsArrayName); vtkSetObjectMacro(ReferenceSystems,vtkPolyData); vtkGetObjectMacro(ReferenceSystems,vtkPolyData); vtkSetStringMacro(ReferenceSystemGroupIdsArrayName); vtkGetStringMacro(ReferenceSystemGroupIdsArrayName); protected: vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter(); ~vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* BoundaryMetricArrayName; char* GroupIdsArrayName; vtkPolyData* Centerlines; char* CenterlineAbscissasArrayName; char* CenterlineRadiusArrayName; char* CenterlineGroupIdsArrayName; char* CenterlineIdsArrayName; char* CenterlineTractIdsArrayName; vtkPolyData* ReferenceSystems; char* ReferenceSystemGroupIdsArrayName; private: vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter(const vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineMetricFilter.cxx0000664000175000017500000001430211757446472027363 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineMetricFilter.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:07:48 $ Version: $Revision: 1.6 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataCenterlineMetricFilter.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkvmtkPolyBallLine.h" #include "vtkCell.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataCenterlineMetricFilter, "$Revision: 1.6 $"); vtkvmtkPolyDataCenterlineMetricFilter::vtkvmtkPolyDataCenterlineMetricFilter() { this->MetricArrayName = NULL; this->BlankingArrayName = NULL; this->GroupIdsArrayName = NULL; this->Centerlines = NULL; this->RadiusArrayName = NULL; this->CenterlineGroupIdsArrayName = NULL; this->CenterlineIdsArrayName = NULL; this->CenterlineTractIdsArrayName = NULL; this->UseRadiusInformation = 1; this->IncludeBifurcations = 1; } vtkvmtkPolyDataCenterlineMetricFilter::~vtkvmtkPolyDataCenterlineMetricFilter() { if (this->MetricArrayName) { delete[] this->MetricArrayName; this->MetricArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->Centerlines) { this->Centerlines->Delete(); this->Centerlines = NULL; } if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->BlankingArrayName) { delete[] this->BlankingArrayName; this->BlankingArrayName = NULL; } if (this->CenterlineGroupIdsArrayName) { delete[] this->CenterlineGroupIdsArrayName; this->CenterlineGroupIdsArrayName = NULL; } if (this->CenterlineTractIdsArrayName) { delete[] this->CenterlineGroupIdsArrayName; this->CenterlineGroupIdsArrayName = NULL; } if (this->CenterlineIdsArrayName) { delete[] this->CenterlineIdsArrayName; this->CenterlineIdsArrayName = NULL; } } int vtkvmtkPolyDataCenterlineMetricFilter::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->MetricArrayName) { vtkErrorMacro(<<"MetricArrayName not set."); return 1; } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not set."); 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->UseRadiusInformation) { if (!this->RadiusArrayName) { vtkErrorMacro(<<"RadiusArrayName not set."); return 1; } vtkDataArray* radiusArray = this->Centerlines->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { vtkErrorMacro(<<"RadiusArray with name specified does not exist."); return 1; } } if (this->IncludeBifurcations) { if (!this->BlankingArrayName) { vtkErrorMacro(<<"BlankingArrayName not set."); return 1; } vtkDataArray* blankingArray = this->Centerlines->GetCellData()->GetArray(this->BlankingArrayName); if (!blankingArray) { vtkErrorMacro(<<"BlankingArray with name specified does not exist."); return 1; } if (!this->CenterlineIdsArrayName) { vtkErrorMacro(<<"CenterlineIdsArrayName not set."); 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 set."); return 1; } vtkDataArray* centerlineTractIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineTractIdsArrayName); if (!centerlineTractIdsArray) { vtkErrorMacro(<<"CenterlineTractIdsArray with name specified does not exist."); return 1; } } if (!this->CenterlineGroupIdsArrayName) { vtkErrorMacro(<<"CenterlineGroupIdsArrayName not set."); return 1; } vtkDataArray* centerlineGroupIdsArray = this->Centerlines->GetCellData()->GetArray(this->CenterlineGroupIdsArrayName); if (!centerlineGroupIdsArray) { vtkErrorMacro(<<"CenterlineGroupIdsArrayName with name specified does not exist."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkDoubleArray* metricArray = vtkDoubleArray::New(); metricArray->SetName(this->MetricArrayName); metricArray->SetNumberOfComponents(1); metricArray->SetNumberOfTuples(numberOfInputPoints); metricArray->FillComponent(0,0.0); output->GetPointData()->AddArray(metricArray); vtkIdType groupId; for (int i=0; i(groupIdsArray->GetComponent(i,0)); this->EvaluateMetric(i,input->GetPoint(i),groupId,metricArray); } metricArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkSimplifyVoronoiDiagram.h0000664000175000017500000000651511757446472025414 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSimplifyVoronoiDiagram.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkSimplifyVoronoiDiagram - Remove non essential Voronoi polygon points. // .SECTION Description // This class identifies and removes Voronoi polygon points if they are used by one cell and they are not poles. This helps to get rid of noisy Voronoi diagram parts induced by non smooth surface point distribution. This operation has no effect on the accuracy of the computation of centerlines and of surface related quantities. // .SECTION See Also // vtkVoronoiDiagram3D #ifndef __vtkvmtkSimplifyVoronoiDiagram_h #define __vtkvmtkSimplifyVoronoiDiagram_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #define VTK_VMTK_REMOVE_BOUNDARY_POINTS 0 #define VTK_VMTK_REMOVE_BOUNDARY_CELLS 1 class vtkCellArray; class vtkCellTypes; class vtkCellLinks; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkSimplifyVoronoiDiagram : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkSimplifyVoronoiDiagram,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSimplifyVoronoiDiagram *New(); // Set/Get id list of Voronoi diagram points to preserve. vtkSetObjectMacro(UnremovablePointIds,vtkIdList); vtkGetObjectMacro(UnremovablePointIds,vtkIdList); // Set/Get id list of Voronoi diagram cells to preserve. vtkSetObjectMacro(UnremovableCellIds,vtkIdList); vtkGetObjectMacro(UnremovableCellIds,vtkIdList); // Description: // Set/Get type of simplification. vtkSetMacro(Simplification,int); vtkGetMacro(Simplification,int); void SetSimplificationToRemoveBoundaryPoints() { this->SetSimplification(VTK_VMTK_REMOVE_BOUNDARY_POINTS);}; void SetSimplificationToRemoveBoundaryCells() { this->SetSimplification(VTK_VMTK_REMOVE_BOUNDARY_CELLS);}; vtkSetMacro(IncludeUnremovable,int); vtkGetMacro(IncludeUnremovable,int); vtkBooleanMacro(IncludeUnremovable,int); vtkSetMacro(OnePassOnly,int); vtkGetMacro(OnePassOnly,int); vtkBooleanMacro(OnePassOnly,int); protected: vtkvmtkSimplifyVoronoiDiagram(); ~vtkvmtkSimplifyVoronoiDiagram(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdType IsBoundaryEdge(vtkCellLinks* links, vtkIdType* edge); vtkIdList* UnremovablePointIds; vtkIdList* UnremovableCellIds; int Simplification; int IncludeUnremovable; int OnePassOnly; private: vtkvmtkSimplifyVoronoiDiagram(const vtkvmtkSimplifyVoronoiDiagram&); // Not implemented. void operator=(const vtkvmtkSimplifyVoronoiDiagram&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineAbscissaMetricFilter.h0000664000175000017500000000402211757446472030457 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineAbscissaMetricFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCenterlineAbscissaMetricFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataCenterlineAbscissaMetricFilter_h #define __vtkvmtkPolyDataCenterlineAbscissaMetricFilter_h #include "vtkvmtkPolyDataCenterlineMetricFilter.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlineAbscissaMetricFilter : public vtkvmtkPolyDataCenterlineMetricFilter { public: static vtkvmtkPolyDataCenterlineAbscissaMetricFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataCenterlineAbscissaMetricFilter,vtkvmtkPolyDataCenterlineMetricFilter); vtkSetStringMacro(AbscissasArrayName); vtkGetStringMacro(AbscissasArrayName); protected: vtkvmtkPolyDataCenterlineAbscissaMetricFilter(); ~vtkvmtkPolyDataCenterlineAbscissaMetricFilter(); virtual void EvaluateMetric(vtkIdType pointId, double point[3], vtkIdType groupId, vtkDataArray* metricArray); char* AbscissasArrayName; private: vtkvmtkPolyDataCenterlineAbscissaMetricFilter(const vtkvmtkPolyDataCenterlineAbscissaMetricFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataCenterlineAbscissaMetricFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkVoronoiDiagram3D.cxx0000664000175000017500000002132611757446472024436 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkVoronoiDiagram3D.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkVoronoiDiagram3D.h" #include "vtkUnstructuredGrid.h" #include "vtkTetra.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkVoronoiDiagram3D, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkVoronoiDiagram3D); vtkvmtkVoronoiDiagram3D::vtkvmtkVoronoiDiagram3D() { this->BuildLines = 0; this->PoleIds = vtkIdList::New(); this->RadiusArrayName = NULL; } vtkvmtkVoronoiDiagram3D::~vtkvmtkVoronoiDiagram3D() { this->PoleIds->Delete(); if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } } int vtkvmtkVoronoiDiagram3D::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkUnstructuredGrid"); return 1; } void vtkvmtkVoronoiDiagram3D::ExtractUniqueEdges(vtkUnstructuredGrid* input, vtkCellArray* edgeArray) // could be a class { int isVisited; vtkIdType i, j, k; vtkIdType edgePts[2]; vtkIdType npts, *pts; vtkIntArray* visited; vtkIdList* pointCells; vtkIdList* insertedLoopPoints; visited = vtkIntArray::New(); visited->SetNumberOfTuples(input->GetNumberOfPoints()); visited->FillComponent(0,0); pointCells = vtkIdList::New(); insertedLoopPoints = vtkIdList::New(); for (i=0; iGetNumberOfPoints(); i++) { visited->SetValue(i,1); edgePts[0] = i; pointCells->Initialize(); insertedLoopPoints->Initialize(); input->GetPointCells(i,pointCells); for (j=0; jGetNumberOfIds(); j++) { input->GetCellPoints(pointCells->GetId(j),npts,pts); for (k=0; kGetValue(pts[k]); if (!isVisited) if (insertedLoopPoints->IsId(pts[k])==-1) { edgePts[1] = pts[k]; insertedLoopPoints->InsertNextId(pts[k]); edgeArray->InsertNextCell(2,edgePts); } } } } visited->Delete(); pointCells->Delete(); insertedLoopPoints->Delete(); } void vtkvmtkVoronoiDiagram3D::BuildVoronoiPolys(vtkUnstructuredGrid* input, vtkCellArray* voronoiPolys) { bool boundaryTetra; vtkIdType npts, *pts; pts = NULL; vtkIdType neighborTetraId; vtkIdType i, k, h; vtkCellArray* edgeArray; vtkIdList* polyIds; vtkIdList* neighborCells; vtkIdList* neighborTrianglePointIds; vtkIdList* neighborNeighborCells; vtkIdList* linePointIds; vtkTetra* neighborTetra; edgeArray = vtkCellArray::New(); polyIds = vtkIdList::New(); neighborCells = vtkIdList::New(); neighborTrianglePointIds = vtkIdList::New(); neighborNeighborCells = vtkIdList::New(); linePointIds = vtkIdList::New(); this->ExtractUniqueEdges(input,edgeArray); edgeArray->InitTraversal(); for (i=0; iGetNumberOfCells(); i++) { edgeArray->GetNextCell(npts,pts); linePointIds->Initialize(); linePointIds->InsertNextId(pts[0]); linePointIds->InsertNextId(pts[1]); boundaryTetra = false; neighborCells->Initialize(); neighborTrianglePointIds->Initialize(); polyIds->Initialize(); input->GetCellNeighbors(-1,linePointIds,neighborCells); neighborTrianglePointIds->InsertNextId(linePointIds->GetId(0)); neighborTrianglePointIds->InsertNextId(linePointIds->GetId(1)); neighborTetraId = neighborCells->GetId(0); neighborTetra = vtkTetra::SafeDownCast(input->GetCell(neighborTetraId)); polyIds->InsertNextId(neighborTetraId); for (k=0; kGetNumberOfIds(); k++) { neighborNeighborCells->Initialize(); for (h=0; hGetNumberOfPoints(); h++) { if (neighborTrianglePointIds->IsId(neighborTetra->GetPointId(h))==-1) { neighborTrianglePointIds->InsertId(2,neighborTetra->GetPointId(h)); input->GetCellNeighbors(neighborTetraId,neighborTrianglePointIds,neighborNeighborCells); if (neighborNeighborCells->GetNumberOfIds()==0) { boundaryTetra = true; break; } else if (neighborNeighborCells->GetNumberOfIds()==1) { neighborTetraId = neighborNeighborCells->GetId(0); neighborTetra = vtkTetra::SafeDownCast(input->GetCell(neighborTetraId)); polyIds->InsertUniqueId(neighborTetraId); break; } } } if (boundaryTetra) break; } if (!boundaryTetra) voronoiPolys->InsertNextCell(polyIds); } edgeArray->Delete(); polyIds->Delete(); neighborCells->Delete(); neighborTrianglePointIds->Delete(); neighborNeighborCells->Delete(); linePointIds->Delete(); } int vtkvmtkVoronoiDiagram3D::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())); vtkPolyData *output = vtkPolyData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); // Declare double p0[3], p1[3], p2[3], p3[3]; double tetraCenter[3], tetraRadius; double currentRadius; vtkIdType i, j, id, poleId; vtkPoints* newPoints; vtkCellArray* newPolys; vtkCellArray* newLines; vtkDoubleArray* newScalars; vtkDoubleArray* thicknessScalars; vtkIdList* cellIds; vtkTetra* tetra; poleId = -1; // Allocate newPoints = vtkPoints::New(); newPoints->SetNumberOfPoints(input->GetNumberOfCells()); newScalars = vtkDoubleArray::New(); newScalars->SetNumberOfTuples(input->GetNumberOfCells()); newPolys = vtkCellArray::New(); newLines = vtkCellArray::New(); thicknessScalars = vtkDoubleArray::New(); thicknessScalars->SetNumberOfTuples(input->GetNumberOfPoints()); thicknessScalars->FillComponent(0,0.0); cellIds = vtkIdList::New(); this->PoleIds->SetNumberOfIds(input->GetNumberOfPoints()); // Execute for (i=0; iGetNumberOfPoints(); i++) { this->PoleIds->SetId(i,-1); } for (i=0; iGetNumberOfCells(); i++) { tetra = (vtkTetra*) input->GetCell(i); tetra->GetPoints()->GetPoint(0,p0); tetra->GetPoints()->GetPoint(1,p1); tetra->GetPoints()->GetPoint(2,p2); tetra->GetPoints()->GetPoint(3,p3); tetraRadius = sqrt(vtkTetra::Circumsphere(p0,p1,p2,p3,tetraCenter)); newPoints->SetPoint(i,tetraCenter); newScalars->SetValue(i,(double)tetraRadius); } // compute poles input->BuildLinks(); for (i=0; iGetNumberOfPoints(); i++) { cellIds->Initialize(); input->GetPointCells(i,cellIds); currentRadius = thicknessScalars->GetValue(i); for (j=0; jGetNumberOfIds(); j++) { id = cellIds->GetId(j); tetraRadius = newScalars->GetValue(id); if (tetraRadius - currentRadius > VTK_VMTK_DOUBLE_TOL) { poleId = id; currentRadius = tetraRadius; } } this->PoleIds->SetId(i,poleId); thicknessScalars->SetValue(i,currentRadius); } this->BuildVoronoiPolys(input,newPolys); if (this->BuildLines) { this->BuildVoronoiLines(); } if (this->RadiusArrayName) { newScalars->SetName(this->RadiusArrayName); } else { newScalars->SetName("VoronoiRadius"); } output->SetPoints(newPoints); output->GetPointData()->AddArray(newScalars); output->GetPointData()->SetActiveScalars(newScalars->GetName()); output->SetPolys(newPolys); if (this->BuildLines) { output->SetLines(newLines); } // Destroy newPoints->Delete(); newPolys->Delete(); newLines->Delete(); newScalars->Delete(); thicknessScalars->Delete(); cellIds->Delete(); return 1; } void vtkvmtkVoronoiDiagram3D::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkVoronoiDiagram3D.h0000664000175000017500000000635411757446472024067 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkVoronoiDiagram3D.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkVoronoiDiagram3D - Compute the Voronoi diagram of a set of points in 3D. // .SECTION Description // This class computes the Voronoi diagram of a set of points given their Delaunay tessellation. Basically, the output points are Delaunay tetrahedra circumcenters, and the cells are convex polygons constructed by connecting circumcenters of tetrahedra sharing a face. The radius of the circumsphere associated with each circumcenter is stored in a point data array with name specifed by RadiusArrayName. The id list of poles is also provided. Poles are the farthest inner and outer Voronoi points associated with a Delaunay point. Since this class is meant to deal with Delaunay tessellations which are internal to a given surface, only the internal pole is considered for each input point. #ifndef __vtkvmtkVoronoiDiagram3D_h #define __vtkvmtkVoronoiDiagram3D_h #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkCellArray.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class vtkUnstructuredGrid; class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkVoronoiDiagram3D : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkVoronoiDiagram3D,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkVoronoiDiagram3D *New(); // vtkSetMacro(BuildLines,int); // vtkGetMacro(BuildLines,int); // vtkBooleanMacro(BuildLines,int); // Description: // Set/Get the name of the point data array where circumsphere radius values are stored. vtkSetStringMacro(RadiusArrayName); vtkGetStringMacro(RadiusArrayName); // Description: // Get the id list of poles. The id list has the same size as input points. For every input point, one Voronoi point id is stored in the list. vtkGetObjectMacro(PoleIds,vtkIdList); protected: vtkvmtkVoronoiDiagram3D(); ~vtkvmtkVoronoiDiagram3D(); int FillInputPortInformation(int, vtkInformation *info); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ExtractUniqueEdges(vtkUnstructuredGrid* input, vtkCellArray* edgeArray); void BuildVoronoiPolys(vtkUnstructuredGrid* input, vtkCellArray* voronoiPolys); void BuildVoronoiLines() {}; // not yet implemented int BuildLines; vtkIdList* PoleIds; char* RadiusArrayName; private: vtkvmtkVoronoiDiagram3D(const vtkvmtkVoronoiDiagram3D&); // Not implemented. void operator=(const vtkvmtkVoronoiDiagram3D&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkAppendFilter.cxx0000664000175000017500000001661111757446472023705 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkAppendFilter.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:49:05 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkAppendFilter.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkDataSetAttributes.h" #include "vtkDataSetCollection.h" #include "vtkExecutive.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkUnstructuredGrid.h" #include "vtkMath.h" #include "vtkMergePoints.h" vtkCxxRevisionMacro(vtkvmtkAppendFilter, "$Revision: 1.76 $"); vtkStandardNewMacro(vtkvmtkAppendFilter); vtkvmtkAppendFilter::vtkvmtkAppendFilter() { this->MergeDuplicatePoints = 1; } vtkvmtkAppendFilter::~vtkvmtkAppendFilter() { } int vtkvmtkAppendFilter::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { // get the output info object vtkInformation *outInfo = outputVector->GetInformationObject(0); // get the ouptut vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkIdType numPts, numCells; int tenth, count, abort=0; float decimal; vtkPoints *newPts; vtkPointData *pd; vtkCellData *cd; vtkIdList *ptIds, *newPtIds; int i, idx; vtkDataSet *ds; vtkIdType ptId, cellId, newCellId; vtkPointData *outputPD = output->GetPointData(); vtkCellData *outputCD = output->GetCellData(); vtkDebugMacro(<<"Appending data together"); double bounds[6], inputBounds[6]; vtkMath::UninitializeBounds(bounds); // Loop over all data sets, checking to see what data is common to // all inputs. Note that data is common if 1) it is the same attribute // type (scalar, vector, etc.), 2) it is the same native type (int, // float, etc.), and 3) if a data array in a field, if it has the same name. count = 0; decimal = 0.0; numPts = 0; numCells = 0; int numInputs = inputVector[0]->GetNumberOfInformationObjects(); vtkDataSetAttributes::FieldList ptList(numInputs); vtkDataSetAttributes::FieldList cellList(numInputs); int firstPD=1; int firstCD=1; vtkInformation *inInfo = 0; for (idx = 0; idx < numInputs; ++idx) { inInfo = inputVector[0]->GetInformationObject(idx); ds = 0; if (inInfo) { ds = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); } if (ds != NULL) { if ( ds->GetNumberOfPoints() <= 0 && ds->GetNumberOfCells() <= 0 ) { continue; //no input, just skip } numPts += ds->GetNumberOfPoints(); numCells += ds->GetNumberOfCells(); ds->GetBounds(inputBounds); if (vtkMath::AreBoundsInitialized(bounds)) { int j; for (j=0; j<6; j+=2) { if (inputBounds[j] < bounds[j]) { bounds[j] = inputBounds[j]; } if (inputBounds[j+1] > bounds[j+1]) { bounds[j+1] = inputBounds[j+1]; } } } else { int j; for (j=0; j<6; j+=2) { bounds[j] = inputBounds[j]; bounds[j+1] = inputBounds[j+1]; } } pd = ds->GetPointData(); if ( firstPD ) { ptList.InitializeFieldList(pd); firstPD = 0; } else { ptList.IntersectFieldList(pd); } cd = ds->GetCellData(); if ( firstCD ) { cellList.InitializeFieldList(cd); firstCD = 0; } else { cellList.IntersectFieldList(cd); } }//if non-empty dataset }//for all inputs if ( numPts < 1) { vtkDebugMacro(<<"No data to append!"); return 1; } // Now can allocate memory output->Allocate(numCells); //allocate storage for geometry/topology // outputPD->CopyGlobalIdsOn(); outputPD->CopyAllocate(ptList,numPts); // outputCD->CopyGlobalIdsOn(); outputCD->CopyAllocate(cellList,numCells); newPts = vtkPoints::New(); ptIds = vtkIdList::New(); ptIds->Allocate(VTK_CELL_SIZE); newPtIds = vtkIdList::New(); newPtIds->Allocate(VTK_CELL_SIZE); vtkMergePoints* locator = vtkMergePoints::New(); if (this->MergeDuplicatePoints) { locator->InitPointInsertion(newPts,bounds); } vtkIdList* ptIdMap = vtkIdList::New(); vtkIdType newPtId; double point[3]; // Append each input dataset together // tenth = (numPts + numCells)/10 + 1; int inputCount = 0; // Since empty inputs are not in the list. for (idx = 0; idx < numInputs && !abort; ++idx) { inInfo = inputVector[0]->GetInformationObject(idx); ds = 0; if (inInfo) { ds = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); } if ( ds != NULL && (ds->GetNumberOfPoints() > 0 || ds->GetNumberOfCells() > 0) ) { numPts = ds->GetNumberOfPoints(); numCells = ds->GetNumberOfCells(); pd = ds->GetPointData(); ptIdMap->Initialize(); ptIdMap->SetNumberOfIds(numPts); // copy points and point data for (ptId=0; ptId < numPts && !abort; ptId++) { ds->GetPoint(ptId,point); if (this->MergeDuplicatePoints) { if (locator->InsertUniquePoint(point,newPtId)) { outputPD->CopyData(ptList,pd,inputCount,ptId,newPtId); } } else { newPtId = newPts->InsertNextPoint(point); outputPD->CopyData(ptList,pd,inputCount,ptId,newPtId); } ptIdMap->SetId(ptId,newPtId); // Update progress count++; if (!(count % tenth)) { decimal += 0.1; this->UpdateProgress(decimal); abort = this->GetAbortExecute(); } } cd = ds->GetCellData(); // copy cell and cell data for (cellId=0; cellIdGetCellPoints(cellId, ptIds); newPtIds->Reset(); for (i=0; iGetNumberOfIds(); i++) { newPtIds->InsertId(i,ptIdMap->GetId(ptIds->GetId(i))); } newCellId = output->InsertNextCell(ds->GetCellType(cellId),newPtIds); outputCD->CopyData(cellList,cd,inputCount,cellId,newCellId); // Update progress count++; if (!(count % tenth)) { decimal += 0.1; this->UpdateProgress(decimal); abort = this->GetAbortExecute(); } } ++inputCount; } } // Update ourselves and release memory // output->SetPoints(newPts); newPts->Delete(); ptIds->Delete(); newPtIds->Delete(); locator->Delete(); return 1; } void vtkvmtkAppendFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyBallModeller.cxx0000664000175000017500000002410011757446472024522 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBallModeller.cxx,v $ Language: C++ Date: $Date: 2006/01/09 17:01:50 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyBallModeller.h" #include "vtkvmtkPolyBall.h" #include "vtkvmtkPolyBallLine.h" #include "vtkPolyData.h" #include "vtkDoubleArray.h" #include "vtkImageData.h" #include "vtkMath.h" #include "vtkvmtkConstants.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkPointData.h" vtkCxxRevisionMacro(vtkvmtkPolyBallModeller, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkPolyBallModeller); vtkvmtkPolyBallModeller::vtkvmtkPolyBallModeller() { this->ReferenceImage = NULL; this->ModelBounds[0] = 0.0; this->ModelBounds[1] = 0.0; this->ModelBounds[2] = 0.0; this->ModelBounds[3] = 0.0; this->ModelBounds[4] = 0.0; this->ModelBounds[5] = 0.0; this->SampleDimensions[0] = 50; this->SampleDimensions[1] = 50; this->SampleDimensions[2] = 50; this->RadiusArrayName = NULL; this->UsePolyBallLine = 0; this->NegateFunction = 0; } vtkvmtkPolyBallModeller::~vtkvmtkPolyBallModeller() { if (this->ReferenceImage) { this->ReferenceImage->Delete(); this->ReferenceImage = NULL; } if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } } int vtkvmtkPolyBallModeller::RequestInformation ( vtkInformation * vtkNotUsed(request), vtkInformationVector** vtkNotUsed( inputVector ), vtkInformationVector *outputVector) { double spacing[3], origin[3]; vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkPolyData* input = vtkPolyData::SafeDownCast(this->GetInput()); if (this->RadiusArrayName == NULL) { vtkErrorMacro(<<"Error: RadiusArrayName not specified!"); return 1; } vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); if (radiusArray == NULL) { vtkErrorMacro(<<"Error: RadiusArray with name specified does not exist!"); return 1; } int extent[6]; if (this->ReferenceImage) { this->ReferenceImage->GetOrigin(origin); this->ReferenceImage->GetSpacing(spacing); this->ReferenceImage->GetDimensions(this->SampleDimensions); this->ReferenceImage->GetExtent(extent); } else { double maxRadius = radiusArray->GetRange()[1]; if ((this->ModelBounds[0] >= this->ModelBounds[1]) || (this->ModelBounds[2] >= this->ModelBounds[3]) || (this->ModelBounds[4] >= this->ModelBounds[5])) { double* bounds = input->GetBounds(); double maxDist = 2.0 * maxRadius; int i; for (i=0; i<3; i++) { this->ModelBounds[2*i] = bounds[2*i] - maxDist; this->ModelBounds[2*i+1] = bounds[2*i+1] + maxDist; } } int i; for (i=0; i<3; i++) { origin[i] = this->ModelBounds[2*i]; if (this->SampleDimensions[i] <= 1) { spacing[i] = 1.0; } else { spacing[i] = (this->ModelBounds[2*i+1] - this->ModelBounds[2*i]) / (this->SampleDimensions[i] - 1); } } extent[0] = 0; extent[1] = this->SampleDimensions[0]-1; extent[2] = 0; extent[3] = this->SampleDimensions[1]-1; extent[4] = 0; extent[5] = this->SampleDimensions[2]-1; } outInfo->Set(vtkDataObject::ORIGIN(),origin,3); outInfo->Set(vtkDataObject::SPACING(),spacing,3); vtkDataObject::SetPointDataActiveScalarInfo(outInfo, VTK_DOUBLE, 1); //outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),0, this->SampleDimensions[0]-1, 0, this->SampleDimensions[1]-1, 0, this->SampleDimensions[2]-1); outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(),extent[0],extent[1],extent[2],extent[3],extent[4],extent[5]); return 1; } int vtkvmtkPolyBallModeller::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData"); return 1; } int vtkvmtkPolyBallModeller::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())); vtkImageData *output = vtkImageData::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); if (this->RadiusArrayName == NULL) { vtkErrorMacro(<<"Error: RadiusArrayName not specified!"); return 1; } if (input->GetPointData()->GetArray(this->RadiusArrayName) == NULL) { vtkErrorMacro(<<"Error: RadiusArray with name specified does not exist!"); return 1; } output->SetExtent(outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT())); output->AllocateScalars(); vtkDoubleArray *functionArray = vtkDoubleArray::SafeDownCast(output->GetPointData()->GetScalars()); functionArray->SetName(this->RadiusArrayName); int numberOfOutputPoints = output->GetNumberOfPoints(); #if 0 vtkImplicitFunction* function; if (!this->UsePolyBallLine) { vtkvmtkPolyBall* polyBall = vtkvmtkPolyBall::New(); polyBall->SetInput(input); polyBall->SetPolyBallRadiusArrayName(this->RadiusArrayName); function = polyBall; } else { vtkvmtkPolyBallLine* polyBall = vtkvmtkPolyBallLine::New(); polyBall->SetInput(input); polyBall->SetPolyBallRadiusArrayName(this->RadiusArrayName); function = polyBall; } double point[3]; int i; for (i=0; iGetPoint(i,point); double polyBallFunction = function->EvaluateFunction(point); functionArray->SetComponent(i,0,polyBallFunction); } function->Delete(); #endif if (!this->UsePolyBallLine) { functionArray->FillComponent(0,VTK_VMTK_LARGE_DOUBLE); vtkDoubleArray* radiusArray = vtkDoubleArray::SafeDownCast(input->GetPointData()->GetArray(this->RadiusArrayName)); int numberOfInputPoints = input->GetNumberOfPoints(); int extent[6]; double x[3], p[3], r; double boundingBox0[3], boundingBox1[3]; int ijk0[3], ijk1[3], ijk[3]; int ijkExtent[6]; double pcoords[3]; int inBounds0, inBounds1; double radiusFactor = 2.0; output->GetExtent(extent); double sphereFunctionValue, currentSphereFunctionValue; int n; int i, j, k; vtkIdType outputId; for (n=0; nGetPoint(n,p); r = radiusArray->GetValue(n); boundingBox0[0] = p[0] - radiusFactor * r; boundingBox0[1] = p[1] - radiusFactor * r; boundingBox0[2] = p[2] - radiusFactor * r; boundingBox1[0] = p[0] + radiusFactor * r; boundingBox1[1] = p[1] + radiusFactor * r; boundingBox1[2] = p[2] + radiusFactor * r; inBounds0 = output->ComputeStructuredCoordinates(boundingBox0,ijk0,pcoords); inBounds1 = output->ComputeStructuredCoordinates(boundingBox1,ijk1,pcoords); if (!inBounds0 && !inBounds1) { continue; } ijkExtent[0] = ijk0[0] < extent[0] ? extent[0] : ijk0[0]; ijkExtent[1] = ijk1[0] > extent[1] ? extent[1] : ijk1[0]; ijkExtent[2] = ijk0[1] < extent[2] ? extent[2] : ijk0[1]; ijkExtent[3] = ijk1[1] > extent[3] ? extent[3] : ijk1[1]; ijkExtent[4] = ijk0[2] < extent[4] ? extent[4] : ijk0[2]; ijkExtent[5] = ijk1[2] > extent[5] ? extent[5] : ijk1[2]; for (k=ijkExtent[4]; k<=ijkExtent[5]; k++) { for (j=ijkExtent[2]; j<=ijkExtent[3]; j++) { for (i=ijkExtent[0]; i<=ijkExtent[1]; i++) { ijk[0] = i; ijk[1] = j; ijk[2] = k; outputId = output->ComputePointId(ijk); output->GetPoint(outputId,x); sphereFunctionValue = ((x[0] - p[0]) * (x[0] - p[0]) + (x[1] - p[1]) * (x[1] - p[1]) + (x[2] - p[2]) * (x[2] - p[2])) - r * r; currentSphereFunctionValue = functionArray->GetComponent(outputId,0); if (sphereFunctionValue < currentSphereFunctionValue) { functionArray->SetComponent(outputId,0,sphereFunctionValue); } } } } } } else { vtkvmtkPolyBallLine* polyBallLine = vtkvmtkPolyBallLine::New(); polyBallLine->SetInput(input); polyBallLine->SetPolyBallRadiusArrayName(this->RadiusArrayName); double point[3]; int i; for (i=0; iGetPoint(i,point); double polyBallLineValue = polyBallLine->EvaluateFunction(point); functionArray->SetComponent(i,0,polyBallLineValue); } } if (this->NegateFunction) { int i; for (i=0; iGetComponent(i,0); functionValue *= -1.0; functionArray->SetComponent(i,0,functionValue); } } return 1; } void vtkvmtkPolyBallModeller::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Sample Dimensions: (" << this->SampleDimensions[0] << ", " << this->SampleDimensions[1] << ", " << this->SampleDimensions[2] << ")\n"; os << indent << "ModelBounds: \n"; os << indent << " Xmin,Xmax: (" << this->ModelBounds[0] << ", " << this->ModelBounds[1] << ")\n"; os << indent << " Ymin,Ymax: (" << this->ModelBounds[2] << ", " << this->ModelBounds[3] << ")\n"; os << indent << " Zmin,Zmax: (" << this->ModelBounds[4] << ", " << this->ModelBounds[5] << ")\n"; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataDistanceToCenterlines.h0000664000175000017500000000537411757446472026650 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDistanceToCenterlines.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataDistanceToCenterlines_h #define __vtkvmtkPolyDataDistanceToCenterlines_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataDistanceToCenterlines : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataDistanceToCenterlines* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataDistanceToCenterlines,vtkPolyDataAlgorithm); vtkSetObjectMacro(Centerlines,vtkPolyData); vtkGetObjectMacro(Centerlines,vtkPolyData); vtkSetMacro(UseRadiusInformation,int); vtkGetMacro(UseRadiusInformation,int); vtkBooleanMacro(UseRadiusInformation,int); vtkSetMacro(EvaluateTubeFunction,int); vtkGetMacro(EvaluateTubeFunction,int); vtkBooleanMacro(EvaluateTubeFunction,int); vtkSetMacro(EvaluateCenterlineRadius,int); vtkGetMacro(EvaluateCenterlineRadius,int); vtkBooleanMacro(EvaluateCenterlineRadius,int); vtkSetStringMacro(DistanceToCenterlinesArrayName); vtkGetStringMacro(DistanceToCenterlinesArrayName); vtkSetStringMacro(CenterlineRadiusArrayName); vtkGetStringMacro(CenterlineRadiusArrayName); vtkSetMacro(ProjectPointArrays,int); vtkGetMacro(ProjectPointArrays,int); vtkBooleanMacro(ProjectPointArrays,int); protected: vtkvmtkPolyDataDistanceToCenterlines(); ~vtkvmtkPolyDataDistanceToCenterlines(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* DistanceToCenterlinesArrayName; char* CenterlineRadiusArrayName; vtkPolyData* Centerlines; int UseRadiusInformation; int EvaluateTubeFunction; int EvaluateCenterlineRadius; int ProjectPointArrays; private: vtkvmtkPolyDataDistanceToCenterlines(const vtkvmtkPolyDataDistanceToCenterlines&); // Not implemented. void operator=(const vtkvmtkPolyDataDistanceToCenterlines&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBranchExtractor.cxx0000664000175000017500000003132111757446472026425 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBranchExtractor.cxx,v $ Language: C++ Date: $Date: 2006/07/07 10:46:19 $ Version: $Revision: 1.10 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineBranchExtractor.h" #include "vtkvmtkCenterlineSphereDistance.h" #include "vtkvmtkPolyBallLine.h" #include "vtkPolyData.h" #include "vtkPolyLine.h" #include "vtkPointData.h" #include "vtkIdList.h" #include "vtkCellData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCenterlineBranchExtractor, "$Revision: 1.10 $"); vtkStandardNewMacro(vtkvmtkCenterlineBranchExtractor); vtkvmtkCenterlineBranchExtractor::vtkvmtkCenterlineBranchExtractor() { } vtkvmtkCenterlineBranchExtractor::~vtkvmtkCenterlineBranchExtractor() { } void vtkvmtkCenterlineBranchExtractor::ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId) { this->NumberOfSplittingPoints = 0; if (this->SubIds) { delete[] this->SubIds; this->SubIds = NULL; } if (this->PCoords) { delete[] this->PCoords; this->PCoords = NULL; } if (this->TractBlanking) { delete[] this->TractBlanking; this->TractBlanking = NULL; } if (!this->RadiusArrayName) { return; } if (input->GetCell(cellId)->GetCellType() != VTK_LINE && input->GetCell(cellId)->GetCellType() != VTK_POLY_LINE) { return; } vtkDataArray* radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { return; } // TODO: remove assumption: centerlines organized in a tree, parent branches as sources and children as targets vtkvmtkPolyBallLine* tube = vtkvmtkPolyBallLine::New(); tube->SetInput(input); tube->SetPolyBallRadiusArrayName(this->RadiusArrayName); vtkIdList* tubeCellIds = vtkIdList::New(); vtkIdList* intersectionSubIds = vtkIdList::New(); vtkDoubleArray* intersectionPCoords = vtkDoubleArray::New(); vtkIdType numberOfCells = input->GetNumberOfCells(); //for every other cell than cellId, find intersection of cellId with the tube function of the other cell int j; for (j=0; jGetCell(j)->GetCellType() != VTK_LINE && input->GetCell(j)->GetCellType() != VTK_POLY_LINE) { continue; } tubeCellIds->Initialize(); tubeCellIds->InsertNextId(j); tube->SetInputCellIds(tubeCellIds); int numberOfCellPoints = input->GetCell(cellId)->GetNumberOfPoints(); double point0[3], point1[3]; double tubeValue0, tubeValue1; for (int k=0; kGetCell(cellId)->GetPoints()->GetPoint(k,point0); input->GetCell(cellId)->GetPoints()->GetPoint(k+1,point1); tubeValue0 = tube->EvaluateFunction(point0); tubeValue1 = tube->EvaluateFunction(point1); // if (tubeValue0 * tubeValue1 <= 0.0) if ((tubeValue0 <= 0.0) && (tubeValue1 > 0.0)) // this is for divergent networks { double radius0, radius1; radius0 = radiusArray->GetComponent(input->GetCell(cellId)->GetPointId(k),0); radius1 = radiusArray->GetComponent(input->GetCell(cellId)->GetPointId(k+1),0); //TODO: use Newton iterations double segmentLength, stepSize, pcoordStepSize; int numberOfSteps; double subPoint0[3], subPoint1[3]; double subTubeValue0, subTubeValue1; segmentLength = vtkMath::Distance2BetweenPoints(point0,point1); stepSize = 1E-2 * (radius0 + radius1) / 2.0; numberOfSteps = (int)ceil(segmentLength / stepSize); stepSize = segmentLength / numberOfSteps; pcoordStepSize = 1.0 / (double)numberOfSteps; double pcoord = 0.0; int s; for (s=0; sEvaluateFunction(subPoint0); subTubeValue1 = tube->EvaluateFunction(subPoint1); // if (subTubeValue0 * subTubeValue1 <= 0.0) if ((subTubeValue0 <= 0.0) && (subTubeValue1 > 0.0)) // this is for divergent networks { pcoord += pcoordStepSize; break; } pcoord += pcoordStepSize; } //since we are considering each other cell separately, we need to decide where to put the intersection point in order to have them sorted along cellId int numberOfIntersections = intersectionSubIds->GetNumberOfIds(); int insertLocation = 0; for (s=0; s intersectionSubIds->GetId(s)) || (k==intersectionSubIds->GetId(s) && pcoord > intersectionPCoords->GetValue(s)); bool beforeNext = true; if (sGetId(s+1)) || (k==intersectionSubIds->GetId(s+1) && pcoord <= intersectionPCoords->GetValue(s+1)); } if (afterThis && beforeNext) { insertLocation = s+1; break; } } for (s=numberOfIntersections-1; s>=insertLocation; s--) { intersectionSubIds->InsertId(s+1,intersectionSubIds->GetId(s)); intersectionPCoords->InsertValue(s+1,intersectionPCoords->GetValue(s)); } intersectionSubIds->InsertId(insertLocation,k); intersectionPCoords->InsertValue(insertLocation,pcoord); } } } // For each branch, find point at one-sphere distance upstream (i.e. touching forward). vtkIdType touchingSubId; double touchingPCoord; const int numberOfGapSpheres = 1; const bool forward = true; vtkIdList* touchingSubIds = vtkIdList::New(); vtkDoubleArray* touchingPCoords = vtkDoubleArray::New(); int i; for (i=0; iGetNumberOfIds(); i++) { vtkvmtkCenterlineSphereDistance::FindNTouchingSphereCenter(input,this->RadiusArrayName,cellId,intersectionSubIds->GetId(i),intersectionPCoords->GetValue(i),numberOfGapSpheres,touchingSubId,touchingPCoord,forward); if (touchingSubId == -1) { touchingSubId = 0; touchingPCoord = 0.0; touchingSubIds->InsertNextId(touchingSubId); touchingPCoords->InsertNextValue(touchingPCoord); continue; } touchingSubIds->InsertNextId(touchingSubId); touchingPCoords->InsertNextValue(touchingPCoord); } vtkIdList* splittingSubIds = vtkIdList::New(); vtkDoubleArray* splittingPCoords = vtkDoubleArray::New(); vtkIdList* blankingFlags = vtkIdList::New(); blankingFlags->InsertNextId(0); /* for (i=0; iGetNumberOfIds(); i++) { // put one intersection every touching. Blank out between touching and intersection. if (i==0) { splittingSubIds->InsertNextId(touchingSubIds->GetId(i)); splittingPCoords->InsertNextValue(touchingPCoords->GetValue(i)); blankingFlags->InsertNextId(1); } else { // check if this touching is before previous intersection. If it is, skip the touching. if (!((touchingSubIds->GetId(i) < intersectionSubIds->GetId(i-1)) || ((touchingSubIds->GetId(i) == intersectionSubIds->GetId(i-1)) && (touchingPCoords->GetValue(i) <= intersectionPCoords->GetValue(i-1))))) { splittingSubIds->InsertNextId(touchingSubIds->GetId(i)); splittingPCoords->InsertNextValue(touchingPCoords->GetValue(i)); blankingFlags->InsertNextId(1); } } if (i==intersectionSubIds->GetNumberOfIds()-1) { splittingSubIds->InsertNextId(intersectionSubIds->GetId(i)); splittingPCoords->InsertNextValue(intersectionPCoords->GetValue(i)); blankingFlags->InsertNextId(0); } else { // check if subsequent touching is before this intersection. If it is, and if subsequent intersection is after this intersection, skip the intersection. if (! (((touchingSubIds->GetId(i+1) < intersectionSubIds->GetId(i)) || ((touchingSubIds->GetId(i+1) == intersectionSubIds->GetId(i)) && (touchingPCoords->GetValue(i+1) <= intersectionPCoords->GetValue(i))))) && (((intersectionSubIds->GetId(i+1) > intersectionSubIds->GetId(i)) || ((intersectionSubIds->GetId(i+1) == intersectionSubIds->GetId(i)) && (intersectionPCoords->GetValue(i+1) > intersectionPCoords->GetValue(i))))) ) { splittingSubIds->InsertNextId(intersectionSubIds->GetId(i)); splittingPCoords->InsertNextValue(intersectionPCoords->GetValue(i)); blankingFlags->InsertNextId(0); } } } */ //for every touching, put one intersection, and blank in between. If a subsequent touching falls between a previous touching and the corresponding intersection, take the farthest intersection vtkIdType prevIntersectionId = -1; for (i=0; iGetNumberOfIds(); i++) { if (i > 0) { if ((touchingSubIds->GetId(i) < intersectionSubIds->GetId(prevIntersectionId)) || ((touchingSubIds->GetId(i) == intersectionSubIds->GetId(prevIntersectionId)) && (touchingPCoords->GetValue(i) <= intersectionPCoords->GetValue(prevIntersectionId)))) { continue; } } splittingSubIds->InsertNextId(touchingSubIds->GetId(i)); splittingPCoords->InsertNextValue(touchingPCoords->GetValue(i)); blankingFlags->InsertNextId(1); vtkIdType maxIntersectionId = i; if (i < touchingSubIds->GetNumberOfIds()-1) { for (j=i+1; jGetNumberOfIds(); j++) { if ((touchingSubIds->GetId(j) < intersectionSubIds->GetId(maxIntersectionId)) || ((touchingSubIds->GetId(j) == intersectionSubIds->GetId(maxIntersectionId)) && (touchingPCoords->GetValue(j) <= intersectionPCoords->GetValue(maxIntersectionId)))) { if ((intersectionSubIds->GetId(j) > intersectionSubIds->GetId(maxIntersectionId)) || ((intersectionSubIds->GetId(j) == intersectionSubIds->GetId(maxIntersectionId)) && (intersectionPCoords->GetValue(j) >= intersectionPCoords->GetValue(maxIntersectionId)))) { maxIntersectionId = j; } } else { break; } } } splittingSubIds->InsertNextId(intersectionSubIds->GetId(maxIntersectionId)); splittingPCoords->InsertNextValue(intersectionPCoords->GetValue(maxIntersectionId)); blankingFlags->InsertNextId(0); prevIntersectionId = maxIntersectionId; } this->NumberOfSplittingPoints = splittingSubIds->GetNumberOfIds(); this->SubIds = new vtkIdType[this->NumberOfSplittingPoints]; this->PCoords = new double[this->NumberOfSplittingPoints]; for (i=0; iGetNumberOfIds(); i++) { this->SubIds[i] = splittingSubIds->GetId(i); this->PCoords[i] = splittingPCoords->GetValue(i); } this->TractBlanking = new int[this->NumberOfSplittingPoints+1]; for (i=0; iNumberOfSplittingPoints+1; i++) { this->TractBlanking[i] = blankingFlags->GetId(i); } tube->Delete(); tubeCellIds->Delete(); intersectionSubIds->Delete(); intersectionPCoords->Delete(); touchingSubIds->Delete(); touchingPCoords->Delete(); splittingSubIds->Delete(); splittingPCoords->Delete(); blankingFlags->Delete(); } void vtkvmtkCenterlineBranchExtractor::GroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts) { Superclass::GroupTracts(input,centerlineTracts); //New ideas: // loop over group ids, if blanked group, if same centerlineId as another tract in same group, make it another group. And what about the rest? No, better: assume net is a tree. For every group, look at which tracts of each centerline are downstream (via TractIdsArray) and group them in a bifurcation. In order to relax the assumption on the tree, for every group, for every direction, look for all the groups to which the next next tracts belong (tractId + 2 or -2). } void vtkvmtkCenterlineBranchExtractor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBranchUtilities.h0000664000175000017500000000347011757446472025503 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBranchUtilities.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // . #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: vtkTypeRevisionMacro(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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkReferenceSystemUtilities.cxx0000664000175000017500000000307311757446472026325 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkReferenceSystemUtilities.cxx,v $ Language: C++ Date: $Date: 2005/07/28 16:11:52 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkReferenceSystemUtilities, "$Revision: 1.1 $"); 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(groupIdsArray->GetComponent(i,0)); if (current_groupId == groupId) { pointId = i; break; } } return pointId; } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkNonManifoldSteepestDescent.cxx0000664000175000017500000001715711757446472026565 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNonManifoldSteepestDescent.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkNonManifoldSteepestDescent.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkNonManifoldSteepestDescent, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkNonManifoldSteepestDescent); vtkvmtkNonManifoldSteepestDescent::vtkvmtkNonManifoldSteepestDescent() { this->DescentArrayName = NULL; this->DescentArray = NULL; this->NumberOfEdgeSubdivisions = 250; this->Direction = VTK_VMTK_DOWNWARD; } vtkvmtkNonManifoldSteepestDescent::~vtkvmtkNonManifoldSteepestDescent() { } double vtkvmtkNonManifoldSteepestDescent::GetSteepestDescentInCell(vtkPolyData* input, vtkIdType cellId, vtkIdType* edge, double s, vtkIdType* steepestDescentEdge, double &steepestDescentS, double &steepestDescentLength) { double currentPoint[3], currentScalar; double descent, steepestDescent; double descentLength; double point0[3], point1[3], point[3]; double scalar0, scalar1, scalar; double currentS; double directionFactor = 0.0; vtkIdType npts, *pts; vtkIdType i, j; if (!this->DescentArray) { vtkErrorMacro("DescentArray not set."); } if (this->Direction==VTK_VMTK_DOWNWARD) { directionFactor = 1.0; } else if (this->Direction==VTK_VMTK_UPWARD) { directionFactor = - 1.0; } double edgePoint0[3], edgePoint1[3]; input->GetPoint(edge[0],edgePoint0); input->GetPoint(edge[1],edgePoint1); currentPoint[0] = edgePoint0[0] * (1.0 - s) + edgePoint1[0] * s; currentPoint[1] = edgePoint0[1] * (1.0 - s) + edgePoint1[1] * s; currentPoint[2] = edgePoint0[2] * (1.0 - s) + edgePoint1[2] * s; currentScalar = this->DescentArray->GetTuple1(edge[0]) * (1.0 - s) + this->DescentArray->GetTuple1(edge[1]) * s; steepestDescent = - VTK_VMTK_LARGE_DOUBLE * directionFactor; steepestDescentLength = VTK_VMTK_LARGE_DOUBLE; input->GetCellPoints(cellId,npts,pts); for (i=0; iGetPoint(pts[i],point0); input->GetPoint(pts[(i+1)%npts],point1); scalar0 = this->DescentArray->GetTuple1(pts[i]); scalar1 = this->DescentArray->GetTuple1(pts[(i+1)%npts]); if (edge[0]==edge[1]) { if (pts[i]==edge[0]) { continue; } } else { if (((pts[i]==edge[0]) && (pts[(i+1)%npts]==edge[1]))||((pts[i]==edge[1]) && (pts[(i+1)%npts]==edge[0]))) { point[0] = point0[0]; point[1] = point0[1]; point[2] = point0[2]; scalar = scalar0; currentS = 0.0; descentLength = sqrt(vtkMath::Distance2BetweenPoints(point,currentPoint)); if (descentLength > VTK_VMTK_DOUBLE_TOL) { descent = - (scalar - currentScalar) / descentLength; } else { descent = 0.0; } if (directionFactor*(descent - steepestDescent) > VTK_VMTK_DOUBLE_TOL) { steepestDescent = descent; steepestDescentLength = descentLength; steepestDescentEdge[0] = pts[i]; steepestDescentEdge[1] = pts[i]; steepestDescentS = currentS; } continue; } } currentS = 0.0; for (j=0; jNumberOfEdgeSubdivisions; j++) { point[0] = point0[0] * (1.0 - currentS) + point1[0] * currentS; point[1] = point0[1] * (1.0 - currentS) + point1[1] * currentS; point[2] = point0[2] * (1.0 - currentS) + point1[2] * currentS; scalar = scalar0 * (1.0 - currentS) + scalar1 * currentS; descentLength = sqrt(vtkMath::Distance2BetweenPoints(point,currentPoint)); if (descentLength > VTK_VMTK_DOUBLE_TOL) { descent = - (scalar - currentScalar) / descentLength; } else { descent = 0.0; } if (directionFactor * (descent - steepestDescent) > VTK_VMTK_DOUBLE_TOL) { steepestDescent = descent; steepestDescentLength = descentLength; if (fabs(currentS)NumberOfEdgeSubdivisions; } } return steepestDescent; } double vtkvmtkNonManifoldSteepestDescent::GetSteepestDescent(vtkPolyData* input, vtkIdType* edge, double s, vtkIdType* steepestDescentEdge, double &steepestDescentS) { double descent, steepestDescent; double descentLength, steepestDescentLength; vtkIdType descentEdge[2]; double descentS; vtkIdList *neighborCells; vtkIdType i, cellId; double directionFactor = 0.0; neighborCells = vtkIdList::New(); input->GetCellEdgeNeighbors(-1,edge[0],edge[1],neighborCells); if (this->Direction==VTK_VMTK_DOWNWARD) { directionFactor = 1.0; } else if (this->Direction==VTK_VMTK_UPWARD) { directionFactor = - 1.0; } steepestDescent = - VTK_VMTK_LARGE_DOUBLE * directionFactor; steepestDescentLength = VTK_VMTK_LARGE_DOUBLE; steepestDescentEdge[0] = -1; steepestDescentEdge[1] = -1; for (i=0; iGetNumberOfIds(); i++) { cellId = neighborCells->GetId(i); descent = this->GetSteepestDescentInCell(input,cellId,edge,s,descentEdge,descentS,descentLength); if (directionFactor*(descent - steepestDescent) > VTK_VMTK_DOUBLE_TOL) { steepestDescent = descent; steepestDescentLength = descentLength; steepestDescentEdge[0] = descentEdge[0]; steepestDescentEdge[1] = descentEdge[1]; steepestDescentS = descentS; } } neighborCells->Delete(); return steepestDescent; } int vtkvmtkNonManifoldSteepestDescent::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->DescentArrayName) { vtkErrorMacro("No descent array name specified!"); return 1; } if (!input->GetPointData()->GetArray(this->DescentArrayName)) { vtkErrorMacro("Descent array with specified name does not exist!"); return 1; } this->DescentArray = input->GetPointData()->GetArray(this->DescentArrayName); return 1; } void vtkvmtkNonManifoldSteepestDescent::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkNonManifoldSteepestDescent.h0000664000175000017500000000650611757446472026206 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNonManifoldSteepestDescent.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkNonManifoldSteepestDescent - Abstract class for steepest descent on a polygonal non-manifold. // .SECTION Description // This class is an abstract filter used as base class for performing steepest descent on a non-manifold surface made of convex polygons (such as the Voronoi diagram) on the basis of a given scalar field. Steepest descent is performed on the edges of input polygons with a first order approximation. // // .SECTION See Also // vtkSteepestDescentLineTracer vtkSurfaceToCenterlines vtkVoronoiDiagram3D #ifndef __vtkvmtkNonManifoldSteepestDescent_h #define __vtkvmtkNonManifoldSteepestDescent_h #include "vtkPolyDataAlgorithm.h" #include "vtkDataArray.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #define VTK_VMTK_DOWNWARD 0 #define VTK_VMTK_UPWARD 1 class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkNonManifoldSteepestDescent : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkNonManifoldSteepestDescent,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkNonManifoldSteepestDescent *New(); // Description: // Set/Get the name of the point data array used as the descent scalar field. vtkSetStringMacro(DescentArrayName); vtkGetStringMacro(DescentArrayName); vtkSetMacro(Direction,int); vtkGetMacro(Direction,int); void SetDirectionToDownward() {this->SetDirection(VTK_VMTK_DOWNWARD); } void SetDirectionToUpward() {this->SetDirection(VTK_VMTK_UPWARD); } protected: vtkvmtkNonManifoldSteepestDescent(); ~vtkvmtkNonManifoldSteepestDescent(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); // Description: // Compute the steepest descent point in terms of edge (point id pair) and parametric coordinate on edge. It takes in input a starting point expressed in terms of edge (point id pair) and parametric coordinate on edge. It returns the descent value. double GetSteepestDescent(vtkPolyData* input, vtkIdType* edge, double s, vtkIdType* steepestDescentEdge, double &steepestDescentS); double GetSteepestDescentInCell(vtkPolyData* input, vtkIdType cellId, vtkIdType* edge, double s, vtkIdType* steepestDescentEdge, double &steepestDescentS, double &steepestDescentLength); vtkDataArray* DescentArray; char* DescentArrayName; int NumberOfEdgeSubdivisions; int Direction; private: vtkvmtkNonManifoldSteepestDescent(const vtkvmtkNonManifoldSteepestDescent&); // Not implemented. void operator=(const vtkvmtkNonManifoldSteepestDescent&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineSphereDistance.h0000664000175000017500000000407211757446472025665 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineSphereDistance.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkCenterlineSphereDistance,vtkObject); void PrintSelf(ostream& os, vtkIndent indent); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataCenterlineGroupsClipper.h0000664000175000017500000000643611757446472027226 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCenterlineGroupsClipper.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCenterlineGroupsClipper - . // .SECTION Description // ... #ifndef __vtkvmtkPolyDataCenterlineGroupsClipper_h #define __vtkvmtkPolyDataCenterlineGroupsClipper_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" #include "vtkIdList.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataCenterlineGroupsClipper : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataCenterlineGroupsClipper,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataCenterlineGroupsClipper *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); vtkPolyData* GetClippedOutput(); vtkSetMacro(CutoffRadiusFactor,double); vtkGetMacro(CutoffRadiusFactor,double); vtkSetMacro(ClipValue,double); vtkGetMacro(ClipValue,double); vtkSetMacro(UseRadiusInformation,int); vtkGetMacro(UseRadiusInformation,int); vtkBooleanMacro(UseRadiusInformation,int); protected: vtkvmtkPolyDataCenterlineGroupsClipper(); ~vtkvmtkPolyDataCenterlineGroupsClipper(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkPolyData* Centerlines; vtkIdList* CenterlineGroupIds; char* CenterlineGroupIdsArrayName; char* CenterlineRadiusArrayName; char* GroupIdsArrayName; char* BlankingArrayName; int ClipAllCenterlineGroupIds; double CutoffRadiusFactor; double ClipValue; int GenerateClippedOutput; int UseRadiusInformation; private: vtkvmtkPolyDataCenterlineGroupsClipper(const vtkvmtkPolyDataCenterlineGroupsClipper&); // Not implemented. void operator=(const vtkvmtkPolyDataCenterlineGroupsClipper&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBifurcationProfiles.h0000664000175000017500000000645211757446472026366 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBifurcationProfiles.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataBifurcationProfiles - ... // .SECTION Description // ... #ifndef __vtkvmtkPolyDataBifurcationProfiles_h #define __vtkvmtkPolyDataBifurcationProfiles_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" class VTK_VMTK_COMPUTATIONAL_GEOMETRY_EXPORT vtkvmtkPolyDataBifurcationProfiles : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkPolyDataBifurcationProfiles,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyDataBifurcationProfiles* 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(BifurcationProfileGroupIdsArrayName); vtkGetStringMacro(BifurcationProfileGroupIdsArrayName); vtkSetStringMacro(BifurcationProfileBifurcationGroupIdsArrayName); vtkGetStringMacro(BifurcationProfileBifurcationGroupIdsArrayName); vtkSetStringMacro(BifurcationProfileOrientationArrayName); vtkGetStringMacro(BifurcationProfileOrientationArrayName); protected: vtkvmtkPolyDataBifurcationProfiles(); ~vtkvmtkPolyDataBifurcationProfiles(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ComputeBifurcationProfiles(vtkPolyData* input, int bifurcationGroupId, vtkIdList* upStreamGroupIds, vtkIdList* downStreamGroupIds, vtkPolyData* output); vtkPolyData* Centerlines; char* GroupIdsArrayName; char* CenterlineRadiusArrayName; char* CenterlineGroupIdsArrayName; char* CenterlineIdsArrayName; char* CenterlineTractIdsArrayName; char* BlankingArrayName; char* BifurcationProfileGroupIdsArrayName; char* BifurcationProfileBifurcationGroupIdsArrayName; char* BifurcationProfileOrientationArrayName; private: vtkvmtkPolyDataBifurcationProfiles(const vtkvmtkPolyDataBifurcationProfiles&); // Not implemented. void operator=(const vtkvmtkPolyDataBifurcationProfiles&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBranchExtractor.h0000664000175000017500000000355211757446472026057 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBranchExtractor.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkCenterlineBranchExtractor,vtkvmtkCenterlineSplittingAndGroupingFilter); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCenterlineBranchExtractor *New(); protected: vtkvmtkCenterlineBranchExtractor(); ~vtkvmtkCenterlineBranchExtractor(); virtual void ComputeCenterlineSplitting(vtkPolyData* input, vtkIdType cellId); virtual void GroupTracts(vtkPolyData* input, vtkPolyData* centerlineTracts); private: vtkvmtkCenterlineBranchExtractor(const vtkvmtkCenterlineBranchExtractor&); // Not implemented. void operator=(const vtkvmtkCenterlineBranchExtractor&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineUtilities.h0000664000175000017500000001014011757446472024730 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineUtilities.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .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: vtkTypeRevisionMacro(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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyBall.cxx0000664000175000017500000000603011757446472023040 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBall.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:28 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyBall, "$Revision: 1.2 $"); 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; iInput->GetNumberOfPoints(); i++) { this->Input->GetPoint(i,px); pr = polyballRadiusArray->GetComponent(i,0); 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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkUnstructuredGridCenterlineGroupsClipper.h0000664000175000017500000000660511757446472031024 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridCenterlineGroupsClipper.h,v $ Language: C++ Date: Sun Feb 20 15:29:37 CET 2011 Version: Revision: 1.0 Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - . // .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: vtkTypeRevisionMacro(vtkvmtkUnstructuredGridCenterlineGroupsClipper,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBifurcationSections.cxx0000664000175000017500000005563211757446472026751 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBifurcationSections.cxx,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataBifurcationSections, "$Revision: 1.1 $"); 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; iGetNumberOfIds(); 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; iInsertNextId(upStreamGroupIds->GetId(i)); bifurcationSectionOrientations->InsertNextValue(vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_UPSTREAM_ORIENTATION); } for (i=0; iInsertNextId(downStreamGroupIds->GetId(i)); bifurcationSectionOrientations->InsertNextValue(vtkvmtkCenterlineBifurcationVectors::VTK_VMTK_DOWNSTREAM_ORIENTATION); } int numberOfBifurcationSections = bifurcationSectionGroupIds->GetNumberOfIds(); for (i=0; iGetId(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; jGetNumberOfIds(); 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; jInsertNextPoint(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); } vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyBall.h0000664000175000017500000000435011757446472022470 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBall.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - // .SECTION Description // .. #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: vtkTypeRevisionMacro(vtkvmtkPolyBall,vtkImplicitFunction); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkPolyBall *New(); // Description // Evaluate polyball. double EvaluateFunction(double x[3]); double EvaluateFunction(double x, double y, double z) {return this->vtkImplicitFunction::EvaluateFunction(x, y, z); } ; // Description // Evaluate polyball gradient. void EvaluateGradient(double x[3], double n[3]); // Description: // Set / get input poly data. vtkSetObjectMacro(Input,vtkPolyData); vtkGetObjectMacro(Input,vtkPolyData); // 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkPolyDataBranchSections.h0000664000175000017500000001031211757446472025310 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataBranchSections.h,v $ Language: C++ Date: $Date: 2006/10/17 15:16:16 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - ... // .SECTION Description // ... #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: vtkTypeRevisionMacro(vtkvmtkPolyDataBranchSections,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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 vmtk-1.0.1/vtkVmtk/ComputationalGeometry/vtkvmtkCenterlineBifurcationReferenceSystems.cxx0000664000175000017500000003243711757446472031021 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineBifurcationReferenceSystems.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.8 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkCenterlineBifurcationReferenceSystems.h" #include "vtkPolyData.h" #include "vtkDoubleArray.h" #include "vtkIntArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkPolyLine.h" #include "vtkPoints.h" #include "vtkTriangle.h" #include "vtkvmtkConstants.h" #include "vtkvmtkMath.h" #include "vtkMath.h" #include "vtkCellArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkCenterlineUtilities.h" vtkCxxRevisionMacro(vtkvmtkCenterlineBifurcationReferenceSystems, "$Revision: 1.8 $"); vtkStandardNewMacro(vtkvmtkCenterlineBifurcationReferenceSystems); vtkvmtkCenterlineBifurcationReferenceSystems::vtkvmtkCenterlineBifurcationReferenceSystems() { this->RadiusArrayName = NULL; this->GroupIdsArrayName = NULL; this->BlankingArrayName = NULL; this->NormalArrayName = NULL; this->UpNormalArrayName = NULL; } vtkvmtkCenterlineBifurcationReferenceSystems::~vtkvmtkCenterlineBifurcationReferenceSystems() { if (this->RadiusArrayName) { delete[] this->RadiusArrayName; this->RadiusArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } if (this->BlankingArrayName) { delete[] this->BlankingArrayName; this->BlankingArrayName = NULL; } if (this->NormalArrayName) { delete[] this->NormalArrayName; this->NormalArrayName = NULL; } if (this->UpNormalArrayName) { delete[] this->UpNormalArrayName; this->UpNormalArrayName = NULL; } } int vtkvmtkCenterlineBifurcationReferenceSystems::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())); vtkDataArray* radiusArray; vtkDataArray* groupIdsArray; vtkDataArray* blankingArray; if (!this->RadiusArrayName) { vtkErrorMacro(<<"RadiusArrayName not specified"); return 1; } radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); if (!radiusArray) { vtkErrorMacro(<<"RadiusArray with name specified does not exist"); return 1; } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not specified"); return 1; } groupIdsArray = input->GetCellData()->GetArray(this->GroupIdsArrayName); if (!input->GetCellData()->GetArray(this->GroupIdsArrayName)) { vtkErrorMacro(<<"GroupIdsArray with name specified does not exist"); return 1; } if (!this->BlankingArrayName) { vtkErrorMacro(<<"BlankingArrayName not specified"); return 1; } blankingArray = input->GetCellData()->GetArray(this->BlankingArrayName); if (!input->GetCellData()->GetArray(this->BlankingArrayName)) { vtkErrorMacro(<<"BlankingArray with name specified does not exist"); return 1; } if (!this->NormalArrayName) { vtkErrorMacro(<<"NormalArrayName not specified"); return 1; } if (!this->UpNormalArrayName) { vtkErrorMacro(<<"UpNormalArrayName not specified"); return 1; } vtkPoints* outputPoints = vtkPoints::New(); vtkDoubleArray* normalArray = vtkDoubleArray::New(); normalArray->SetName(this->NormalArrayName); normalArray->SetNumberOfComponents(3); vtkDoubleArray* upNormalArray = vtkDoubleArray::New(); upNormalArray->SetName(this->UpNormalArrayName); upNormalArray->SetNumberOfComponents(3); vtkIntArray* referenceGroupIdsArray = vtkIntArray::New(); referenceGroupIdsArray->SetName(this->GroupIdsArrayName); vtkIdList* blankedGroupIds = vtkIdList::New(); vtkvmtkCenterlineUtilities::GetBlankedGroupsIdList(input,this->GroupIdsArrayName,this->BlankingArrayName,blankedGroupIds); int i; for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = blankedGroupIds->GetId(i); this->ComputeGroupReferenceSystem(input,groupId,outputPoints,normalArray,upNormalArray,referenceGroupIdsArray); } blankedGroupIds->Delete(); vtkCellArray* outputVertices = vtkCellArray::New(); int numberOfOutputPoints = outputPoints->GetNumberOfPoints(); for (i=0; iInsertNextCell(1); outputVertices->InsertCellPoint(i); } output->SetPoints(outputPoints); output->SetVerts(outputVertices); output->GetPointData()->AddArray(normalArray); output->GetPointData()->AddArray(upNormalArray); output->GetPointData()->AddArray(referenceGroupIdsArray); outputPoints->Delete(); outputVertices->Delete(); normalArray->Delete(); upNormalArray->Delete(); referenceGroupIdsArray->Delete(); return 1; } void vtkvmtkCenterlineBifurcationReferenceSystems::ComputeGroupReferenceSystem(vtkPolyData* input, int referenceGroupId, vtkPoints* outputPoints, vtkDoubleArray* normalArray, vtkDoubleArray* upNormalArray, vtkIntArray* referenceGroupIdsArray) { vtkDataArray* radiusArray; vtkDataArray* groupIdsArray; vtkDataArray* blankingArray; radiusArray = input->GetPointData()->GetArray(this->RadiusArrayName); groupIdsArray = input->GetCellData()->GetArray(this->GroupIdsArrayName); blankingArray = input->GetCellData()->GetArray(this->BlankingArrayName); vtkIdType point0Id, point1Id; double point0[3]; double point1[3]; double radius0; double radius1; vtkPoints* bifurcationPoints = vtkPoints::New(); vtkDoubleArray* bifurcationRadii = vtkDoubleArray::New(); vtkIdList* groupCellIds = vtkIdList::New(); // vtkvmtkCenterlineUtilities::GetGroupCellIds(input,this->GroupIdsArrayName,referenceGroupId,groupCellIds); vtkvmtkCenterlineUtilities::GetGroupUniqueCellIds(input,this->GroupIdsArrayName,referenceGroupId,groupCellIds); int i; for (i=0; iGetNumberOfIds(); i++) { vtkIdType cellId = groupCellIds->GetId(i); vtkCell* polyLine = input->GetCell(cellId); if (polyLine->GetCellType() != VTK_LINE && polyLine->GetCellType() != VTK_POLY_LINE) { continue; } point0Id = polyLine->GetPointId(0); input->GetPoint(point0Id,point0); point1Id = polyLine->GetPointId(polyLine->GetNumberOfPoints()-1); input->GetPoint(point1Id,point1); bool skip = false; for (int j=0; jGetNumberOfPoints(); j+=2) { if (vtkMath::Distance2BetweenPoints(point0,bifurcationPoints->GetPoint(j)) < VTK_VMTK_DOUBLE_TOL && vtkMath::Distance2BetweenPoints(point1,bifurcationPoints->GetPoint(j+1)) < VTK_VMTK_DOUBLE_TOL) { skip = true; break; } } if (skip) { continue; } radius0 = radiusArray->GetComponent(point0Id,0); bifurcationPoints->InsertNextPoint(point0); bifurcationRadii->InsertNextTuple1(radius0); radius1 = radiusArray->GetComponent(point1Id,0); bifurcationPoints->InsertNextPoint(point1); bifurcationRadii->InsertNextTuple1(radius1); } groupCellIds->Delete(); int numberOfBifurcationPoints = bifurcationPoints->GetNumberOfPoints(); double bifurcationOrigin[3]; double bifurcationNormal[3]; double bifurcationUpNormal[3]; double point[3]; double radius; double weight; double weightSum; bifurcationOrigin[0] = bifurcationOrigin[1] = bifurcationOrigin[2] = 0.0; weightSum = 0.0; for (i=0; iGetPoint(i,point); radius = bifurcationRadii->GetComponent(i,0); weight = radius*radius; bifurcationOrigin[0] += weight * point[0]; bifurcationOrigin[1] += weight * point[1]; bifurcationOrigin[2] += weight * point[2]; weightSum += weight; } bifurcationOrigin[0] /= weightSum; bifurcationOrigin[1] /= weightSum; bifurcationOrigin[2] /= weightSum; vtkDoubleArray* bifurcationNormals = vtkDoubleArray::New(); bifurcationNormals->SetNumberOfComponents(3); vtkPoints* vertexPoints = vtkPoints::New(); for (i=0; iInitialize(); if (vtkMath::Distance2BetweenPoints(bifurcationPoints->GetPoint(i),bifurcationPoints->GetPoint(j))InsertPoint(0,bifurcationPoints->GetPoint(i)); vertexPoints->InsertPoint(1,bifurcationPoints->GetPoint(i+1)); vertexPoints->InsertPoint(2,bifurcationPoints->GetPoint(j+1)); } else { vertexPoints->InsertPoint(0,bifurcationPoints->GetPoint(i)); vertexPoints->InsertPoint(1,bifurcationPoints->GetPoint(i+1)); vertexPoints->InsertPoint(2,bifurcationPoints->GetPoint(j+1)); vertexPoints->InsertPoint(3,bifurcationPoints->GetPoint(j)); } int numberOfPolygonPoints = vertexPoints->GetNumberOfPoints(); double vertexPoint0[3], vertexPoint1[3], vertexPoint2[3]; double vertexNormal[3]; double cotangent0, cotangent1; double polygonNormal[3]; polygonNormal[0] = polygonNormal[1] = polygonNormal[2] = 0.0; for (int n=0; nGetPoint(vertexId0,vertexPoint0); vertexPoints->GetPoint(vertexId1,vertexPoint1); vertexPoints->GetPoint(vertexId2,vertexPoint2); vtkTriangle::ComputeNormal(vertexPoint0,vertexPoint1,vertexPoint2,vertexNormal); cotangent0 = vtkvmtkMath::Cotangent(vertexPoint0,vertexPoint1,bifurcationOrigin); cotangent1 = vtkvmtkMath::Cotangent(bifurcationOrigin,vertexPoint1,vertexPoint2); weight = (cotangent0 + cotangent1) / vtkMath::Distance2BetweenPoints(bifurcationOrigin,vertexPoint1); for (int k=0; k<3; k++) { polygonNormal[k] += weight * vertexNormal[k]; } } vtkMath::Normalize(polygonNormal); bifurcationNormals->InsertNextTuple(polygonNormal); } } int numberOfNormals = bifurcationNormals->GetNumberOfTuples(); double positiveNormal[3], orientedNormal[3]; bifurcationNormals->GetTuple(0,positiveNormal); for (i=1; iGetTuple(i,orientedNormal); if (vtkMath::Dot(positiveNormal,orientedNormal) < 0.0) { orientedNormal[0] *= -1.0; orientedNormal[1] *= -1.0; orientedNormal[2] *= -1.0; bifurcationNormals->SetTuple(i,orientedNormal); } } bifurcationNormal[0] = bifurcationNormal[1] = bifurcationNormal[2] = 0.0; for (i=0; iGetTuple(i,orientedNormal); for (int k=0; k<3; k++) { bifurcationNormal[k] += orientedNormal[k]; } } vtkMath::Normalize(bifurcationNormal); bifurcationUpNormal[0] = bifurcationUpNormal[1] = bifurcationUpNormal[2] = 0.0; double upVector[3], projectedUpVector[3]; weightSum = 0.0; for (i=0; iGetPoint(i+1,point1); bifurcationPoints->GetPoint(i,point0); radius0 = bifurcationRadii->GetTuple1(i); radius1 = bifurcationRadii->GetTuple1(i+1); //weight upVectors with squared sphere radii //weight = radius0 * radius0 + radius1 * radius1; //weight upVectors with squared sphere radii of downstream branch weight = radius1 * radius1; int k; for (k=0; k<3; k++) { upVector[k] = point1[k] - point0[k]; } double dot = vtkMath::Dot(upVector,bifurcationNormal); for (k=0; k<3; k++) { projectedUpVector[k] = upVector[k] - dot * bifurcationNormal[k]; } vtkMath::Normalize(projectedUpVector); for (k=0; k<3; k++) { bifurcationUpNormal[k] += projectedUpVector[k] * weight; } weightSum += weight; } vtkMath::Normalize(bifurcationUpNormal); outputPoints->InsertNextPoint(bifurcationOrigin); normalArray->InsertNextTuple(bifurcationNormal); upNormalArray->InsertNextTuple(bifurcationUpNormal); referenceGroupIdsArray->InsertNextTuple1(referenceGroupId); vertexPoints->Delete(); bifurcationPoints->Delete(); bifurcationRadii->Delete(); bifurcationNormals->Delete(); } void vtkvmtkCenterlineBifurcationReferenceSystems::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/CMakeLists.txt0000664000175000017500000000717711757446472015371 0ustar lucalucaPROJECT(VTK_VMTK) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) IF(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) ENDIF(COMMAND cmake_policy) SUBDIRS( Common ComputationalGeometry DifferentialGeometry IO Misc Segmentation Utilities ) IF (VTK_USE_RENDERING) SUBDIRS( Rendering ) ENDIF (VTK_USE_RENDERING) OPTION(VTK_VMTK_CONTRIB "Build and install classes in the vtkVmtk/Contrib directory." OFF) IF (VTK_VMTK_CONTRIB) SUBDIRS(Contrib) ENDIF (VTK_VMTK_CONTRIB) INCLUDE (${VTK_VMTK_SOURCE_DIR}/CMakeOptions.cmake) CONFIGURE_FILE( ${VTK_VMTK_SOURCE_DIR}/vtkvmtkConfigure.h.in ${VTK_VMTK_BINARY_DIR}/vtkvmtkConfigure.h ) if(APPLE) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib") set(CMAKE_EXE_LINKER_FLAGS "-Wl,-dylib_file,/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib:/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib") endif(APPLE) OPTION(VTK_VMTK_BUILD_TETGEN "Build TetGen and TetGen wrapper. Check TetGen license before you activate this." ON) OPTION(VTK_VMTK_BUILD_STREAMTRACER "Build static temporal stream tracer." ON) IF (VTK_USE_COCOA) OPTION(VTK_VMTK_USE_COCOA "Build the Cocoa vmtk classes." ON) ENDIF (VTK_USE_COCOA) IF(NOT VTK_VMTK_INSTALL_BIN_DIR) #SET(VTK_VMTK_INSTALL_BIN_DIR ${VTK_VMTK_INSTALL_ROOT}/bin) SET(VTK_VMTK_INSTALL_BIN_DIR bin) ENDIF(NOT VTK_VMTK_INSTALL_BIN_DIR) IF(NOT VTK_VMTK_INSTALL_INCLUDE_DIR) #SET(VTK_VMTK_INSTALL_INCLUDE_DIR ${VTK_VMTK_INSTALL_ROOT}/include/vmtk) SET(VTK_VMTK_INSTALL_INCLUDE_DIR include/vmtk) ENDIF(NOT VTK_VMTK_INSTALL_INCLUDE_DIR) IF(NOT VTK_VMTK_INSTALL_LIB_DIR) #SET(VTK_VMTK_INSTALL_LIB_DIR ${VTK_VMTK_INSTALL_ROOT}/lib/vmtk) SET(VTK_VMTK_INSTALL_LIB_DIR lib/vmtk) ENDIF(NOT VTK_VMTK_INSTALL_LIB_DIR) IF(NOT VTK_VMTK_MODULE_INSTALL_LIB_DIR) #SET(VTK_VMTK_MODULE_INSTALL_LIB_DIR ${VTK_VMTK_INSTALL_ROOT}/lib/vmtk/vmtk) SET(VTK_VMTK_MODULE_INSTALL_LIB_DIR lib/vmtk/vmtk) ENDIF(NOT VTK_VMTK_MODULE_INSTALL_LIB_DIR) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/Common) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/ComputationalGeometry) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/DifferentialGeometry) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/IO) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/Misc) IF (VTK_USE_RENDERING) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/Rendering) ENDIF (VTK_USE_RENDERING) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/Segmentation) IF (VTK_VMTK_CONTRIB) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/Contrib) ENDIF (VTK_VMTK_CONTRIB) INCLUDE_DIRECTORIES (${VTK_VMTK_SOURCE_DIR}/Utilities/vtkvmtkITK) INCLUDE_DIRECTORIES (${VTK_VMTK_BINARY_DIR}) SET(VTK_DOXYGEN_HOME ${VTK_VMTK_SOURCE_DIR}/Utilities/Doxygen) FILE(GLOB files "${VTK_VMTK_BINARY_DIR}/vtkvmtkConfigure*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) INCLUDE_DIRECTORIES (${VTK_PYTHON_INCLUDE_DIR}) CONFIGURE_FILE(${VTK_VMTK_SOURCE_DIR}/vtkvmtk.py ${VTK_VMTK_BINARY_DIR}/vtkvmtk.py COPYONLY) #INSTALL_FILES(${VTK_VMTK_MODULE_INSTALL_LIB_DIR} FILES ${VTK_VMTK_BINARY_DIR}/vtkvmtk.py) INSTALL(FILES ${VTK_VMTK_BINARY_DIR}/vtkvmtk.py DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) SET(TETGEN_SOURCE_DIR "${VTK_VMTK_SOURCE_DIR}/Utilities/tetgen1.4.3") vmtk-1.0.1/vtkVmtk/vtkvmtk.py0000664000175000017500000000147111757446472014700 0ustar lucaluca""" This module loads all the classes from the vtkVmtk library into its namespace. This is a required module.""" import os import vtk if os.name == 'posix': from libvtkvmtkCommonPython import * from libvtkvmtkComputationalGeometryPython import * from libvtkvmtkDifferentialGeometryPython import * from libvtkvmtkIOPython import * from libvtkvmtkMiscPython import * from libvtkvmtkRenderingPython import * from libvtkvmtkSegmentationPython import * from libvtkvmtkITKPython import * else: from vtkvmtkCommonPython import * from vtkvmtkComputationalGeometryPython import * from vtkvmtkDifferentialGeometryPython import * from vtkvmtkIOPython import * from vtkvmtkRenderingPython import * from vtkvmtkSegmentationPython import * from vtkvmtkITKPython import * vmtk-1.0.1/vtkVmtk/Contrib/0000775000175000017500000000000011757446472014215 5ustar lucalucavmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyBallLine2.h0000664000175000017500000000734111757446472020432 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBallLine2.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkPolyBallLine2 - // .SECTION Description // This is another version of a polyball line // Here the ditance to the line is first computed and then the radius at the closest point is substracted // This way each line segment only influences its voronoi cell #ifndef __vtkvmtkPolyBallLine2_h #define __vtkvmtkPolyBallLine2_h #include "vtkImplicitFunction.h" #include "vtkPolyData.h" #include "vtkIdList.h" #include "vtkTriangleFilter.h" #include "vtkCellLocator.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_CONTRIB_EXPORT vtkvmtkPolyBallLine2 : public vtkImplicitFunction { public: static vtkvmtkPolyBallLine2 *New(); vtkTypeRevisionMacro(vtkvmtkPolyBallLine2,vtkImplicitFunction); void PrintSelf(ostream& os, vtkIndent indent); // Description // Evaluate polyball. double EvaluateFunction(double x[3]); double EvaluateFunction(double x, double y, double z) {return this->vtkImplicitFunction::EvaluateFunction(x, y, z); } ; // Description // Evaluate polyball gradient. void EvaluateGradient(double x[3], double n[3]); // Description: // Set / get input poly data. virtual void SetInput(vtkPolyData *inp); vtkGetObjectMacro(Input,vtkPolyData); // Description: // Set / get input cell ids used for the function. virtual void SetInputCellIds(vtkIdList *cellIds); vtkGetObjectMacro(InputCellIds,vtkIdList); // Description: // Set / get a single input cell id used for the function. virtual void SetInputCellId(vtkIdType cellId); vtkGetMacro(InputCellId,vtkIdType); // Description: // Set / get poly ball radius array name. vtkSetStringMacro(PolyBallRadiusArrayName); vtkGetStringMacro(PolyBallRadiusArrayName); vtkSetMacro(UseRadiusInformation,int); vtkGetMacro(UseRadiusInformation,int); vtkBooleanMacro(UseRadiusInformation,int); static double ComplexDot(double x[4], double y[4]); protected: vtkvmtkPolyBallLine2(); ~vtkvmtkPolyBallLine2(); vtkPolyData* Input; vtkIdList* InputCellIds; vtkIdType InputCellId; char* PolyBallRadiusArrayName; vtkIdType LastPolyBallCellId; vtkIdType LastPolyBallCellSubId; double LastPolyBallCellPCoord; double LastPolyBallCenter[3]; double LastPolyBallCenterRadius; int UseRadiusInformation; // Used to triangulate the polylines vtkTriangleFilter *Triangulator; //For faster distance computation vtkCellLocator *Locator; //Local copy of the cells used in the input vtkPolyData *LocalInput; //Triangulated input (for increased performance) vtkPolyData *TriangulatedInput; //Should the locator be rebuild bool ShouldBuildLocator; //MTime of input last time the locator was built unsigned long LocatorMTime; //Rebuild the locator void BuildLocator(); private: vtkvmtkPolyBallLine2(const vtkvmtkPolyBallLine2&); // Not implemented. void operator=(const vtkvmtkPolyBallLine2&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkRBFInterpolation2.cxx0000664000175000017500000001126311757446472021636 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkRBFInterpolation2.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:28 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkRBFInterpolation2.h" #include "vtkvmtkConstants.h" #include "vtkPointData.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkRBFInterpolation2, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkRBFInterpolation2); vtkvmtkRBFInterpolation2::vtkvmtkRBFInterpolation2() { this->Source = NULL; this->RBFType = THIN_PLATE_SPLINE; this->Coefficients = NULL; } vtkvmtkRBFInterpolation2::~vtkvmtkRBFInterpolation2() { if (this->Source) { this->Source->Delete(); this->Source = NULL; } if (this->Coefficients) { this->Coefficients->Delete(); this->Coefficients = NULL; } } double vtkvmtkRBFInterpolation2::EvaluateRBF(double c[3], double x[3]) { if (this->RBFType == THIN_PLATE_SPLINE) { double r2 = vtkMath::Distance2BetweenPoints(c,x); if (!r2) { return 0.0; } return r2 * log(sqrt(r2)); } else if (this->RBFType == BIHARMONIC) { return sqrt(vtkMath::Distance2BetweenPoints(c,x)); } else if (this->RBFType == TRIHARMONIC) { return pow(vtkMath::Distance2BetweenPoints(c,x),1.5); } else { vtkErrorMacro(<<"Error: Unsupported RBFType!"); return 0.0; } } void vtkvmtkRBFInterpolation2::ComputeCoefficients() { if (this->Coefficients) { this->Coefficients->Delete(); this->Coefficients = NULL; } if (!this->Source) { vtkErrorMacro("No Source specified!"); return; } vtkDataArray *sourceScalars = this->Source->GetPointData()->GetScalars(); if (!sourceScalars) { vtkErrorMacro("No scalars to interpolate!"); return; } int numberOfPoints = this->Source->GetNumberOfPoints(); if (!numberOfPoints) { vtkWarningMacro("Empty Source specified!"); return; } this->Coefficients = vtkDoubleArray::New(); this->Coefficients->SetNumberOfValues(numberOfPoints); double **A, *x; x = new double[numberOfPoints]; A = new double* [numberOfPoints]; int i; for (i=0; iGetComponent(i,0); } double center[3]; int j; for (i=0; iSource->GetPoint(i,center); for (j=0; jEvaluateRBF(center,this->Source->GetPoint(j)); } } int ret = vtkMath::SolveLinearSystem(A,x,numberOfPoints); if (!ret) { vtkErrorMacro(<<"Cannot compute coefficients: error during linear system solve"); } for (i=0; iCoefficients->SetValue(i,x[i]); } delete[] x; for (i=0; iSource) { vtkErrorMacro("No Source specified!"); return 0.0; } int numberOfPoints = this->Source->GetNumberOfPoints(); if (!numberOfPoints) { vtkWarningMacro("Empty Source specified!"); return 0.0; } if (!this->Coefficients) { this->ComputeCoefficients(); } double rbfValue = 0.0; double center[3]; int i; for (i=0; iSource->GetPoint(i,center); rbfValue += this->Coefficients->GetValue(i) * this->EvaluateRBF(center,x); } return rbfValue; } void vtkvmtkRBFInterpolation2::EvaluateGradient(double x[3], double n[3]) { vtkWarningMacro("RBF gradient computation not implemented."); } unsigned long vtkvmtkRBFInterpolation2::GetMTime() { unsigned long mTime=this->Superclass::GetMTime(); unsigned long sourceMTime; if (this->Source != NULL) { sourceMTime = this->Source->GetMTime(); mTime = ( sourceMTime > mTime ? sourceMTime : mTime ); } return mTime; } void vtkvmtkRBFInterpolation2::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkCellDimensionFilter.cxx0000664000175000017500000000670011757446472022266 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCellDimensionFilter.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkCellDimensionFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkThreshold.h" #include "vtkIntArray.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkCellDimensionFilter, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkCellDimensionFilter); vtkvmtkCellDimensionFilter::vtkvmtkCellDimensionFilter() { this->Threshold = vtkThreshold::New(); } vtkvmtkCellDimensionFilter::~vtkvmtkCellDimensionFilter() { if (this->Threshold) { this->Threshold->Delete(); } } int vtkvmtkCellDimensionFilter::FillInputPortInformation(int, vtkInformation *info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); return 1; } void vtkvmtkCellDimensionFilter::ThresholdByLower(int lower) { Threshold->ThresholdByLower(lower); } void vtkvmtkCellDimensionFilter::ThresholdByUpper(int upper) { Threshold->ThresholdByUpper(upper); } void vtkvmtkCellDimensionFilter::ThresholdBetween(int lower, int upper) { Threshold->ThresholdBetween(lower,upper); } int vtkvmtkCellDimensionFilter::GetLowerThreshold() { return Threshold->GetLowerThreshold(); } int vtkvmtkCellDimensionFilter::GetUpperThreshold() { return Threshold->GetUpperThreshold(); } int vtkvmtkCellDimensionFilter::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); vtkInformation *outInfo = outputVector->GetInformationObject(0); vtkDataSet *input = vtkDataSet::SafeDownCast( inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast( outInfo->Get(vtkUnstructuredGrid::DATA_OBJECT())); vtkIdType numberOfCells = input->GetNumberOfCells(); vtkIntArray *cellDimensionArray = vtkIntArray::New(); cellDimensionArray->SetName("CellDimensionArray"); cellDimensionArray->SetNumberOfComponents(1); cellDimensionArray->SetNumberOfTuples(numberOfCells); for (int i=0; iSetValue(i,input->GetCell(i)->GetCellDimension()); } input->GetCellData()->AddArray(cellDimensionArray); Threshold->SetInput(input); Threshold->SetInputArrayToProcess(0,0,0,1,"CellDimensionArray"); Threshold->Update(); output->DeepCopy(Threshold->GetOutput()); input->GetCellData()->RemoveArray("CellDimensionArray"); cellDimensionArray->Delete(); return 1; } void vtkvmtkCellDimensionFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataGeodesicRBFInterpolation.h0000664000175000017500000000516511757446472024306 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataGeodesicRBFInterpolation.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkPolyDataGeodesicRBFInterpolation - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataGeodesicRBFInterpolation_h #define __vtkvmtkPolyDataGeodesicRBFInterpolation_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" #include "vtkIdList.h" #include "vtkDoubleArray.h" class VTK_VMTK_CONTRIB_EXPORT vtkvmtkPolyDataGeodesicRBFInterpolation : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataGeodesicRBFInterpolation* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataGeodesicRBFInterpolation,vtkPolyDataAlgorithm); vtkSetObjectMacro(SeedIds,vtkIdList); vtkGetObjectMacro(SeedIds,vtkIdList); vtkSetObjectMacro(SeedValues,vtkDataArray); vtkGetObjectMacro(SeedValues,vtkDataArray); vtkSetStringMacro(InterpolatedArrayName); vtkGetStringMacro(InterpolatedArrayName); vtkSetMacro(RBFType,int); vtkGetMacro(RBFType,int); void SetRBFTypeToThinPlateSpline() { this->SetRBFType(THIN_PLATE_SPLINE); } void SetRBFTypeToBiharmonic() { this->SetRBFType(BIHARMONIC); } void SetRBFTypeToTriharmonic() { this->SetRBFType(TRIHARMONIC); } //BTX enum { THIN_PLATE_SPLINE, BIHARMONIC, TRIHARMONIC }; //ETX protected: vtkvmtkPolyDataGeodesicRBFInterpolation(); ~vtkvmtkPolyDataGeodesicRBFInterpolation(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); double EvaluateRBF(double r); char* InterpolatedArrayName; vtkIdList* SeedIds; vtkDataArray* SeedValues; int RBFType; private: vtkvmtkPolyDataGeodesicRBFInterpolation(const vtkvmtkPolyDataGeodesicRBFInterpolation&); // Not implemented. void operator=(const vtkvmtkPolyDataGeodesicRBFInterpolation&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkRBFInterpolation2.h0000664000175000017500000000510011757446472021254 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkRBFInterpolation2.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkRBFInterpolation2 - // .SECTION Description // .. #ifndef __vtkvmtkRBFInterpolation2_h #define __vtkvmtkRBFInterpolation2_h #include "vtkImplicitFunction.h" #include "vtkPolyData.h" #include "vtkDoubleArray.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_CONTRIB_EXPORT vtkvmtkRBFInterpolation2 : public vtkImplicitFunction { public: vtkTypeRevisionMacro(vtkvmtkRBFInterpolation2,vtkImplicitFunction); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkRBFInterpolation2 *New(); // Description // Evaluate polyball. double EvaluateFunction(double x[3]); double EvaluateFunction(double x, double y, double z) {return this->vtkImplicitFunction::EvaluateFunction(x, y, z); } ; // Description // Evaluate polyball gradient. void EvaluateGradient(double x[3], double n[3]); void ComputeCoefficients(); // Description: // Set / get source poly data. vtkSetObjectMacro(Source,vtkPolyData); vtkGetObjectMacro(Source,vtkPolyData); vtkSetMacro(RBFType,int); vtkGetMacro(RBFType,int); void SetRBFTypeToThinPlateSpline() { this->SetRBFType(THIN_PLATE_SPLINE); } void SetRBFTypeToBiharmonic() { this->SetRBFType(BIHARMONIC); } void SetRBFTypeToTriharmonic() { this->SetRBFType(TRIHARMONIC); } //BTX enum { THIN_PLATE_SPLINE, BIHARMONIC, TRIHARMONIC }; //ETX unsigned long GetMTime(); protected: vtkvmtkRBFInterpolation2(); ~vtkvmtkRBFInterpolation2(); double EvaluateRBF(double c[3], double x[3]); vtkPolyData* Source; int RBFType; vtkDoubleArray* Coefficients; private: vtkvmtkRBFInterpolation2(const vtkvmtkRBFInterpolation2&); // Not implemented. void operator=(const vtkvmtkRBFInterpolation2&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataGeodesicRBFInterpolation.cxx0000664000175000017500000001507111757446472024656 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataGeodesicRBFInterpolation.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan 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 #include "vtkvmtkConstants.h" #if (VTK_MAJOR_VERSION >= 5) && (VTK_MINOR_VERSION >= 2) #include "vtkDijkstraGraphGeodesicPath.h" #endif vtkCxxRevisionMacro(vtkvmtkPolyDataGeodesicRBFInterpolation, "$Revision: 1.3 $"); 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 vt k> =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(); dijkstraAlgo->SetInput(input); dijkstraAlgo->StopWhenEndReachedOff(); dijkstraAlgo->UseScalarWeightsOff(); vtkstd::vector geodesicDistances; //Compute the geodesic distances for (int i=0; iSetStartVertex(SeedIds->GetId(i)); dijkstraAlgo->Update(); vtkDoubleArray *seedDistances = vtkDoubleArray::New(); #if (VTK_MINOR_VERSION < 5) seedDistances->DeepCopy(dijkstraAlgo->Getd()); #else dijkstraAlgo->GetCumulativeWeights(seedDistances); #endif geodesicDistances.push_back(seedDistances); } //Compute the coefficients double **A, *x; x = new double[numberOfSeeds]; A = new double* [numberOfSeeds]; int i; for (i=0; iSeedValues->GetComponent(i,0); } int j; for (i=0; iGetValue(this->SeedIds->GetId(j)); A[i][j] = this->EvaluateRBF(dist); } } cout << "A " << endl; for (int i=0;iGetValue(i); rbfValue += x[j]*this->EvaluateRBF(dist); } interpolatedArray->SetComponent(i,0,rbfValue); } delete[] x; for (int i=0;iDelete(); } geodesicDistances.clear(); if (createArray) interpolatedArray->Delete(); return 1; #endif } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataDistanceToSpheres.cxx0000664000175000017500000001044411757446472023420 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDistanceToSpheres.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkPolyDataDistanceToSpheres.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkIOStream.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataDistanceToSpheres, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataDistanceToSpheres); vtkvmtkPolyDataDistanceToSpheres::vtkvmtkPolyDataDistanceToSpheres() { this->DistanceToSpheresArrayName = NULL; this->Spheres = NULL; this->DistanceOffset = 0.; this->DistanceScale = 1.; this->MinDistance = 0.; this->MaxDistance = -1.; } vtkvmtkPolyDataDistanceToSpheres::~vtkvmtkPolyDataDistanceToSpheres() { if (this->DistanceToSpheresArrayName) { delete[] this->DistanceToSpheresArrayName; this->DistanceToSpheresArrayName = NULL; } if (this->Spheres) { this->Spheres->Delete(); this->Spheres = NULL; } } int vtkvmtkPolyDataDistanceToSpheres::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->DistanceToSpheresArrayName) { vtkErrorMacro(<<"DistanceToSpheresArrayName not set."); return 1; } if (!this->Spheres) { vtkErrorMacro(<<"Spheres not set"); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkDataArray* distanceToSpheresArray = output->GetPointData()->GetArray(this->DistanceToSpheresArrayName); bool createArray = !distanceToSpheresArray; if (createArray) { distanceToSpheresArray = vtkDoubleArray::New(); distanceToSpheresArray->SetName(this->DistanceToSpheresArrayName); distanceToSpheresArray->SetNumberOfComponents(1); distanceToSpheresArray->SetNumberOfTuples(numberOfInputPoints); distanceToSpheresArray->FillComponent(0, VTK_VMTK_LARGE_DOUBLE); output->GetPointData()->AddArray(distanceToSpheresArray); } int numberOfSpheres = this->Spheres->GetNumberOfPoints(); vtkDataArray* scalarArray = this->Spheres->GetPointData()->GetScalars(); double maxd = this->MaxDistance > 0 ? this->MaxDistance : VTK_VMTK_LARGE_DOUBLE; double point[3], sphereCenter[3]; double sphereRadius = 0.; double distanceToSpheres; for (int i=0; iGetComponent(i,0); input->GetPoint(i,point); for (int j=0; jSpheres->GetPoint(j,sphereCenter); if (scalarArray) sphereRadius = scalarArray->GetComponent(j,0); double newDist = sqrt(vtkMath::Distance2BetweenPoints(point,sphereCenter)) - sphereRadius; if (newDist<0.) newDist = 0.; //Scale and offset the distance newDist = this->DistanceOffset + this->DistanceScale*newDist; if (newDistMinDistance) newDist = this->MinDistance; if (newDist>maxd) newDist = maxd; if (newDistSetComponent(i,0,distanceToSpheres); } if (createArray) distanceToSpheresArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataDistanceToSpheres.h0000664000175000017500000000455011757446472023046 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDistanceToSpheres.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan 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(); vtkTypeRevisionMacro(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 *); 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 vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataDijkstraDistanceToPoints.cxx0000664000175000017500000001137511757446472024763 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDijkstraDistanceToPoints.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkPolyDataDijkstraDistanceToPoints.h" #include "vtkVersion.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkFloatArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkIOStream.h" #include "vtkvmtkConstants.h" #if (VTK_MAJOR_VERSION >= 5) && (VTK_MINOR_VERSION >= 2) #include "vtkDijkstraGraphGeodesicPath.h" #endif vtkCxxRevisionMacro(vtkvmtkPolyDataDijkstraDistanceToPoints, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataDijkstraDistanceToPoints); vtkvmtkPolyDataDijkstraDistanceToPoints::vtkvmtkPolyDataDijkstraDistanceToPoints() { this->DijkstraDistanceToPointsArrayName = NULL; this->SeedIds = NULL; this->DistanceOffset = 0.; this->DistanceScale = 1.; this->MinDistance = 0.; this->MaxDistance = -1.; } vtkvmtkPolyDataDijkstraDistanceToPoints::~vtkvmtkPolyDataDijkstraDistanceToPoints() { if (this->DijkstraDistanceToPointsArrayName) { delete[] this->DijkstraDistanceToPointsArrayName; this->DijkstraDistanceToPointsArrayName = NULL; } if (this->SeedIds) { this->SeedIds->Delete(); this->SeedIds = NULL; } } int vtkvmtkPolyDataDijkstraDistanceToPoints::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 vt k> =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->DijkstraDistanceToPointsArrayName) { vtkErrorMacro(<<"DijkstraDistanceToPointsArrayName not set."); return 1; } if (!this->SeedIds) { vtkErrorMacro(<<"SeedIds not set"); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkDataArray* distanceToPointsArray = output->GetPointData()->GetArray(this->DijkstraDistanceToPointsArrayName); bool createArray = !distanceToPointsArray; if (createArray) { distanceToPointsArray = vtkDoubleArray::New(); distanceToPointsArray->SetName(this->DijkstraDistanceToPointsArrayName); distanceToPointsArray->SetNumberOfComponents(1); distanceToPointsArray->SetNumberOfTuples(numberOfInputPoints); distanceToPointsArray->FillComponent(0, VTK_VMTK_LARGE_DOUBLE); output->GetPointData()->AddArray(distanceToPointsArray); } int numberOfSeeds = this->SeedIds->GetNumberOfIds(); vtkDijkstraGraphGeodesicPath *dijkstraAlgo = vtkDijkstraGraphGeodesicPath::New(); dijkstraAlgo->SetInput(input); dijkstraAlgo->StopWhenEndReachedOff(); dijkstraAlgo->UseScalarWeightsOff(); double maxd = this->MaxDistance > 0 ? this->MaxDistance : VTK_VMTK_LARGE_DOUBLE; for (int i=0; iSetStartVertex(SeedIds->GetId(i)); dijkstraAlgo->Update(); #if (VTK_MINOR_VERSION < 5) vtkFloatArray *seedDistances = dijkstraAlgo->Getd(); #else vtkDoubleArray *seedDistances = vtkDoubleArray::New(); dijkstraAlgo->GetCumulativeWeights(seedDistances); #endif for (int i=0;iDistanceOffset + this->DistanceScale*seedDistances->GetValue(i); if (newDistMinDistance) newDist = this->MinDistance; if (newDist>maxd) newDist = maxd; if (newDistGetComponent(i,0)) distanceToPointsArray->SetComponent(i,0,newDist); } #if (VTK_MINOR_VERSION >= 5) seedDistances->Delete(); #endif } if (createArray) distanceToPointsArray->Delete(); return 1; #endif } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkCenterlineInterpolateArray.h0000664000175000017500000000503011757446472023311 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineInterpolateArray.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkInterpolateCenterlineArray - .. // .SECTION Description // Interpolate a point-based array from a set of values provided #ifndef __vtkvmtkCenterlineInterpolateArray_h #define __vtkvmtkCenterlineInterpolateArray_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkDataArray.h" #include "vtkIdList.h" class VTK_VMTK_CONTRIB_EXPORT vtkvmtkCenterlineInterpolateArray : public vtkPolyDataAlgorithm { public: static vtkvmtkCenterlineInterpolateArray* New(); vtkTypeRevisionMacro(vtkvmtkCenterlineInterpolateArray,vtkPolyDataAlgorithm); //Description: //Default value to fill in when no data is available vtkSetMacro(DefaultValue,double); vtkGetMacro(DefaultValue,double); //Description: //Set/Get the values from which to interpolate vtkSetObjectMacro(Values,vtkDataArray); vtkGetObjectMacro(Values,vtkDataArray); //Description: //Set/Get the point ids corresponding to the provided values vtkSetObjectMacro(ValuesIds,vtkIdList); vtkGetObjectMacro(ValuesIds,vtkIdList); //Description: //Set/Get the name of the resulting array vtkSetStringMacro(InterpolatedArrayName); vtkGetStringMacro(InterpolatedArrayName); protected: vtkvmtkCenterlineInterpolateArray(); ~vtkvmtkCenterlineInterpolateArray(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char *InterpolatedArrayName; double DefaultValue; vtkDataArray *Values; vtkIdList *ValuesIds; private: vtkvmtkCenterlineInterpolateArray(const vtkvmtkCenterlineInterpolateArray&); // Not implemented. void operator=(const vtkvmtkCenterlineInterpolateArray&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/CMakeLists.txt0000664000175000017500000001056311757446472016762 0ustar lucalucaSET (VTK_VMTK_CONTRIB_SRCS vtkvmtkBoundaryLayerGenerator2.cxx vtkvmtkCellDimensionFilter.cxx vtkvmtkCenterlineInterpolateArray.cxx vtkvmtkDolfinWriter2.cxx vtkvmtkPolyBallLine2.cxx vtkvmtkPolyDataDijkstraDistanceToPoints.cxx vtkvmtkPolyDataDistanceToSpheres.cxx vtkvmtkPolyDataGeodesicRBFInterpolation.cxx vtkvmtkPolyDataSampleFunction.cxx vtkvmtkRBFInterpolation2.cxx vtkvmtkSurfaceProjectCellArray.cxx ) SET (VTK_VMTK_CONTRIB_TARGET_LINK_LIBRARIES vtkvmtkContrib vtkvmtkMisc vtkCommon vtkFiltering vtkGraphics vtkHybrid) ADD_LIBRARY (vtkvmtkContrib ${VTK_VMTK_CONTRIB_SRCS}) TARGET_LINK_LIBRARIES(vtkvmtkContrib ${VTK_VMTK_CONTRIB_TARGET_LINK_LIBRARIES}) SET_TARGET_PROPERTIES(vtkvmtkContrib PROPERTIES LINKER_LANGUAGE CXX) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkContrib PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) INSTALL(TARGETS vtkvmtkContrib LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_CONTRIB_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/Contrib/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkContrib) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkContribPython VTK_VMTK_CONTRIB_PYTHON_SRCS "${VTK_VMTK_CONTRIB_SRCS}") ADD_LIBRARY(vtkvmtkContribPythonD ${VTK_VMTK_CONTRIB_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkContribPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkContribPython MODULE vtkvmtkContribPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkContribPythonD vtkvmtkContrib vtkvmtkMisc vtkvmtkMiscPythonD vtkCommon vtkCommonPythonD vtkFiltering vtkFilteringPythonD vtkGraphics vtkGraphicsPythonD) TARGET_LINK_LIBRARIES (vtkvmtkContribPython vtkvmtkContribPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkContribPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkContribPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkContribPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) CONFIGURE_FILE(${VTK_VMTK_SOURCE_DIR}/Contrib/vtkvmtkcontrib.py ${VTK_VMTK_BINARY_DIR}/Contrib/vtkvmtkcontrib.py COPYONLY) #INSTALL_FILES(${VTK_VMTK_MODULE_INSTALL_LIB_DIR} FILES ${VTK_VMTK_BINARY_DIR}/vtkvmtk.py) INSTALL(FILES ${VTK_VMTK_BINARY_DIR}/Contrib/vtkvmtkcontrib.py DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkContribTCL VTK_VMTK_CONTRIB_TCL_SRCS "${VTK_VMTK_CONTRIB_SRCS}" "") ADD_LIBRARY(vtkvmtkContribTCL ${VTK_VMTK_CONTRIB_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkContribTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkContribTCL vtkvmtkContrib vtkvmtkMiscTCL vtkvmtkMisc vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkGraphics vtkGraphicsTCL) INSTALL(TARGETS vtkvmtkContribTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkContribTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkSurfaceProjectCellArray.h0000664000175000017500000000537111757446472022541 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfaceProjectCellArray.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkSurfaceProjectCellArray - ... // .SECTION Description // Projects a cell array from a reference surface // For each cell, the cell value chosen is the one of the cell on the reference surface which has the // smallest minimum distance to the cell vertices. // If the distance of any vertices in the cell to the reference surface is higher than // DistanceTolerance, the cell array values are set to DefaultValue for each component. #ifndef __vtkvmtkSurfaceProjectCellArray_h #define __vtkvmtkSurfaceProjectCellArray_h #include "vtkPolyDataAlgorithm.h" #include "vtkPolyData.h" #include "vtkvmtkWin32Header.h" class vtkPolyData; class VTK_VMTK_CONTRIB_EXPORT vtkvmtkSurfaceProjectCellArray : public vtkPolyDataAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkSurfaceProjectCellArray,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkSurfaceProjectCellArray *New(); // Description: // Set/Get the reference surface to compute distance from. vtkSetObjectMacro(ReferenceSurface,vtkPolyData); vtkGetObjectMacro(ReferenceSurface,vtkPolyData); //Set/Get the name of the array to project vtkSetStringMacro(ProjectedArrayName); vtkGetStringMacro(ProjectedArrayName); //Set/Get the distance tolerance vtkSetMacro(DistanceTolerance, double); vtkGetMacro(DistanceTolerance, double); //Set/Get the default value vtkSetMacro(DefaultValue, double); vtkGetMacro(DefaultValue, double); protected: vtkvmtkSurfaceProjectCellArray(); ~vtkvmtkSurfaceProjectCellArray(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkPolyData *ReferenceSurface; char *ProjectedArrayName; double DistanceTolerance; double DefaultValue; private: vtkvmtkSurfaceProjectCellArray(const vtkvmtkSurfaceProjectCellArray&); // Not implemented. void operator=(const vtkvmtkSurfaceProjectCellArray&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataSampleFunction.cxx0000664000175000017500000000615011757446472022757 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataSampleFunction.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkPolyDataSampleFunction.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkIOStream.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataSampleFunction, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataSampleFunction); vtkCxxSetObjectMacro(vtkvmtkPolyDataSampleFunction,ImplicitFunction,vtkImplicitFunction); vtkvmtkPolyDataSampleFunction::vtkvmtkPolyDataSampleFunction() { this->SampleArrayName = NULL; this->ImplicitFunction = NULL; } vtkvmtkPolyDataSampleFunction::~vtkvmtkPolyDataSampleFunction() { if (this->SampleArrayName) { delete[] this->SampleArrayName; this->SampleArrayName = NULL; } this->ImplicitFunction = NULL; } int vtkvmtkPolyDataSampleFunction::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->SampleArrayName) { vtkErrorMacro(<<"DistanceToSpheresArrayName not set."); return 1; } if (!this->ImplicitFunction) { vtkErrorMacro(<<"ImplicitFunction not set."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); output->DeepCopy(input); vtkDataArray* sampleArray = output->GetPointData()->GetArray(this->SampleArrayName); bool createArray = !sampleArray; if (createArray) { sampleArray = vtkDoubleArray::New(); sampleArray->SetName(this->SampleArrayName); sampleArray->SetNumberOfComponents(1); sampleArray->SetNumberOfTuples(numberOfInputPoints); sampleArray->FillComponent(0, 0); output->GetPointData()->AddArray(sampleArray); } double point[3]; for (int i=0; iGetPoint(i,point); sampleArray->SetComponent(i,0,this->ImplicitFunction->EvaluateFunction(point)); } if (createArray) sampleArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataSampleFunction.h0000664000175000017500000000400311757446472022377 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataSampleFunction.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkPolyDataSampleFunction - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataSampleFunction_h #define __vtkvmtkPolyDataSampleFunction_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" #include "vtkImplicitFunction.h" class VTK_VMTK_CONTRIB_EXPORT vtkvmtkPolyDataSampleFunction : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataSampleFunction* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataSampleFunction,vtkPolyDataAlgorithm); // Description: // Specify the implicit function to use to generate data. virtual void SetImplicitFunction(vtkImplicitFunction*); vtkGetObjectMacro(ImplicitFunction,vtkImplicitFunction); vtkSetStringMacro(SampleArrayName); vtkGetStringMacro(SampleArrayName); protected: vtkvmtkPolyDataSampleFunction(); ~vtkvmtkPolyDataSampleFunction(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* SampleArrayName; vtkImplicitFunction *ImplicitFunction; private: vtkvmtkPolyDataSampleFunction(const vtkvmtkPolyDataSampleFunction&); // Not implemented. void operator=(const vtkvmtkPolyDataSampleFunction&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkCenterlineInterpolateArray.cxx0000664000175000017500000001744211757446472023676 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCenterlineInterpolateArray.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkCenterlineInterpolateArray.h" #include #include #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 "vtkvmtkConstants.h" #include "vtkvmtkCenterlineAttributesFilter.h" vtkCxxRevisionMacro(vtkvmtkCenterlineInterpolateArray, "$Revision: 1.3 $"); 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; iGetNumberOfComponents(); i++) { interpolatedArray->FillComponent(i, this->DefaultValue); } output->GetPointData()->AddArray(interpolatedArray); } int numberOfComponents = vtkstd::min(interpolatedArray->GetNumberOfComponents(),this->Values->GetNumberOfComponents()); //Compute abscissas for the centerlines vtkvmtkCenterlineAttributesFilter *attribFilter = vtkvmtkCenterlineAttributesFilter::New(); attribFilter->SetInput(input); 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; iValuesIds->GetNumberOfIds(); i++) { hasValueArray->SetValue(this->ValuesIds->GetId(i),true); for (int j=0; jSetComponent(this->ValuesIds->GetId(i),j,this->Values->GetComponent(i,j)); } } int numberOfInputCells = input->GetNumberOfCells(); for (int i=0; iGetCell(i)); if (!polyLine) { continue; } int numberOfLinePoints = polyLine->GetNumberOfPoints(); bool foundValue = false; int startInd = 0; //Find the first point having a value while ((startIndGetValue(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--; vtkstd::vector startVal(numberOfComponents); for (int j=0; jGetComponent(polyLine->GetPointId(startInd),j); } double startAbs = abscissaArray->GetComponent(polyLine->GetPointId(startInd),0); for (int j=0; jSetComponent(polyLine->GetPointId(j),k,startVal[k]); } hasValueArray->SetValue(polyLine->GetPointId(j),true); } int endInd = startInd + 1; foundValue = false; while (endIndGetValue(polyLine->GetPointId(endInd)); if (foundValue) { //Interpolate between the start and end values vtkstd::vector endVal(numberOfComponents); for (int j=0; jGetComponent(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;jGetComponent(polyLine->GetPointId(j),0); for (int k=0; kSetComponent(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; jSetComponent(polyLine->GetPointId(j),k,startVal[k]); } hasValueArray->SetValue(polyLine->GetPointId(j),true); } } if (createArray) interpolatedArray->Delete(); attribFilter->Delete(); hasValueArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkcontrib.py0000664000175000017500000000041311757446472017654 0ustar lucaluca""" This module loads all the classes from the contrib library into its namespace. This is a required module.""" import os import vtk import vtkvmtk if os.name == 'posix': from libvtkvmtkContribPython import * else: from vtkvmtkContribPython import * vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkDolfinWriter2.h0000664000175000017500000000537511757446472020521 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDolfinWriter2.h,v $ Language: C++ Date: $Date: 2006/04/06 16:47:47 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkDolfinWriter2 - // .SECTION Description // Slightly modified version of vtkvmtkDolfinWriter // Modifications include bug fixes, and a new region indicators // array which corresponds to the different cell entity Ids // of the tetrahedra. // .SECTION See Also #ifndef __vtkvmtkDolfinWriter2_h #define __vtkvmtkDolfinWriter2_h #include "vtkvmtkWin32Header.h" #include "vtkUnstructuredGridWriter.h" class vtkCell; class vtkIdList; class VTK_VMTK_CONTRIB_EXPORT vtkvmtkDolfinWriter2 : public vtkUnstructuredGridWriter { public: static vtkvmtkDolfinWriter2 *New(); vtkTypeRevisionMacro(vtkvmtkDolfinWriter2,vtkUnstructuredGridWriter); void PrintSelf(ostream& os, vtkIndent indent); vtkSetStringMacro(CellEntityIdsArrayName); vtkGetStringMacro(CellEntityIdsArrayName); vtkSetMacro(CellEntityIdsOffset,int); vtkGetMacro(CellEntityIdsOffset,int); protected: vtkvmtkDolfinWriter2(); ~vtkvmtkDolfinWriter2(); void WriteData(); static void GetDolfinConnectivity(int cellType, vtkIdList* dolfinConnectivity); static void GetDolfinFaceOrder(int cellType, vtkIdList* dolfinFaceOrder); //Description: //Get the connectivity for a specific cell. The point ids are sorted in increasing order static void GetDolfinCellConnectivity(vtkCell *cell, vtkIdList* dolfinConnectivity); //Description: //Get the face order for a specific cell static void GetDolfinCellFaceOrder(vtkCell *cell, vtkIdList* dolfinFaceOrder); char* CellEntityIdsArrayName; int CellEntityIdsOffset; private: vtkvmtkDolfinWriter2(const vtkvmtkDolfinWriter2&); // Not implemented. void operator=(const vtkvmtkDolfinWriter2&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyDataDijkstraDistanceToPoints.h0000664000175000017500000000474111757446472024407 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDijkstraDistanceToPoints.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkPolyDataDijkstraDistanceToPoints - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataDijkstraDistanceToPoints_h #define __vtkvmtkPolyDataDijkstraDistanceToPoints_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkComputationalGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #include "vtkPolyData.h" #include "vtkIdList.h" class VTK_VMTK_CONTRIB_EXPORT vtkvmtkPolyDataDijkstraDistanceToPoints : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataDijkstraDistanceToPoints* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataDijkstraDistanceToPoints,vtkPolyDataAlgorithm); vtkSetObjectMacro(SeedIds,vtkIdList); vtkGetObjectMacro(SeedIds,vtkIdList); 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(DijkstraDistanceToPointsArrayName); vtkGetStringMacro(DijkstraDistanceToPointsArrayName); protected: vtkvmtkPolyDataDijkstraDistanceToPoints(); ~vtkvmtkPolyDataDijkstraDistanceToPoints(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* DijkstraDistanceToPointsArrayName; vtkIdList* SeedIds; double DistanceOffset; double DistanceScale; double MinDistance; double MaxDistance; private: vtkvmtkPolyDataDijkstraDistanceToPoints(const vtkvmtkPolyDataDijkstraDistanceToPoints&); // Not implemented. void operator=(const vtkvmtkPolyDataDijkstraDistanceToPoints&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkDolfinWriter2.cxx0000664000175000017500000003053211757446472021065 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDolfinWriter2.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // #include #include "vtkvmtkDolfinWriter2.h" #include "vtkUnstructuredGrid.h" #include "vtkCellType.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkIdTypeArray.h" #include "vtkObjectFactory.h" #include "vtkSortDataArray.h" #include "vtkTetra.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkDolfinWriter2, "$Revision: 1.6 $"); vtkStandardNewMacro(vtkvmtkDolfinWriter2); vtkvmtkDolfinWriter2::vtkvmtkDolfinWriter2() { this->CellEntityIdsArrayName = NULL; this->CellEntityIdsOffset = 0; } vtkvmtkDolfinWriter2::~vtkvmtkDolfinWriter2() { if (this->CellEntityIdsArrayName) { delete[] this->CellEntityIdsArrayName; this->CellEntityIdsArrayName = NULL; } } void vtkvmtkDolfinWriter2::WriteData() { vtkUnstructuredGrid *input= vtkUnstructuredGrid::SafeDownCast(this->GetInput()); if (!this->FileName) { vtkErrorMacro(<<"FileName not set."); return; } ofstream out (this->FileName); if (!out.good()) { vtkErrorMacro(<<"Could not open file for writing."); return; } input->BuildLinks(); int numberOfPoints = input->GetNumberOfPoints(); int numberOfCells = input->GetNumberOfCells(); vtkIdTypeArray* cellEntityIdsArray = NULL; if (this->CellEntityIdsArrayName) { if (input->GetCellData()->GetArray(this->CellEntityIdsArrayName)) { cellEntityIdsArray = vtkIdTypeArray::New(); cellEntityIdsArray->DeepCopy(input->GetCellData()->GetArray(this->CellEntityIdsArrayName)); } else { vtkErrorMacro(<<"BoundaryDataArray with name specified does not exist"); } } vtkIdTypeArray* tetraCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TETRA,tetraCellIdArray); int numberOfTetras = tetraCellIdArray->GetNumberOfTuples(); out << "" << endl << endl; out << "" << endl; out << " " << endl; out << " " << endl; int i; double point[3]; for (i=0; iGetPoint(i,point); out << " " <" << endl; out << " " << endl; vtkIdList* dolfinConnectivity = vtkIdList::New(); // this->GetDolfinConnectivity(VTK_TETRA,dolfinConnectivity); vtkIdList* volumeCellIdMap = vtkIdList::New(); volumeCellIdMap->SetNumberOfIds(numberOfCells); int numberOfCellPoints = 4; int k; for (i=0; iGetValue(i); volumeCellIdMap->SetId(tetraCellId,i); vtkCell* tetra = input->GetCell(tetraCellId); this->GetDolfinCellConnectivity(tetra,dolfinConnectivity); vtkIdList* cellPointIds = input->GetCell(tetraCellId)->GetPointIds(); out << " GetId(dolfinConnectivity->GetId(k)) << "\" "; } out << "/>" << endl; } out << " " << endl; if (cellEntityIdsArray) { out << " " << endl; //Set the id of the tetrahedra out << " " << endl; for (i=0; iGetValue(i); out << " GetValue(tetraCellId) + this->CellEntityIdsOffset << "\" "; out << "/>" << endl; } out << " " << endl; vtkIdTypeArray* triangleCellIdArray = vtkIdTypeArray::New(); input->GetIdsOfCellsOfType(VTK_TRIANGLE,triangleCellIdArray); int numberOfTriangles = triangleCellIdArray->GetNumberOfTuples(); vtkIdList* boundaryFaceCells = vtkIdList::New(); // boundaryFaceCells->SetNumberOfIds(numberOfTriangles); vtkIdList* boundaryFaceIds = vtkIdList::New(); // boundaryFaceIds->SetNumberOfIds(numberOfTriangles); vtkIdList* boundaryFaceIndicators = vtkIdList::New(); vtkIdType triangleCellId; for (i=0; iGetValue(i); vtkIdList* faceCellPoints = vtkIdList::New(); input->GetCellPoints(triangleCellId,faceCellPoints); vtkIdList* cellIds = vtkIdList::New(); input->GetCellNeighbors(triangleCellId,faceCellPoints,cellIds); vtkIdType nNeighbors = cellIds->GetNumberOfIds(); for (int j=0; jGetId(j); vtkCell* cell = input->GetCell(cellId); int cellType = cell->GetCellType(); if (cellType != VTK_TETRA) { vtkErrorMacro(<<"Volume cell adjacent to triangle is not tetrahedron (volume cell id: "<GetNumberOfFaces(); vtkIdType faceId = -1; int k; for (k=0; kGetFace(k); vtkIdList* matchingPointIds = vtkIdList::New(); matchingPointIds->DeepCopy(face->GetPointIds()); matchingPointIds->IntersectWith(*faceCellPoints); int numberOfNonMatching = face->GetNumberOfPoints() - matchingPointIds->GetNumberOfIds(); matchingPointIds->Delete(); if (numberOfNonMatching==0) { faceId = k; break; } } vtkIdList* dolfinFaceOrder = vtkIdList::New(); // this->GetDolfinFaceOrder(cellType,dolfinFaceOrder); this->GetDolfinCellFaceOrder(cell,dolfinFaceOrder); vtkIdType dolfinFaceId = dolfinFaceOrder->GetId(faceId); dolfinFaceOrder->Delete(); boundaryFaceCells->InsertNextId(volumeCellIdMap->GetId(cellId)); boundaryFaceIds->InsertNextId(dolfinFaceId); boundaryFaceIndicators->InsertNextId(cellEntityIdsArray->GetValue(triangleCellId) + this->CellEntityIdsOffset); } faceCellPoints->Delete(); cellIds->Delete(); } vtkIdType numberOfBoundaryFacets = boundaryFaceCells->GetNumberOfIds(); out << " " << endl; for (i=0; iGetId(i) << "\" "; out << "/>" << endl; } out << " " << endl; out << " " << endl; for (i=0; iGetId(i) << "\" "; out << "/>" << endl; } out << " " << endl; out << " " << endl; for (i=0; iGetId(i) << "\" "; out << "/>" << endl; } out << " " << endl; out << " " << endl; triangleCellIdArray->Delete(); boundaryFaceCells->Delete(); boundaryFaceIds->Delete(); boundaryFaceIndicators->Delete(); } out << " " << endl; out << "" << endl; tetraCellIdArray->Delete(); dolfinConnectivity->Delete(); volumeCellIdMap->Delete(); if (cellEntityIdsArray) { cellEntityIdsArray->Delete(); } } void vtkvmtkDolfinWriter2::GetDolfinConnectivity(int cellType, vtkIdList* dolfinConnectivity) { dolfinConnectivity->Initialize(); switch(cellType) { case VTK_TETRA: dolfinConnectivity->SetNumberOfIds(4); dolfinConnectivity->SetId(0,0); dolfinConnectivity->SetId(1,1); dolfinConnectivity->SetId(2,2); dolfinConnectivity->SetId(3,3); break; default: cerr<<"Element type not currently supported in dolfin. Skipping element for connectivity."<Initialize(); switch(cellType) { case VTK_TETRA: dolfinFaceOrder->SetNumberOfIds(4); dolfinFaceOrder->SetId(0,2); dolfinFaceOrder->SetId(1,0); dolfinFaceOrder->SetId(2,1); dolfinFaceOrder->SetId(3,3); break; default: cerr<<"Element type not currently supported in dolfin. Skipping element for face ordering."<Initialize(); int cellType = cell->GetCellType(); vtkIdList* pointIds = vtkIdList::New(); switch(cellType) { case VTK_TETRA: pointIds->DeepCopy(cell->GetPointIds()); dolfinConnectivity->SetNumberOfIds(4); dolfinConnectivity->SetId(0,0); dolfinConnectivity->SetId(1,1); dolfinConnectivity->SetId(2,2); dolfinConnectivity->SetId(3,3); vtkSortDataArray::Sort(pointIds,dolfinConnectivity); break; default: cerr<<"Element type not currently supported in dolfin. Skipping element for connectivity."<Delete(); } void vtkvmtkDolfinWriter2::GetDolfinCellFaceOrder(vtkCell* cell, vtkIdList *dolfinFaceOrder) { dolfinFaceOrder->Initialize(); int cellType = cell->GetCellType(); vtkIdList* dolfinConnectivity = vtkIdList::New(); GetDolfinCellConnectivity(cell,dolfinConnectivity); vtkIdList* inverseDolfinConnectivity = vtkIdList::New(); inverseDolfinConnectivity->SetNumberOfIds(dolfinConnectivity->GetNumberOfIds()); for (int i=0; iGetNumberOfIds(); i++) { inverseDolfinConnectivity->SetId(dolfinConnectivity->GetId(i),i); } switch(cellType) { case VTK_TETRA: dolfinFaceOrder->SetNumberOfIds(4); for (int i=0; i<4; i++) { int* faceArray = vtkTetra::GetFaceArray(i); for (int j=0; j<4;j++) { bool inFaceArray = false; for (int k=0;k<3;k++) { if (inverseDolfinConnectivity->GetId(faceArray[k])==j) { inFaceArray = true; } } if (!inFaceArray) { dolfinFaceOrder->SetId(i,j); break; } } } break; default: cerr<<"Element type not currently supported in dolfin. Skipping element for face ordering."<Delete(); } void vtkvmtkDolfinWriter2::PrintSelf(ostream& os, vtkIndent indent) { vtkUnstructuredGridWriter::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkSurfaceProjectCellArray.cxx0000664000175000017500000001147311757446472023114 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSurfaceProjectCellArray.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkSurfaceProjectCellArray.h" #include "vtkCellLocator.h" #include "vtkDoubleArray.h" #include "vtkGenericCell.h" #include "vtkPolyData.h" #include "vtkCellData.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkSurfaceProjectCellArray, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkSurfaceProjectCellArray); vtkvmtkSurfaceProjectCellArray::vtkvmtkSurfaceProjectCellArray() { this->ReferenceSurface = NULL; this->ProjectedArrayName = NULL; this->DistanceTolerance = VTK_VMTK_LARGE_DOUBLE; this->DefaultValue = 0.; } vtkvmtkSurfaceProjectCellArray::~vtkvmtkSurfaceProjectCellArray() { if (this->ReferenceSurface) { this->ReferenceSurface->Delete(); this->ReferenceSurface = NULL; } if (this->ProjectedArrayName) { delete[] this->ProjectedArrayName; this->ProjectedArrayName = NULL; } } int vtkvmtkSurfaceProjectCellArray::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())); vtkCellLocator *locator; vtkGenericCell *genericCell; if (!this->ReferenceSurface) { vtkErrorMacro(<<"No reference surface!"); return 1; } vtkDataArray *referenceArray = this->ReferenceSurface->GetCellData()->GetArray(this->ProjectedArrayName); if (!referenceArray) { vtkErrorMacro(<<"No reference array!"); return 1; } int numberOfCells = input->GetNumberOfCells(); output->DeepCopy(input); vtkDataArray *projectedArray = output->GetCellData()->GetArray(this->ProjectedArrayName); if (!projectedArray) { projectedArray = vtkDoubleArray::New(); projectedArray->SetName(this->ProjectedArrayName); projectedArray->SetNumberOfTuples(numberOfCells); projectedArray->SetNumberOfComponents(referenceArray->GetNumberOfComponents()); output->GetCellData()->AddArray(projectedArray); } int numberOfComponents = vtkstd::min(referenceArray->GetNumberOfComponents(), projectedArray->GetNumberOfComponents()); for (int i=0; iFillComponent(i, DefaultValue); } this->ReferenceSurface->BuildCells(); locator = vtkCellLocator::New(); genericCell = vtkGenericCell::New(); locator->SetDataSet(this->ReferenceSurface); locator->BuildLocator(); vtkIdList *cellPtsIds = vtkIdList::New(); double point[3], closestPoint[3]; double distance2; double distanceTolerance2 = this->DistanceTolerance*this->DistanceTolerance; vtkIdType cellId; int subId; for (int i=0; iGetCellPoints(i,cellPtsIds); bool skipCell = false; double minDistance = VTK_VMTK_LARGE_DOUBLE; vtkIdType minId = 0; //Find the cell with the smallest minimum distance to the vertices for (int j=0; jGetNumberOfIds(); j++) { input->GetPoint(cellPtsIds->GetId(j), point); locator->FindClosestPoint(point,closestPoint,genericCell,cellId,subId,distance2); if (distance2>distanceTolerance2) { skipCell = true; break; } if ((j==0) || (distance2 < minDistance)) { minDistance = distance2; minId = cellId; } } if (!skipCell) { for (int j=0; jSetComponent(i,j,referenceArray->GetComponent(minId,j)); } } } locator->Delete(); genericCell->Delete(); cellPtsIds->Delete(); return 1; } void vtkvmtkSurfaceProjectCellArray::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkCellDimensionFilter.h0000664000175000017500000000471111757446472021713 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkCellDimensionFilter.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ // .NAME vtkvmtkCellDimensionFilter - ... // .SECTION Description // Threshold all cells of a given dimension, output to an unstructured grid #ifndef __vtkvmtkCellDimensionFilter_h #define __vtkvmtkCellDimensionFilter_h #include "vtkUnstructuredGridAlgorithm.h" #include "vtkvmtkWin32Header.h" class vtkUnstructuredGrid; class vtkThreshold; class VTK_VMTK_CONTRIB_EXPORT vtkvmtkCellDimensionFilter : public vtkUnstructuredGridAlgorithm { public: vtkTypeRevisionMacro(vtkvmtkCellDimensionFilter,vtkUnstructuredGridAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); static vtkvmtkCellDimensionFilter* New(); // Description: // Criterion is cells whose dimension is less or equal to lower threshold. void ThresholdByLower(int lower); // Description: // Criterion is cells whose dimension is greater or equal to upper threshold. void ThresholdByUpper(int upper); // Description: // Criterion is cells whose dimension is between lower and upper thresholds // (inclusive of the end values). void ThresholdBetween(int lower, int upper); // Description: // Get the Upper and Lower thresholds. virtual int GetUpperThreshold(); virtual int GetLowerThreshold(); protected: vtkvmtkCellDimensionFilter(); ~vtkvmtkCellDimensionFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); virtual int FillInputPortInformation(int port, vtkInformation *info); vtkThreshold *Threshold; private: vtkvmtkCellDimensionFilter(const vtkvmtkCellDimensionFilter&); // Not implemented. void operator=(const vtkvmtkCellDimensionFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkPolyBallLine2.cxx0000664000175000017500000001665611757446472021016 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyBallLine2.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ #include "vtkvmtkPolyBallLine2.h" #include "vtkvmtkConstants.h" #include "vtkPointData.h" #include "vtkPolyLine.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyBallLine2, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyBallLine2); vtkvmtkPolyBallLine2::vtkvmtkPolyBallLine2() { this->Input = NULL; this->InputCellIds = NULL; this->InputCellId = -1; this->PolyBallRadiusArrayName = NULL; this->UseRadiusInformation = 1; this->LocalInput = NULL; this->TriangulatedInput = NULL; this->Triangulator = vtkTriangleFilter::New(); this->Triangulator->PassLinesOn(); this->Locator = vtkCellLocator::New(); this->ShouldBuildLocator = true; this->LocatorMTime = 0; } vtkvmtkPolyBallLine2::~vtkvmtkPolyBallLine2() { if (this->LocalInput && (this->LocalInput != this->Input)) { this->LocalInput->Delete(); this->LocalInput = NULL; } if (this->Input) { this->Input->Delete(); this->Input = NULL; } if (this->InputCellIds) { this->InputCellIds->Delete(); this->InputCellIds = NULL; } if (this->PolyBallRadiusArrayName) { delete[] this->PolyBallRadiusArrayName; this->PolyBallRadiusArrayName = NULL; } if (this->Triangulator) { this->Triangulator->Delete(); this->Triangulator = NULL; } if (this->Locator) { this->Locator->Delete(); this->Locator = NULL; } } void vtkvmtkPolyBallLine2::SetInput(vtkPolyData *inp) { if (this->LocalInput == this->Input) { this->LocalInput = NULL; } //The locator needs to be rebuilt this->ShouldBuildLocator = true; vtkSetObjectBodyMacro(Input,vtkPolyData,inp); } void vtkvmtkPolyBallLine2::SetInputCellIds(vtkIdList *cellIds) { //The locator needs to be rebuilt this->ShouldBuildLocator = true; vtkSetObjectBodyMacro(InputCellIds,vtkIdList,cellIds); } void vtkvmtkPolyBallLine2::SetInputCellId(vtkIdType cellId) { vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting InputCellId to " << cellId); if (this->InputCellId != cellId) { //The locator needs to be rebuilt this->ShouldBuildLocator = true; this->InputCellId = cellId; this->Modified(); } } double vtkvmtkPolyBallLine2::ComplexDot(double x[4], double y[4]) { return x[0]*y[0] + x[1]*y[1] + x[2]*y[2] - x[3]*y[3]; } double vtkvmtkPolyBallLine2::EvaluateFunction(double x[3]) { if (!this->Input) { vtkErrorMacro(<<"No Input specified!"); return 0.0; } if (this->Input->GetNumberOfPoints()==0) { vtkWarningMacro(<<"Empty Input specified!"); return 0.0; } if (this->UseRadiusInformation) { if (!this->PolyBallRadiusArrayName) { vtkErrorMacro(<<"No PolyBallRadiusArrayName specified!"); return 0.0; } } this->ShouldBuildLocator = this->ShouldBuildLocator || (this->LocatorMTime != this->Input->GetMTime()); //Rebuild the locator if needed if (this->ShouldBuildLocator) { this->BuildLocator(); } //Find the cell closest to x double dist2; double closPt[3]; vtkIdType closCellId; int subId; this->Locator->FindClosestPoint(x,closPt,closCellId,subId,dist2); double value; if (this->UseRadiusInformation) { vtkDataArray *polyballRadiusArray = this->TriangulatedInput->GetPointData()->GetArray(this->PolyBallRadiusArrayName); if (polyballRadiusArray==NULL) { vtkErrorMacro(<<"PolyBallRadiusArray with name specified does not exist!"); return 0.0; } vtkIdType cellType = this->TriangulatedInput->GetCellType(closCellId); if (cellType != VTK_LINE) { vtkErrorMacro(<<"Error wrong cell type in polyline!"); return 0.0; } vtkIdList *linePointsIds = vtkIdList::New(); this->TriangulatedInput->GetCellPoints(closCellId, linePointsIds); double *point0; double *point1; double vector0[3], vector1[3]; double radius0, radius1; point0 = this->TriangulatedInput->GetPoint(linePointsIds->GetId(0)); point1 = this->TriangulatedInput->GetPoint(linePointsIds->GetId(1)); for (int i=0;i<3;i++) { vector0[i] = point1[i] - point0[i]; vector1[i] = closPt[i] - point0[i]; } double num = vtkMath::Dot(vector0,vector1); double den = vtkMath::Dot(vector0,vector0); double t=0; //t should be between 0 and 1 since we took the closest point if (den!=0.) { t = num/den; } radius0 = polyballRadiusArray->GetComponent(linePointsIds->GetId(0),0); radius1 = polyballRadiusArray->GetComponent(linePointsIds->GetId(1),0); double radius = radius0 + t*(radius1 - radius0); value = sqrt(dist2) - radius; linePointsIds->Delete(); } else { value = sqrt(dist2); } return value; } void vtkvmtkPolyBallLine2::EvaluateGradient(double x[3], double n[3]) { vtkWarningMacro("Poly ball gradient computation not yet implemented!"); // TODO } void vtkvmtkPolyBallLine2::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } void vtkvmtkPolyBallLine2::BuildLocator() { if (!this->Input) { vtkErrorMacro(<<"No Input specified!"); return; } if (this->Input->GetNumberOfPoints()==0) { vtkWarningMacro(<<"Empty Input specified!"); return; } this->LocatorMTime = this->Input->GetMTime(); if (this->LocalInput && (this->LocalInput != this->Input)) { this->LocalInput->Delete(); } //If only part of the cells are used, copy these cells to LocalInput if (this->InputCellIds || this->InputCellId) { this->LocalInput = vtkPolyData::New(); this->LocalInput->DeepCopy(this->Input); if (this->InputCellIds) { //Remove the cells whose id is not the list for (int i=0; iLocalInput->GetNumberOfCells(); i++) { if (!this->InputCellIds->IsId(i)) { this->LocalInput->DeleteCell(i); } } } else if (this->InputCellId != -1) { //Remove the cells whose is not InputCellId for (int i=0; iLocalInput->GetNumberOfCells(); i++) { if (i!=this->InputCellId) { this->LocalInput->DeleteCell(i); } } } } else { this->LocalInput = this->Input; } //Triangulate the input for improved performance this->Triangulator->SetInput(this->LocalInput); this->Triangulator->Update(); this->TriangulatedInput = this->Triangulator->GetOutput(); //Build the locator this->Locator->SetDataSet(this->TriangulatedInput); this->Locator->BuildLocator(); this->ShouldBuildLocator = false; }vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkBoundaryLayerGenerator2.cxx0000664000175000017500000004560711757446472023115 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryLayerGenerator2.cxx,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan Kalkulo AS Simula Research Laboratory =========================================================================*/ //TODO: Bug in WarpPoints in parent class? #include "vtkvmtkBoundaryLayerGenerator2.h" #include "vtkvmtkConstants.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkCellArray.h" #include "vtkIntArray.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkCellData.h" #include "vtkGeometryFilter.h" #include "vtkOrderedTriangulator.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" vtkCxxRevisionMacro(vtkvmtkBoundaryLayerGenerator2, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkBoundaryLayerGenerator2); vtkvmtkBoundaryLayerGenerator2::vtkvmtkBoundaryLayerGenerator2() { this->CellEntityIdsArrayName = NULL; this->OpenProfilesIdsArrayName = NULL; this->IncludeExtrudedOpenProfilesCells = 0; this->IncludeExtrudedSurfaceCells = 0; this->IncludeOriginalSurfaceCells = 0; this->LayerEntityId = 0; this->SurfaceEntityId = 1; this->OpenProfilesEntityId = 2; this->Triangulator = vtkOrderedTriangulator::New(); } vtkvmtkBoundaryLayerGenerator2::~vtkvmtkBoundaryLayerGenerator2() { if (this->CellEntityIdsArrayName) { delete[] this->CellEntityIdsArrayName; this->CellEntityIdsArrayName = NULL; } if (this->OpenProfilesIdsArrayName) { delete[] this->OpenProfilesIdsArrayName; this->OpenProfilesIdsArrayName = NULL; } this->Triangulator->Delete(); } int vtkvmtkBoundaryLayerGenerator2::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(); vtkIdType numberOfInputPoints = inputPoints->GetNumberOfPoints(); vtkIdType numberOfInputCells = input->GetNumberOfCells(); if (!this->WarpVectorsArrayName) { vtkErrorMacro("WarpVectors 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); } vtkPoints* outputPoints = vtkPoints::New(); vtkPoints* warpedPoints = vtkPoints::New(); vtkCellArray* boundaryLayerCellArray = vtkCellArray::New(); vtkIdList* boundaryLayerCellTypes = vtkIdList::New(); vtkIntArray *cellEntityIdsArray = NULL; if ((this->CellEntityIdsArrayName) && (strcmp(this->CellEntityIdsArrayName,"") != 0)) { cellEntityIdsArray = vtkIntArray::New(); cellEntityIdsArray->SetName(this->CellEntityIdsArrayName); cellEntityIdsArray->SetNumberOfComponents(1); } //Keep track of the id to use int currentSurfaceEntityId = this->SurfaceEntityId; 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; } outputPoints->SetNumberOfPoints(numberOfInputPoints + numberOfLayerPoints * this->NumberOfSubLayers); double point[3]; int i; for (i=0; iGetPoint(i,point); outputPoints->SetPoint(i,point); } vtkIdType npts, *pts; vtkIdType *surfacePts; if (this->IncludeSurfaceCells || this->IncludeOriginalSurfaceCells) { for (i=0; iGetCellPoints(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); if (cellEntityIdsArray) { cellEntityIdsArray->InsertNextValue(currentSurfaceEntityId); } delete[] surfacePts; } //Switch to next surface entity currentSurfaceEntityId++; } if (this->InnerSurface) { this->InnerSurface->Delete(); this->InnerSurface = NULL; } this->InnerSurface = vtkUnstructuredGrid::New(); this->InnerSurface->DeepCopy(input); vtkPoints* innerSurfacePoints = vtkPoints::New(); this->WarpPoints(inputPoints,innerSurfacePoints,this->NumberOfSubLayers-1,warpQuadratic); this->InnerSurface->GetPoints()->DeepCopy(innerSurfacePoints); //Get the ids of the open profiles if necessary vtkDataArray *openProfilesIdsArray = NULL; bool allocateArray = false; if (this->IncludeSurfaceCells || this->IncludeExtrudedOpenProfilesCells) { //Find or build the ids of the open profiles //TODO: Check that the open profiles ids are consistent if (this->OpenProfilesIdsArrayName) { openProfilesIdsArray = input->GetPointData()->GetArray(this->OpenProfilesIdsArrayName); } allocateArray = (openProfilesIdsArray == NULL); if (allocateArray) { //The open profiles ids have to be created openProfilesIdsArray = vtkIntArray::New(); openProfilesIdsArray->SetName("OpenProfilesIds"); openProfilesIdsArray->SetNumberOfComponents(1); openProfilesIdsArray->SetNumberOfTuples(numberOfInputPoints); openProfilesIdsArray->FillComponent(0, -1); //First convert the unstructured grid to poly data vtkGeometryFilter *meshToSurface = vtkGeometryFilter::New(); meshToSurface->SetInput(input); meshToSurface->MergingOff(); meshToSurface->Update(); //Extract the open profiles vtkvmtkPolyDataBoundaryExtractor *openProfilesExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); openProfilesExtractor->SetInput(meshToSurface->GetOutput()); openProfilesExtractor->Update(); //Update the openProfilesIdsArray vtkCellArray *openProfiles = openProfilesExtractor->GetOutput()->GetLines(); vtkDataArray *openProfilesScalars = openProfilesExtractor->GetOutput()->GetPointData()->GetScalars(); vtkIdType npts = 0; vtkIdType *pts = NULL; int profileId; for (profileId=0, openProfiles->InitTraversal(); openProfiles->GetNextCell(npts,pts); profileId++) { for (int i=0;iSetComponent(openProfilesScalars->GetComponent(pts[i],0),0,profileId); } } openProfilesExtractor->Delete(); meshToSurface->Delete(); } } //Add the volumetric elements and the open profiles extensions if necessary boundaryLayerCellArray->InitTraversal(); int k; for (k=0; kNumberOfSubLayers; k++) { warpedPoints->Initialize(); this->WarpPoints(inputPoints,warpedPoints,k,warpQuadratic); for (i=0; iGetPoint(i,point); outputPoints->SetPoint(i + numberOfInputPoints + k*numberOfLayerPoints,point); } vtkIdType prismNPts, *prismPts; vtkIdType nTetraPts = 0; vtkIdType *tetraPts = NULL; for (i=0; iGetCellPoints(i,npts,pts); cellType = input->GetCellType(i); if (cellType == VTK_TRIANGLE || cellType == VTK_QUAD) { prismNPts = npts * 2; prismPts = new vtkIdType[prismNPts]; int j; for (j=0; jTriangulator->InitTriangulation(0.0,1.0, 0.0,1.0, 0.0,1.0, prismNPts); double prismPt[3]; double *p; for (p=pCoords, j=0; jGetPoint(j, prismPt); this->Triangulator->InsertPoint(prismPts[j], prismPt, p, 0); } this->Triangulator->TemplateTriangulate(prismType, prismNPts, prismNEdges); //Go to the end of the list while (boundaryLayerCellArray->GetNextCell(nTetraPts,tetraPts)); //Location from which the tetras will be inserted vtkIdType tetraStartLoc = boundaryLayerCellArray->GetTraversalLocation(); //Insert the new tetras vtkIdType numTets = this->Triangulator->AddTetras(0,boundaryLayerCellArray); for (j=0; jInsertNextId(VTK_TETRA); if (cellEntityIdsArray) { cellEntityIdsArray->InsertNextValue(this->LayerEntityId); } } //Add the extruded open profiles if (openProfilesIdsArray) { for (j=0;jGetComponent(pts[j],0) != -1) && (openProfilesIdsArray->GetComponent(pts[(j+1)%npts],0) != -1)) { //The points forming the extruded open profile vtkIdList *openProfilePts = vtkIdList::New(); openProfilePts->InsertNextId(prismPts[j]); openProfilePts->InsertNextId(prismPts[(j+1)%npts]); openProfilePts->InsertNextId(prismPts[j+npts]); openProfilePts->InsertNextId(prismPts[(j+1)%npts + npts]); vtkIdList *tetraPtsList = vtkIdList::New(); //Go through the tetrahedra we just added boundaryLayerCellArray->SetTraversalLocation(tetraStartLoc); for (int k=0; kGetNextCell(nTetraPts,tetraPts); tetraPtsList->Initialize(); for (int l=0; lInsertNextId(tetraPts[l]); } tetraPtsList->IntersectWith(*openProfilePts); //If this tetrahedra has a face on the extruded open profile, include it if (tetraPtsList->GetNumberOfIds() == 3) { boundaryLayerCellArray->InsertNextCell(tetraPtsList); boundaryLayerCellTypes->InsertNextId(VTK_TRIANGLE); if (cellEntityIdsArray) { cellEntityIdsArray->InsertNextValue(this->OpenProfilesEntityId + openProfilesIdsArray->GetComponent(pts[j],0)); } } } tetraPtsList->Delete(); openProfilePts->Delete(); } } } delete[] prismPts; } //FIXME: NOT HANDLED // else if (cellType == VTK_QUADRATIC_TRIANGLE) // { // prismNPts = npts * 3 - 3; // // prismNPts = npts * 3; // prismPts = new vtkIdType[prismNPts]; // // 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; // // // TODO: this creates a 18-noded wedge, which is not supported by VTK, but it works as a 15-node (the last 3 points are ignored). Better solutions? Could put it in as a vtkGenericCell, but harder to identify it afterwards // // prismPts[15] = pts[3] + k*numberOfLayerPoints + numberOfLayerPoints/2; // // prismPts[16] = pts[4] + k*numberOfLayerPoints + numberOfLayerPoints/2; // // prismPts[17] = pts[5] + k*numberOfLayerPoints + numberOfLayerPoints/2; // // boundaryLayerCellArray->InsertNextCell(prismNPts,prismPts); // if (cellEntityIdsArray) cellEntityIdsArray->InsertNextValue(this->LayerEntityId); // delete[] prismPts; // } else { vtkErrorMacro(<<"Unsupported surface element."); return 1; } } } if (allocateArray) { openProfilesIdsArray->Delete(); } if (this->IncludeSurfaceCells || this->IncludeExtrudedSurfaceCells) { for (i=0; iGetCellPoints(i,npts,pts); cellType = input->GetCellType(i); surfacePts = new vtkIdType[npts]; switch(cellType) { case VTK_TRIANGLE: boundaryLayerCellTypes->InsertNextId(VTK_TRIANGLE); surfacePts[0] = pts[0] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[1] = pts[1] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[2] = pts[2] + this->NumberOfSubLayers*numberOfLayerPoints; break; case VTK_QUAD: boundaryLayerCellTypes->InsertNextId(VTK_QUAD); surfacePts[0] = pts[0] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[1] = pts[1] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[2] = pts[2] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[3] = pts[3] + this->NumberOfSubLayers*numberOfLayerPoints; break; case VTK_QUADRATIC_TRIANGLE: boundaryLayerCellTypes->InsertNextId(VTK_QUADRATIC_TRIANGLE); surfacePts[0] = pts[0] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[1] = pts[1] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[2] = pts[2] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[3] = pts[3] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[4] = pts[4] + this->NumberOfSubLayers*numberOfLayerPoints; surfacePts[5] = pts[5] + this->NumberOfSubLayers*numberOfLayerPoints; break; default: vtkErrorMacro(<<"Unsupported surface element."); return 1; break; } boundaryLayerCellArray->InsertNextCell(npts,surfacePts); if (cellEntityIdsArray) cellEntityIdsArray->InsertNextValue(currentSurfaceEntityId); delete[] surfacePts; } } output->SetPoints(outputPoints); int* boundaryLayerCellTypesInt = new int[boundaryLayerCellTypes->GetNumberOfIds()]; for (i=0; iGetNumberOfIds(); i++) { boundaryLayerCellTypesInt[i] = boundaryLayerCellTypes->GetId(i); } output->SetCells(boundaryLayerCellTypesInt,boundaryLayerCellArray); delete[] boundaryLayerCellTypesInt; if (cellEntityIdsArray) { output->GetCellData()->AddArray(cellEntityIdsArray); cellEntityIdsArray->Delete(); } outputPoints->Delete(); warpedPoints->Delete(); boundaryLayerCellArray->Delete(); boundaryLayerCellTypes->Delete(); innerSurfacePoints->Delete(); return 1; } void vtkvmtkBoundaryLayerGenerator2::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/Contrib/vtkvmtkBoundaryLayerGenerator2.h0000664000175000017500000001006511757446472022530 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryLayerGenerator2.h,v $ Language: C++ Date: $$ Version: $$ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 Tangui Morvan 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: vtkTypeRevisionMacro(vtkvmtkBoundaryLayerGenerator2,vtkvmtkBoundaryLayerGenerator); void PrintSelf(ostream& os, vtkIndent indent); 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 *); 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 vmtk-1.0.1/vtkVmtk/Utilities/0000775000175000017500000000000011757446472014570 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/0000775000175000017500000000000011757446472016442 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/tetgen.cxx0000664000175000017500000456567711757446472020512 0ustar lucaluca/////////////////////////////////////////////////////////////////////////////// // // // TetGen // // // // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // // // // Version 1.4 // // September 6, 2009 // // // // Copyright (C) 2002--2009 // // Hang Si // // Research Group: Numerical Mathematics and Scientific Computing // // Weierstrass Institute for Applied Analysis and Stochastics (WIAS) // // Mohrenstr. 39, 10117 Berlin, Germany // // si@wias-berlin.de // // // // TetGen is freely available through the website: http://tetgen.berlios.de. // // It may be copied, modified, and redistributed for non-commercial use. // // Please consult the file LICENSE for the detailed copyright notices. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // tetgen.cxx // // // // The TetGen library and program. // // // /////////////////////////////////////////////////////////////////////////////// #include "tetgen.h" //// io_cxx /////////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // load_node_call() Read a list of points from a file. // // // // It is a support routine for routines: 'load_nodes()', 'load_poly()', and // // 'load_tetmesh()'. 'infile' is the file handle contains the node list. It // // may point to a .node, or .poly or .smesh file. 'markers' indicates each // // node contains an additional marker (integer) or not. 'infilename' is the // // name of the file being read, it is only used in error messages. // // // // The 'firstnumber' (0 or 1) is automatically determined by the number of // // the first index of the first point. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_node_call(FILE* infile, int markers, char* infilename) { char inputline[INPUTLINESIZE]; char *stringptr; REAL x, y, z, attrib; int firstnode, currentmarker; int index, attribindex; int i, j; // Initialize 'pointlist', 'pointattributelist', and 'pointmarkerlist'. pointlist = new REAL[numberofpoints * 3]; if (pointlist == (REAL *) NULL) { terminatetetgen(1); } if (numberofpointattributes > 0) { pointattributelist = new REAL[numberofpoints * numberofpointattributes]; if (pointattributelist == (REAL *) NULL) { terminatetetgen(1); } } if (markers) { pointmarkerlist = new int[numberofpoints]; if (pointmarkerlist == (int *) NULL) { terminatetetgen(1); } } // Read the point section. index = 0; attribindex = 0; for (i = 0; i < numberofpoints; i++) { stringptr = readnumberline(inputline, infile, infilename); if (useindex) { if (i == 0) { firstnode = (int) strtol (stringptr, &stringptr, 0); if ((firstnode == 0) || (firstnode == 1)) { firstnumber = firstnode; } } stringptr = findnextnumber(stringptr); } // if (useindex) if (*stringptr == '\0') { printf("Error: Point %d has no x coordinate.\n", firstnumber + i); break; } x = (REAL) strtod(stringptr, &stringptr); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Point %d has no y coordinate.\n", firstnumber + i); break; } y = (REAL) strtod(stringptr, &stringptr); if (mesh_dim == 3) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Point %d has no z coordinate.\n", firstnumber + i); break; } z = (REAL) strtod(stringptr, &stringptr); } else { z = 0.0; // mesh_dim == 2; } pointlist[index++] = x; pointlist[index++] = y; pointlist[index++] = z; // Read the point attributes. for (j = 0; j < numberofpointattributes; j++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { attrib = 0.0; } else { attrib = (REAL) strtod(stringptr, &stringptr); } pointattributelist[attribindex++] = attrib; } if (markers) { // Read a point marker. stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { currentmarker = 0; } else { currentmarker = (int) strtol (stringptr, &stringptr, 0); } pointmarkerlist[i] = currentmarker; } } if (i < numberofpoints) { // Failed to read points due to some error. delete [] pointlist; pointlist = (REAL *) NULL; if (markers) { delete [] pointmarkerlist; pointmarkerlist = (int *) NULL; } if (numberofpointattributes > 0) { delete [] pointattributelist; pointattributelist = (REAL *) NULL; } numberofpoints = 0; return false; } return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_node() Load a list of points from a .node file. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_node(char* filebasename) { FILE *infile; char innodefilename[FILENAMESIZE]; char inputline[INPUTLINESIZE]; char *stringptr; bool okflag; int markers; // Assembling the actual file names we want to open. strcpy(innodefilename, filebasename); strcat(innodefilename, ".node"); // Try to open a .node file. infile = fopen(innodefilename, "r"); if (infile == (FILE *) NULL) { printf("File I/O Error: Cannot access file %s.\n", innodefilename); return false; } printf("Opening %s.\n", innodefilename); // Read the first line of the file. stringptr = readnumberline(inputline, infile, innodefilename); // Does this file contain an index colume? stringptr = strstr(inputline, "rbox"); if (stringptr == NULL) { // Read number of points, number of dimensions, number of point // attributes, and number of boundary markers. stringptr = inputline; numberofpoints = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { mesh_dim = 3; } else { mesh_dim = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { numberofpointattributes = 0; } else { numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { markers = 0; } else { markers = (int) strtol (stringptr, &stringptr, 0); } } else { // It is a rbox (qhull) input file. stringptr = inputline; // Get the dimension. mesh_dim = (int) strtol (stringptr, &stringptr, 0); // Get the number of points. stringptr = readnumberline(inputline, infile, innodefilename); numberofpoints = (int) strtol (stringptr, &stringptr, 0); // There is no index column. useindex = 0; } // Load the list of nodes. okflag = load_node_call(infile, markers, innodefilename); fclose(infile); return okflag; } /////////////////////////////////////////////////////////////////////////////// // // // load_var() Load constraints applied on facets, segments, and nodes // // from a .var file. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_var(char* filebasename) { FILE *infile; char varfilename[FILENAMESIZE]; char inputline[INPUTLINESIZE]; char *stringptr; int index; int i; // Variant constraints are saved in file "filename.var". strcpy(varfilename, filebasename); strcat(varfilename, ".var"); infile = fopen(varfilename, "r"); if (infile != (FILE *) NULL) { printf("Opening %s.\n", varfilename); } else { // No such file. Ignore it without a message. return false; } // Read the facet constraint section. stringptr = readnumberline(inputline, infile, varfilename); if (*stringptr != '\0') { numberoffacetconstraints = (int) strtol (stringptr, &stringptr, 0); } else { numberoffacetconstraints = 0; } if (numberoffacetconstraints > 0) { // Initialize 'facetconstraintlist'. facetconstraintlist = new REAL[numberoffacetconstraints * 2]; index = 0; for (i = 0; i < numberoffacetconstraints; i++) { stringptr = readnumberline(inputline, infile, varfilename); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: facet constraint %d has no facet marker.\n", firstnumber + i); break; } else { facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: facet constraint %d has no maximum area bound.\n", firstnumber + i); break; } else { facetconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); } } if (i < numberoffacetconstraints) { // This must be caused by an error. fclose(infile); return false; } } // Read the segment constraint section. stringptr = readnumberline(inputline, infile, varfilename); if (*stringptr != '\0') { numberofsegmentconstraints = (int) strtol (stringptr, &stringptr, 0); } else { numberofsegmentconstraints = 0; } if (numberofsegmentconstraints > 0) { // Initialize 'segmentconstraintlist'. segmentconstraintlist = new REAL[numberofsegmentconstraints * 3]; index = 0; for (i = 0; i < numberofsegmentconstraints; i++) { stringptr = readnumberline(inputline, infile, varfilename); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: segment constraint %d has no frist endpoint.\n", firstnumber + i); break; } else { segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: segment constraint %d has no second endpoint.\n", firstnumber + i); break; } else { segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: segment constraint %d has no maximum length bound.\n", firstnumber + i); break; } else { segmentconstraintlist[index++] = (REAL) strtod(stringptr, &stringptr); } } if (i < numberofsegmentconstraints) { // This must be caused by an error. fclose(infile); return false; } } fclose(infile); return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_mtr() Load a size specification map from a .mtr file. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_mtr(char* filebasename) { FILE *infile; char mtrfilename[FILENAMESIZE]; char inputline[INPUTLINESIZE]; char *stringptr; REAL mtr; int mtrindex; int i, j; strcpy(mtrfilename, filebasename); strcat(mtrfilename, ".mtr"); infile = fopen(mtrfilename, "r"); if (infile != (FILE *) NULL) { printf("Opening %s.\n", mtrfilename); } else { // No such file. Return. return false; } // Read number of points, number of columns (1, 3, or 6). stringptr = readnumberline(inputline, infile, mtrfilename); stringptr = findnextnumber(stringptr); // Skip number of points. if (*stringptr != '\0') { numberofpointmtrs = (int) strtol (stringptr, &stringptr, 0); } if (numberofpointmtrs == 0) { // Column number doesn't match. Set a default number (1). numberofpointmtrs = 1; } // Allocate space for pointmtrlist. pointmtrlist = new REAL[numberofpoints * numberofpointmtrs]; if (pointmtrlist == (REAL *) NULL) { terminatetetgen(1); } mtrindex = 0; for (i = 0; i < numberofpoints; i++) { // Read metrics. stringptr = readnumberline(inputline, infile, mtrfilename); for (j = 0; j < numberofpointmtrs; j++) { if (*stringptr == '\0') { printf("Error: Metric %d is missing value #%d in %s.\n", i + firstnumber, j + 1, mtrfilename); terminatetetgen(1); } mtr = (REAL) strtod(stringptr, &stringptr); pointmtrlist[mtrindex++] = mtr; stringptr = findnextnumber(stringptr); } } fclose(infile); return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_poly() Load a PL complex from a .poly or a .smesh file. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_poly(char* filebasename) { FILE *infile, *polyfile; char innodefilename[FILENAMESIZE]; char inpolyfilename[FILENAMESIZE]; char insmeshfilename[FILENAMESIZE]; char inputline[INPUTLINESIZE]; char *stringptr, *infilename; int smesh, markers, currentmarker; int readnodefile, index; int i, j, k; // Assembling the actual file names we want to open. strcpy(innodefilename, filebasename); strcpy(inpolyfilename, filebasename); strcpy(insmeshfilename, filebasename); strcat(innodefilename, ".node"); strcat(inpolyfilename, ".poly"); strcat(insmeshfilename, ".smesh"); // First assume it is a .poly file. smesh = 0; // Try to open a .poly file. polyfile = fopen(inpolyfilename, "r"); if (polyfile == (FILE *) NULL) { // .poly doesn't exist! Try to open a .smesh file. polyfile = fopen(insmeshfilename, "r"); if (polyfile == (FILE *) NULL) { printf("File I/O Error: Cannot access file %s and %s.\n", inpolyfilename, insmeshfilename); return false; } else { printf("Opening %s.\n", insmeshfilename); } smesh = 1; } else { printf("Opening %s.\n", inpolyfilename); } // Initialize the default values. mesh_dim = 3; // Three-dimemsional accoordinates. numberofpointattributes = 0; // no point attribute. markers = 0; // no boundary marker. // Read number of points, number of dimensions, number of point // attributes, and number of boundary markers. stringptr = readnumberline(inputline, polyfile, inpolyfilename); numberofpoints = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { mesh_dim = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { markers = (int) strtol (stringptr, &stringptr, 0); } if (numberofpoints > 0) { readnodefile = 0; if (smesh) { infilename = insmeshfilename; } else { infilename = inpolyfilename; } infile = polyfile; } else { // If the .poly or .smesh file claims there are zero points, that // means the points should be read from a separate .node file. readnodefile = 1; infilename = innodefilename; } if (readnodefile) { // Read the points from the .node file. printf("Opening %s.\n", innodefilename); infile = fopen(innodefilename, "r"); if (infile == (FILE *) NULL) { printf("File I/O Error: Cannot access file %s.\n", innodefilename); return false; } // Initialize the default values. mesh_dim = 3; // Three-dimemsional accoordinates. numberofpointattributes = 0; // no point attribute. markers = 0; // no boundary marker. // Read number of points, number of dimensions, number of point // attributes, and number of boundary markers. stringptr = readnumberline(inputline, infile, innodefilename); numberofpoints = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { mesh_dim = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { markers = (int) strtol (stringptr, &stringptr, 0); } } if ((mesh_dim != 3) && (mesh_dim != 2)) { printf("Input error: TetGen only works for 2D & 3D point sets.\n"); fclose(infile); return false; } if (numberofpoints < (mesh_dim + 1)) { printf("Input error: TetGen needs at least %d points.\n", mesh_dim + 1); fclose(infile); return false; } // Load the list of nodes. if (!load_node_call(infile, markers, infilename)) { fclose(infile); return false; } if (readnodefile) { fclose(infile); } facet *f; polygon *p; if (mesh_dim == 3) { // Read number of facets and number of boundary markers. stringptr = readnumberline(inputline, polyfile, inpolyfilename); numberoffacets = (int) strtol (stringptr, &stringptr, 0); if (numberoffacets <= 0) { // No facet list, return. fclose(polyfile); return true; } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { markers = 0; // no boundary marker. } else { markers = (int) strtol (stringptr, &stringptr, 0); } // Initialize the 'facetlist', 'facetmarkerlist'. facetlist = new facet[numberoffacets]; if (markers == 1) { facetmarkerlist = new int[numberoffacets]; } // Read data into 'facetlist', 'facetmarkerlist'. if (smesh == 0) { // Facets are in .poly file format. for (i = 1; i <= numberoffacets; i++) { f = &(facetlist[i - 1]); init(f); f->numberofholes = 0; currentmarker = 0; // Read number of polygons, number of holes, and a boundary marker. stringptr = readnumberline(inputline, polyfile, inpolyfilename); f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { f->numberofholes = (int) strtol (stringptr, &stringptr, 0); if (markers == 1) { stringptr = findnextnumber(stringptr); if (*stringptr != '\0') { currentmarker = (int) strtol(stringptr, &stringptr, 0); } } } // Initialize facetmarker if it needs. if (markers == 1) { facetmarkerlist[i - 1] = currentmarker; } // Each facet should has at least one polygon. if (f->numberofpolygons <= 0) { printf("Error: Wrong number of polygon in %d facet.\n", i); break; } // Initialize the 'f->polygonlist'. f->polygonlist = new polygon[f->numberofpolygons]; // Go through all polygons, read in their vertices. for (j = 1; j <= f->numberofpolygons; j++) { p = &(f->polygonlist[j - 1]); init(p); // Read number of vertices of this polygon. stringptr = readnumberline(inputline, polyfile, inpolyfilename); p->numberofvertices = (int) strtol(stringptr, &stringptr, 0); if (p->numberofvertices < 1) { printf("Error: Wrong polygon %d in facet %d\n", j, i); break; } // Initialize 'p->vertexlist'. p->vertexlist = new int[p->numberofvertices]; // Read all vertices of this polygon. for (k = 1; k <= p->numberofvertices; k++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { // Try to load another non-empty line and continue to read the // rest of vertices. stringptr = readnumberline(inputline, polyfile, inpolyfilename); if (*stringptr == '\0') { printf("Error: Missing %d endpoints of polygon %d in facet %d", p->numberofvertices - k, j, i); break; } } p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0); } } if (j <= f->numberofpolygons) { // This must be caused by an error. However, there're j - 1 // polygons have been read. Reset the 'f->numberofpolygon'. if (j == 1) { // This is the first polygon. delete [] f->polygonlist; } f->numberofpolygons = j - 1; // No hole will be read even it exists. f->numberofholes = 0; break; } // If this facet has hole pints defined, read them. if (f->numberofholes > 0) { // Initialize 'f->holelist'. f->holelist = new REAL[f->numberofholes * 3]; // Read the holes' coordinates. index = 0; for (j = 1; j <= f->numberofholes; j++) { stringptr = readnumberline(inputline, polyfile, inpolyfilename); for (k = 1; k <= 3; k++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Hole %d in facet %d has no coordinates", j, i); break; } f->holelist[index++] = (REAL) strtod (stringptr, &stringptr); } if (k <= 3) { // This must be caused by an error. break; } } if (j <= f->numberofholes) { // This must be caused by an error. break; } } } if (i <= numberoffacets) { // This must be caused by an error. numberoffacets = i - 1; fclose(polyfile); return false; } } else { // poly == 0 // Read the facets from a .smesh file. for (i = 1; i <= numberoffacets; i++) { f = &(facetlist[i - 1]); init(f); // Initialize 'f->facetlist'. In a .smesh file, each facetlist only // contains exactly one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new polygon[f->numberofpolygons]; p = &(f->polygonlist[0]); init(p); // Read number of vertices of this polygon. stringptr = readnumberline(inputline, polyfile, insmeshfilename); p->numberofvertices = (int) strtol (stringptr, &stringptr, 0); if (p->numberofvertices < 1) { printf("Error: Wrong number of vertex in facet %d\n", i); break; } // Initialize 'p->vertexlist'. p->vertexlist = new int[p->numberofvertices]; for (k = 1; k <= p->numberofvertices; k++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { // Try to load another non-empty line and continue to read the // rest of vertices. stringptr = readnumberline(inputline, polyfile, inpolyfilename); if (*stringptr == '\0') { printf("Error: Missing %d endpoints in facet %d", p->numberofvertices - k, i); break; } } p->vertexlist[k - 1] = (int) strtol (stringptr, &stringptr, 0); } if (k <= p->numberofvertices) { // This must be caused by an error. break; } // Read facet's boundary marker at last. if (markers == 1) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { currentmarker = 0; } else { currentmarker = (int) strtol(stringptr, &stringptr, 0); } facetmarkerlist[i - 1] = currentmarker; } } if (i <= numberoffacets) { // This must be caused by an error. numberoffacets = i - 1; fclose(polyfile); return false; } } // Read the hole section. stringptr = readnumberline(inputline, polyfile, inpolyfilename); if (*stringptr != '\0') { numberofholes = (int) strtol (stringptr, &stringptr, 0); } else { numberofholes = 0; } if (numberofholes > 0) { // Initialize 'holelist'. holelist = new REAL[numberofholes * 3]; for (i = 0; i < 3 * numberofholes; i += 3) { stringptr = readnumberline(inputline, polyfile, inpolyfilename); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Hole %d has no x coord.\n", firstnumber + (i / 3)); break; } else { holelist[i] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Hole %d has no y coord.\n", firstnumber + (i / 3)); break; } else { holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Hole %d has no z coord.\n", firstnumber + (i / 3)); break; } else { holelist[i + 2] = (REAL) strtod(stringptr, &stringptr); } } if (i < 3 * numberofholes) { // This must be caused by an error. fclose(polyfile); return false; } } // Read the region section. The 'region' section is optional, if we // don't reach the end-of-file, try read it in. stringptr = readnumberline(inputline, polyfile, NULL); if (stringptr != (char *) NULL && *stringptr != '\0') { numberofregions = (int) strtol (stringptr, &stringptr, 0); } else { numberofregions = 0; } if (numberofregions > 0) { // Initialize 'regionlist'. regionlist = new REAL[numberofregions * 5]; index = 0; for (i = 0; i < numberofregions; i++) { stringptr = readnumberline(inputline, polyfile, inpolyfilename); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Region %d has no x coordinate.\n", firstnumber + i); break; } else { regionlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Region %d has no y coordinate.\n", firstnumber + i); break; } else { regionlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Region %d has no z coordinate.\n", firstnumber + i); break; } else { regionlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Region %d has no region attrib.\n", firstnumber + i); break; } else { regionlist[index++] = (REAL) strtod(stringptr, &stringptr); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { regionlist[index] = regionlist[index - 1]; } else { regionlist[index] = (REAL) strtod(stringptr, &stringptr); } index++; } if (i < numberofregions) { // This must be caused by an error. fclose(polyfile); return false; } } } else { // Read a PSLG from Triangle's poly file. assert(mesh_dim == 2); // A PSLG is a facet of a PLC. numberoffacets = 1; // Initialize the 'facetlist'. facetlist = new facet[numberoffacets]; facetmarkerlist = (int *) NULL; // No facet markers. f = &(facetlist[0]); init(f); // Read number of segments. stringptr = readnumberline(inputline, polyfile, inpolyfilename); // Segments are degenerate polygons. f->numberofpolygons = (int) strtol (stringptr, &stringptr, 0); if (f->numberofpolygons > 0) { f->polygonlist = new polygon[f->numberofpolygons]; } // Go through all segments, read in their vertices. for (j = 0; j < f->numberofpolygons; j++) { p = &(f->polygonlist[j]); init(p); // Read in a segment. stringptr = readnumberline(inputline, polyfile, inpolyfilename); stringptr = findnextnumber(stringptr); // Skip its index. p->numberofvertices = 2; // A segment always has two vertices. p->vertexlist = new int[p->numberofvertices]; p->vertexlist[0] = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); p->vertexlist[1] = (int) strtol (stringptr, &stringptr, 0); } // Read number of holes. stringptr = readnumberline(inputline, polyfile, inpolyfilename); f->numberofholes = (int) strtol (stringptr, &stringptr, 0); if (f->numberofholes > 0) { // Initialize 'f->holelist'. f->holelist = new REAL[f->numberofholes * 3]; // Read the holes' coordinates. for (j = 0; j < f->numberofholes; j++) { // Read a 2D hole point. stringptr = readnumberline(inputline, polyfile, inpolyfilename); stringptr = findnextnumber(stringptr); // Skip its index. f->holelist[j * 3] = (REAL) strtod (stringptr, &stringptr); stringptr = findnextnumber(stringptr); f->holelist[j * 3 + 1] = (REAL) strtod (stringptr, &stringptr); f->holelist[j * 3 + 2] = 0.0; // The z-coord. } } // The regions are skipped. } // End of reading poly/smesh file. fclose(polyfile); // Try to load a .var file if it exists. load_var(filebasename); // Try to load a .mtr file if it exists. load_mtr(filebasename); return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_off() Load a polyhedron from a .off file. // // // // The .off format is one of file formats of the Geomview, an interactive // // program for viewing and manipulating geometric objects. More information // // is available form: http://www.geomview.org. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_off(char* filebasename) { FILE *fp; tetgenio::facet *f; tetgenio::polygon *p; char infilename[FILENAMESIZE]; char buffer[INPUTLINESIZE]; char *bufferp; double *coord; int nverts = 0, iverts = 0; int nfaces = 0, ifaces = 0; int nedges = 0; int line_count = 0, i; strncpy(infilename, filebasename, 1024 - 1); infilename[FILENAMESIZE - 1] = '\0'; if (infilename[0] == '\0') { printf("Error: No filename.\n"); return false; } if (strcmp(&infilename[strlen(infilename) - 4], ".off") != 0) { strcat(infilename, ".off"); } if (!(fp = fopen(infilename, "r"))) { printf("File I/O Error: Unable to open file %s\n", infilename); return false; } printf("Opening %s.\n", infilename); // OFF requires the index starts from '0'. firstnumber = 0; while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { // Check section if (nverts == 0) { // Read header bufferp = strstr(bufferp, "OFF"); if (bufferp != NULL) { // Read mesh counts bufferp = findnextnumber(bufferp); // Skip field "OFF". if (*bufferp == '\0') { // Read a non-empty line. bufferp = readline(buffer, fp, &line_count); } if ((sscanf(bufferp, "%d%d%d", &nverts, &nfaces, &nedges) != 3) || (nverts == 0)) { printf("Syntax error reading header on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } // Allocate memory for 'tetgenio' if (nverts > 0) { numberofpoints = nverts; pointlist = new REAL[nverts * 3]; } if (nfaces > 0) { numberoffacets = nfaces; facetlist = new tetgenio::facet[nfaces]; } } } else if (iverts < nverts) { // Read vertex coordinates coord = &pointlist[iverts * 3]; for (i = 0; i < 3; i++) { if (*bufferp == '\0') { printf("Syntax error reading vertex coords on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } coord[i] = (REAL) strtod(bufferp, &bufferp); bufferp = findnextnumber(bufferp); } iverts++; } else if (ifaces < nfaces) { // Get next face f = &facetlist[ifaces]; init(f); // In .off format, each facet has one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[1]; p = &f->polygonlist[0]; init(p); // Read the number of vertices, it should be greater than 0. p->numberofvertices = (int) strtol(bufferp, &bufferp, 0); if (p->numberofvertices == 0) { printf("Syntax error reading polygon on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } // Allocate memory for face vertices p->vertexlist = new int[p->numberofvertices]; for (i = 0; i < p->numberofvertices; i++) { bufferp = findnextnumber(bufferp); if (*bufferp == '\0') { printf("Syntax error reading polygon on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0); } ifaces++; } else { // Should never get here printf("Found extra text starting at line %d in file %s\n", line_count, infilename); break; } } // Close file fclose(fp); // Check whether read all points if (iverts != nverts) { printf("Expected %d vertices, but read only %d vertices in file %s\n", nverts, iverts, infilename); return false; } // Check whether read all faces if (ifaces != nfaces) { printf("Expected %d faces, but read only %d faces in file %s\n", nfaces, ifaces, infilename); return false; } return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_ply() Load a polyhedron from a .ply file. // // // // This is a simplified version of reading .ply files, which only reads the // // set of vertices and the set of faces. Other informations (such as color, // // material, texture, etc) in .ply file are ignored. Complete routines for // // reading and writing ,ply files are available from: http://www.cc.gatech. // // edu/projects/large_models/ply.html. Except the header section, ply file // // format has exactly the same format for listing vertices and polygons as // // off file format. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_ply(char* filebasename) { FILE *fp; tetgenio::facet *f; tetgenio::polygon *p; char infilename[FILENAMESIZE]; char buffer[INPUTLINESIZE]; char *bufferp, *str; double *coord; int endheader = 0, format = 0; int nverts = 0, iverts = 0; int nfaces = 0, ifaces = 0; int line_count = 0, i; strncpy(infilename, filebasename, FILENAMESIZE - 1); infilename[FILENAMESIZE - 1] = '\0'; if (infilename[0] == '\0') { printf("Error: No filename.\n"); return false; } if (strcmp(&infilename[strlen(infilename) - 4], ".ply") != 0) { strcat(infilename, ".ply"); } if (!(fp = fopen(infilename, "r"))) { printf("Error: Unable to open file %s\n", infilename); return false; } printf("Opening %s.\n", infilename); // PLY requires the index starts from '0'. firstnumber = 0; while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { if (!endheader) { // Find if it is the keyword "end_header". str = strstr(bufferp, "end_header"); // strstr() is case sensitive. if (!str) str = strstr(bufferp, "End_header"); if (!str) str = strstr(bufferp, "End_Header"); if (str) { // This is the end of the header section. endheader = 1; continue; } // Parse the number of vertices and the number of faces. if (nverts == 0 || nfaces == 0) { // Find if it si the keyword "element". str = strstr(bufferp, "element"); if (!str) str = strstr(bufferp, "Element"); if (str) { bufferp = findnextfield(str); if (*bufferp == '\0') { printf("Syntax error reading element type on line%d in file %s\n", line_count, infilename); fclose(fp); return false; } if (nverts == 0) { // Find if it is the keyword "vertex". str = strstr(bufferp, "vertex"); if (!str) str = strstr(bufferp, "Vertex"); if (str) { bufferp = findnextnumber(str); if (*bufferp == '\0') { printf("Syntax error reading vertex number on line"); printf(" %d in file %s\n", line_count, infilename); fclose(fp); return false; } nverts = (int) strtol(bufferp, &bufferp, 0); // Allocate memory for 'tetgenio' if (nverts > 0) { numberofpoints = nverts; pointlist = new REAL[nverts * 3]; } } } if (nfaces == 0) { // Find if it is the keyword "face". str = strstr(bufferp, "face"); if (!str) str = strstr(bufferp, "Face"); if (str) { bufferp = findnextnumber(str); if (*bufferp == '\0') { printf("Syntax error reading face number on line"); printf(" %d in file %s\n", line_count, infilename); fclose(fp); return false; } nfaces = (int) strtol(bufferp, &bufferp, 0); // Allocate memory for 'tetgenio' if (nfaces > 0) { numberoffacets = nfaces; facetlist = new tetgenio::facet[nfaces]; } } } } // It is not the string "element". } if (format == 0) { // Find the keyword "format". str = strstr(bufferp, "format"); if (!str) str = strstr(bufferp, "Format"); if (str) { format = 1; bufferp = findnextfield(str); // Find if it is the string "ascii". str = strstr(bufferp, "ascii"); if (!str) str = strstr(bufferp, "ASCII"); if (!str) { printf("This routine only reads ascii format of ply files.\n"); printf("Hint: You can convert the binary to ascii format by\n"); printf(" using the provided ply tools:\n"); printf(" ply2ascii < %s > ascii_%s\n", infilename, infilename); fclose(fp); return false; } } } } else if (iverts < nverts) { // Read vertex coordinates coord = &pointlist[iverts * 3]; for (i = 0; i < 3; i++) { if (*bufferp == '\0') { printf("Syntax error reading vertex coords on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } coord[i] = (REAL) strtod(bufferp, &bufferp); bufferp = findnextnumber(bufferp); } iverts++; } else if (ifaces < nfaces) { // Get next face f = &facetlist[ifaces]; init(f); // In .off format, each facet has one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[1]; p = &f->polygonlist[0]; init(p); // Read the number of vertices, it should be greater than 0. p->numberofvertices = (int) strtol(bufferp, &bufferp, 0); if (p->numberofvertices == 0) { printf("Syntax error reading polygon on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } // Allocate memory for face vertices p->vertexlist = new int[p->numberofvertices]; for (i = 0; i < p->numberofvertices; i++) { bufferp = findnextnumber(bufferp); if (*bufferp == '\0') { printf("Syntax error reading polygon on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } p->vertexlist[i] = (int) strtol(bufferp, &bufferp, 0); } ifaces++; } else { // Should never get here printf("Found extra text starting at line %d in file %s\n", line_count, infilename); break; } } // Close file fclose(fp); // Check whether read all points if (iverts != nverts) { printf("Expected %d vertices, but read only %d vertices in file %s\n", nverts, iverts, infilename); return false; } // Check whether read all faces if (ifaces != nfaces) { printf("Expected %d faces, but read only %d faces in file %s\n", nfaces, ifaces, infilename); return false; } return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_stl() Load a surface mesh from a .stl file. // // // // The .stl or stereolithography format is an ASCII or binary file used in // // manufacturing. It is a list of the triangular surfaces that describe a // // computer generated solid model. This is the standard input for most rapid // // prototyping machines. // // // // Comment: A .stl file many contain many duplicated points. They will be // // unified during the Delaunay tetrahedralization process. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_stl(char* filebasename) { FILE *fp; tetgenmesh::list *plist; tetgenio::facet *f; tetgenio::polygon *p; char infilename[FILENAMESIZE]; char buffer[INPUTLINESIZE]; char *bufferp, *str; double *coord; int solid = 0; int nverts = 0, iverts = 0; int nfaces = 0; int line_count = 0, i; strncpy(infilename, filebasename, FILENAMESIZE - 1); infilename[FILENAMESIZE - 1] = '\0'; if (infilename[0] == '\0') { printf("Error: No filename.\n"); return false; } if (strcmp(&infilename[strlen(infilename) - 4], ".stl") != 0) { strcat(infilename, ".stl"); } if (!(fp = fopen(infilename, "r"))) { printf("Error: Unable to open file %s\n", infilename); return false; } printf("Opening %s.\n", infilename); // STL file has no number of points available. Use a list to read points. plist = new tetgenmesh::list(sizeof(double) * 3, NULL, 1024); while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { // The ASCII .stl file must start with the lower case keyword solid and // end with endsolid. if (solid == 0) { // Read header bufferp = strstr(bufferp, "solid"); if (bufferp != NULL) { solid = 1; } } else { // We're inside the block of the solid. str = bufferp; // Is this the end of the solid. bufferp = strstr(bufferp, "endsolid"); if (bufferp != NULL) { solid = 0; } else { // Read the XYZ coordinates if it is a vertex. bufferp = str; bufferp = strstr(bufferp, "vertex"); if (bufferp != NULL) { coord = (double *) plist->append(NULL); for (i = 0; i < 3; i++) { bufferp = findnextnumber(bufferp); if (*bufferp == '\0') { printf("Syntax error reading vertex coords on line %d\n", line_count); delete plist; fclose(fp); return false; } coord[i] = (REAL) strtod(bufferp, &bufferp); } } } } } fclose(fp); nverts = plist->len(); // nverts should be an integer times 3 (every 3 vertices denote a face). if (nverts == 0 || (nverts % 3 != 0)) { printf("Error: Wrong number of vertices in file %s.\n", infilename); delete plist; return false; } numberofpoints = nverts; pointlist = new REAL[nverts * 3]; for (i = 0; i < nverts; i++) { coord = (double *) (* plist)[i]; iverts = i * 3; pointlist[iverts] = (REAL) coord[0]; pointlist[iverts + 1] = (REAL) coord[1]; pointlist[iverts + 2] = (REAL) coord[2]; } nfaces = (int) (nverts / 3); numberoffacets = nfaces; facetlist = new tetgenio::facet[nfaces]; // Default use '1' as the array starting index. firstnumber = 1; iverts = firstnumber; for (i = 0; i < nfaces; i++) { f = &facetlist[i]; init(f); // In .stl format, each facet has one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[1]; p = &f->polygonlist[0]; init(p); // Each polygon has three vertices. p->numberofvertices = 3; p->vertexlist = new int[p->numberofvertices]; p->vertexlist[0] = iverts; p->vertexlist[1] = iverts + 1; p->vertexlist[2] = iverts + 2; iverts += 3; } delete plist; return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_medit() Load a surface mesh from a .mesh file. // // // // The .mesh format is the file format of Medit, a user-friendly interactive // // mesh viewer program. // // // // This routine ONLY reads the sections containing vertices, triangles, and // // quadrilaters. Other sections (such as tetrahedra, edges, ...) are ignored.// // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_medit(char* filebasename) { FILE *fp; tetgenio::facet *tmpflist, *f; tetgenio::polygon *p; char infilename[FILENAMESIZE]; char buffer[INPUTLINESIZE]; char *bufferp, *str; double *coord; int *tmpfmlist; int dimension = 0; int nverts = 0; int nfaces = 0; int line_count = 0; int corners = 0; // 3 (triangle) or 4 (quad). int i, j; strncpy(infilename, filebasename, FILENAMESIZE - 1); infilename[FILENAMESIZE - 1] = '\0'; if (infilename[0] == '\0') { printf("Error: No filename.\n"); return false; } if (strcmp(&infilename[strlen(infilename) - 5], ".mesh") != 0) { strcat(infilename, ".mesh"); } if (!(fp = fopen(infilename, "r"))) { printf("Error: Unable to open file %s\n", infilename); return false; } printf("Opening %s.\n", infilename); // Default uses the index starts from '1'. firstnumber = 1; while ((bufferp = readline(buffer, fp, &line_count)) != NULL) { if (*bufferp == '#') continue; // A comment line is skipped. if (dimension == 0) { // Find if it is the keyword "Dimension". str = strstr(bufferp, "Dimension"); if (!str) str = strstr(bufferp, "dimension"); if (!str) str = strstr(bufferp, "DIMENSION"); if (str) { // Read the dimensions bufferp = findnextnumber(str); // Skip field "Dimension". if (*bufferp == '\0') { // Read a non-empty line. bufferp = readline(buffer, fp, &line_count); } dimension = (int) strtol(bufferp, &bufferp, 0); if (dimension != 2 && dimension != 3) { printf("Unknown dimension in file on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } mesh_dim = dimension; } } if (nverts == 0) { // Find if it is the keyword "Vertices". str = strstr(bufferp, "Vertices"); if (!str) str = strstr(bufferp, "vertices"); if (!str) str = strstr(bufferp, "VERTICES"); if (str) { // Read the number of vertices. bufferp = findnextnumber(str); // Skip field "Vertices". if (*bufferp == '\0') { // Read a non-empty line. bufferp = readline(buffer, fp, &line_count); } nverts = (int) strtol(bufferp, &bufferp, 0); // Allocate memory for 'tetgenio' if (nverts > 0) { numberofpoints = nverts; pointlist = new REAL[nverts * 3]; } // Read the follwoing node list. for (i = 0; i < nverts; i++) { bufferp = readline(buffer, fp, &line_count); if (bufferp == NULL) { printf("Unexpected end of file on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } // Read vertex coordinates coord = &pointlist[i * 3]; for (j = 0; j < 3; j++) { if (*bufferp == '\0') { printf("Syntax error reading vertex coords on line"); printf(" %d in file %s\n", line_count, infilename); fclose(fp); return false; } if ((j < 2) || (dimension == 3)) { coord[j] = (REAL) strtod(bufferp, &bufferp); } else { assert((j == 2) && (dimension == 2)); coord[j] = 0.0; } bufferp = findnextnumber(bufferp); } } continue; } } if (nfaces == 0) { // Find if it is the keyword "Triangles" or "Quadrilaterals". corners = 0; str = strstr(bufferp, "Triangles"); if (!str) str = strstr(bufferp, "triangles"); if (!str) str = strstr(bufferp, "TRIANGLES"); if (str) { corners = 3; } else { str = strstr(bufferp, "Quadrilaterals"); if (!str) str = strstr(bufferp, "quadrilaterals"); if (!str) str = strstr(bufferp, "QUADRILATERALS"); if (str) { corners = 4; } } if (corners == 3 || corners == 4) { // Read the number of triangles (or quadrilaterals). bufferp = findnextnumber(str); // Skip field "Triangles". if (*bufferp == '\0') { // Read a non-empty line. bufferp = readline(buffer, fp, &line_count); } nfaces = strtol(bufferp, &bufferp, 0); // Allocate memory for 'tetgenio' if (nfaces > 0) { if (numberoffacets > 0) { // facetlist has already been allocated. Enlarge arrays. tmpflist = new tetgenio::facet[numberoffacets + nfaces]; tmpfmlist = new int[numberoffacets + nfaces]; // Copy the data of old arrays into new arrays. for (i = 0; i < numberoffacets; i++) { f = &(tmpflist[i]); tetgenio::init(f); *f = facetlist[i]; tmpfmlist[i] = facetmarkerlist[i]; } // Release old arrays. delete [] facetlist; delete [] facetmarkerlist; // Remember the new arrays. facetlist = tmpflist; facetmarkerlist = tmpfmlist; } else { // This is the first time to allocate facetlist. facetlist = new tetgenio::facet[nfaces]; facetmarkerlist = new int[nfaces]; } } // Read the following list of faces. for (i = numberoffacets; i < numberoffacets + nfaces; i++) { bufferp = readline(buffer, fp, &line_count); if (bufferp == NULL) { printf("Unexpected end of file on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } f = &facetlist[i]; tetgenio::init(f); // In .mesh format, each facet has one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[1]; p = &f->polygonlist[0]; tetgenio::init(p); p->numberofvertices = corners; // Allocate memory for face vertices p->vertexlist = new int[p->numberofvertices]; // Read the vertices of the face. for (j = 0; j < corners; j++) { if (*bufferp == '\0') { printf("Syntax error reading face on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } p->vertexlist[j] = (int) strtol(bufferp, &bufferp, 0); if (firstnumber == 1) { // Check if a '0' index appears. if (p->vertexlist[j] == 0) { // The first index is set to be 0. firstnumber = 0; } } bufferp = findnextnumber(bufferp); } // Read the marker of the face if it exists. facetmarkerlist[i] = 0; if (*bufferp != '\0') { facetmarkerlist[i] = (int) strtol(bufferp, &bufferp, 0); } } // Have read in a list of triangles/quads. numberoffacets += nfaces; nfaces = 0; } } // if (nverts > 0 && nfaces > 0) break; // Ignore other data. } // Close file fclose(fp); return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_vtk() Load VTK surface mesh from file (.vtk ascii or binary). // // // // This function is contributed by: Bryn Lloyd, Computer Vision Laborator, // // ETH, Zuerich. May 7, 2007. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_vtk(char* filebasename) { FILE *fp; tetgenio::facet *f; tetgenio::polygon *p; char infilename[FILENAMESIZE]; char line[INPUTLINESIZE]; char mode[128], id[256], fmt[64]; char *bufferp; double *coord; float _x, _y, _z; int nverts = 0; int nfaces = 0; int line_count = 0; int dummy; int id1, id2, id3; int nn = -1; int nn_old = -1; int i, j; bool ImALittleEndian = !testIsBigEndian(); strncpy(infilename, filebasename, FILENAMESIZE - 1); infilename[FILENAMESIZE - 1] = '\0'; if (infilename[0] == '\0') { printf("Error: No filename.\n"); return false; } if (strcmp(&infilename[strlen(infilename) - 4], ".vtk") != 0) { strcat(infilename, ".vtk"); } if (!(fp = fopen(infilename, "r"))) { printf("Error: Unable to open file %s\n", infilename); return false; } printf("Opening %s.\n", infilename); // Default uses the index starts from '0'. firstnumber = 0; strcpy(mode, "BINARY"); while((bufferp = readline(line, fp, &line_count)) != NULL) { if(strlen(line) == 0) continue; //swallow lines beginning with a comment sign or white space if(line[0] == '#' || line[0]=='\n' || line[0] == 10 || line[0] == 13 || line[0] == 32) continue; sscanf(line, "%s", id); if(!strcmp(id, "ASCII")) { strcpy(mode, "ASCII"); } if(!strcmp(id, "POINTS")) { sscanf(line, "%s %d %s", id, &nverts, fmt); if (nverts > 0) { numberofpoints = nverts; pointlist = new REAL[nverts * 3]; } if(!strcmp(mode, "BINARY")) { for(i = 0; i < nverts; i++) { coord = &pointlist[i * 3]; if(!strcmp(fmt, "double")) { fread((char*)(&(coord[0])), sizeof(double), 1, fp); fread((char*)(&(coord[1])), sizeof(double), 1, fp); fread((char*)(&(coord[2])), sizeof(double), 1, fp); if(ImALittleEndian){ swapBytes((unsigned char *) &(coord[0]), sizeof(coord[0])); swapBytes((unsigned char *) &(coord[1]), sizeof(coord[1])); swapBytes((unsigned char *) &(coord[2]), sizeof(coord[2])); } } else if(!strcmp(fmt, "float")) { fread((char*)(&_x), sizeof(float), 1, fp); fread((char*)(&_y), sizeof(float), 1, fp); fread((char*)(&_z), sizeof(float), 1, fp); if(ImALittleEndian){ swapBytes((unsigned char *) &_x, sizeof(_x)); swapBytes((unsigned char *) &_y, sizeof(_y)); swapBytes((unsigned char *) &_z, sizeof(_z)); } coord[0] = double(_x); coord[1] = double(_y); coord[2] = double(_z); } else { printf("Error: Only float or double formats are supported!\n"); return false; } } } else if(!strcmp(mode, "ASCII")) { for(i = 0; i < nverts; i++){ bufferp = readline(line, fp, &line_count); if (bufferp == NULL) { printf("Unexpected end of file on line %d in file %s\n", line_count, infilename); fclose(fp); return false; } // Read vertex coordinates coord = &pointlist[i * 3]; for (j = 0; j < 3; j++) { if (*bufferp == '\0') { printf("Syntax error reading vertex coords on line"); printf(" %d in file %s\n", line_count, infilename); fclose(fp); return false; } coord[j] = (REAL) strtod(bufferp, &bufferp); bufferp = findnextnumber(bufferp); } } } continue; } if(!strcmp(id, "POLYGONS")) { sscanf(line, "%s %d %d", id, &nfaces, &dummy); if (nfaces > 0) { numberoffacets = nfaces; facetlist = new tetgenio::facet[nfaces]; } if(!strcmp(mode, "BINARY")) { for(i = 0; i < nfaces; i++){ fread((char*)(&nn), sizeof(int), 1, fp); if(ImALittleEndian){ swapBytes((unsigned char *) &nn, sizeof(nn)); } if (i == 0) nn_old = nn; if (nn != nn_old) { printf("Error: No mixed cells are allowed.\n"); return false; } if(nn == 3){ fread((char*)(&id1), sizeof(int), 1, fp); fread((char*)(&id2), sizeof(int), 1, fp); fread((char*)(&id3), sizeof(int), 1, fp); if(ImALittleEndian){ swapBytes((unsigned char *) &id1, sizeof(id1)); swapBytes((unsigned char *) &id2, sizeof(id2)); swapBytes((unsigned char *) &id3, sizeof(id3)); } f = &facetlist[i]; init(f); // In .off format, each facet has one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[1]; p = &f->polygonlist[0]; init(p); // Set number of vertices p->numberofvertices = 3; // Allocate memory for face vertices p->vertexlist = new int[p->numberofvertices]; p->vertexlist[0] = id1; p->vertexlist[1] = id2; p->vertexlist[2] = id3; } else { printf("Error: Only triangles are supported\n"); return false; } } } else if(!strcmp(mode, "ASCII")) { for(i = 0; i < nfaces; i++) { bufferp = readline(line, fp, &line_count); nn = (int) strtol(bufferp, &bufferp, 0); if (i == 0) nn_old = nn; if (nn != nn_old) { printf("Error: No mixed cells are allowed.\n"); return false; } if (nn == 3) { bufferp = findnextnumber(bufferp); // Skip the first field. id1 = (int) strtol(bufferp, &bufferp, 0); bufferp = findnextnumber(bufferp); id2 = (int) strtol(bufferp, &bufferp, 0); bufferp = findnextnumber(bufferp); id3 = (int) strtol(bufferp, &bufferp, 0); f = &facetlist[i]; init(f); // In .off format, each facet has one polygon, no hole. f->numberofpolygons = 1; f->polygonlist = new tetgenio::polygon[1]; p = &f->polygonlist[0]; init(p); // Set number of vertices p->numberofvertices = 3; // Allocate memory for face vertices p->vertexlist = new int[p->numberofvertices]; p->vertexlist[0] = id1; p->vertexlist[1] = id2; p->vertexlist[2] = id3; } else { printf("Error: Only triangles are supported.\n"); return false; } } } fclose(fp); return true; } if(!strcmp(id,"LINES") || !strcmp(id,"CELLS")){ printf("Warning: load_vtk(): cannot read formats LINES, CELLS.\n"); } } // while () return true; } /////////////////////////////////////////////////////////////////////////////// // // // load_plc() Load a piecewise linear complex from file(s). // // // // 'object' indicates which file format is used to describ the plc. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_plc(char* filebasename, int object) { enum tetgenbehavior::objecttype type; type = (enum tetgenbehavior::objecttype) object; switch (type) { case tetgenbehavior::NODES: return load_node(filebasename); case tetgenbehavior::POLY: return load_poly(filebasename); case tetgenbehavior::OFF: return load_off(filebasename); case tetgenbehavior::PLY: return load_ply(filebasename); case tetgenbehavior::STL: return load_stl(filebasename); case tetgenbehavior::MEDIT: return load_medit(filebasename); case tetgenbehavior::VTK: return load_vtk(filebasename); default: return load_poly(filebasename); } } /////////////////////////////////////////////////////////////////////////////// // // // load_tetmesh() Load a tetrahedral mesh from files. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenio::load_tetmesh(char* filebasename) { FILE *infile; char innodefilename[FILENAMESIZE]; char inelefilename[FILENAMESIZE]; char infacefilename[FILENAMESIZE]; char inedgefilename[FILENAMESIZE]; char involfilename[FILENAMESIZE]; char inputline[INPUTLINESIZE]; char *stringptr, *infilename; REAL attrib, volume; int volelements; int markers, corner; int index, attribindex; int i, j; // Assembling the actual file names we want to open. strcpy(innodefilename, filebasename); strcpy(inelefilename, filebasename); strcpy(infacefilename, filebasename); strcpy(inedgefilename, filebasename); strcpy(involfilename, filebasename); strcat(innodefilename, ".node"); strcat(inelefilename, ".ele"); strcat(infacefilename, ".face"); strcat(inedgefilename, ".edge"); strcat(involfilename, ".vol"); // Read the points from a .node file. infilename = innodefilename; printf("Opening %s.\n", infilename); infile = fopen(infilename, "r"); if (infile == (FILE *) NULL) { printf("File I/O Error: Cannot access file %s.\n", infilename); return false; } // Read the first line of the file. stringptr = readnumberline(inputline, infile, infilename); // Is this list of points generated from rbox? stringptr = strstr(inputline, "rbox"); if (stringptr == NULL) { // Read number of points, number of dimensions, number of point // attributes, and number of boundary markers. stringptr = inputline; numberofpoints = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { mesh_dim = 3; } else { mesh_dim = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { numberofpointattributes = 0; } else { numberofpointattributes = (int) strtol (stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { markers = 0; // Default value. } else { markers = (int) strtol (stringptr, &stringptr, 0); } } else { // It is a rbox (qhull) input file. stringptr = inputline; // Get the dimension. mesh_dim = (int) strtol (stringptr, &stringptr, 0); // Get the number of points. stringptr = readnumberline(inputline, infile, infilename); numberofpoints = (int) strtol (stringptr, &stringptr, 0); // There is no index column. useindex = 0; } // Load the list of nodes. if (!load_node_call(infile, markers, infilename)) { fclose(infile); return false; } fclose(infile); // Read the elements from an .ele file. if (mesh_dim == 3) { infilename = inelefilename; infile = fopen(infilename, "r"); if (infile != (FILE *) NULL) { printf("Opening %s.\n", infilename); // Read number of elements, number of corners (4 or 10), number of // element attributes. stringptr = readnumberline(inputline, infile, infilename); numberoftetrahedra = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { numberofcorners = 4; // Default read 4 nodes per element. } else { numberofcorners = (int) strtol(stringptr, &stringptr, 0); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { numberoftetrahedronattributes = 0; // Default no attribute. } else { numberoftetrahedronattributes = (int) strtol(stringptr, &stringptr, 0); } if (numberofcorners != 4 && numberofcorners != 10) { printf("Error: Wrong number of corners %d (should be 4 or 10).\n", numberofcorners); fclose(infile); return false; } // Allocate memory for tetrahedra. if (numberoftetrahedra > 0) { tetrahedronlist = new int[numberoftetrahedra * numberofcorners]; if (tetrahedronlist == (int *) NULL) { terminatetetgen(1); } // Allocate memory for output tetrahedron attributes if necessary. if (numberoftetrahedronattributes > 0) { tetrahedronattributelist = new REAL[numberoftetrahedra * numberoftetrahedronattributes]; if (tetrahedronattributelist == (REAL *) NULL) { terminatetetgen(1); } } } // Read the list of tetrahedra. index = 0; attribindex = 0; for (i = 0; i < numberoftetrahedra; i++) { // Read tetrahedron index and the tetrahedron's corners. stringptr = readnumberline(inputline, infile, infilename); for (j = 0; j < numberofcorners; j++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Tetrahedron %d is missing vertex %d in %s.\n", i + firstnumber, j + 1, infilename); terminatetetgen(1); } corner = (int) strtol(stringptr, &stringptr, 0); if (corner < firstnumber || corner >= numberofpoints + firstnumber) { printf("Error: Tetrahedron %d has an invalid vertex index.\n", i + firstnumber); terminatetetgen(1); } tetrahedronlist[index++] = corner; } // Read the tetrahedron's attributes. for (j = 0; j < numberoftetrahedronattributes; j++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { attrib = 0.0; } else { attrib = (REAL) strtod(stringptr, &stringptr); } tetrahedronattributelist[attribindex++] = attrib; } } fclose(infile); } } // if (meshdim == 3) // Read the hullfaces or subfaces from a .face file if it exists. if (mesh_dim == 3) { infilename = infacefilename; } else { infilename = inelefilename; } infile = fopen(infilename, "r"); if (infile != (FILE *) NULL) { printf("Opening %s.\n", infilename); // Read number of faces, boundary markers. stringptr = readnumberline(inputline, infile, infilename); numberoftrifaces = (int) strtol (stringptr, &stringptr, 0); stringptr = findnextnumber(stringptr); if (mesh_dim == 2) { // Skip a number. stringptr = findnextnumber(stringptr); } if (*stringptr == '\0') { markers = 0; // Default there is no marker per face. } else { markers = (int) strtol (stringptr, &stringptr, 0); } if (numberoftrifaces > 0) { trifacelist = new int[numberoftrifaces * 3]; if (trifacelist == (int *) NULL) { terminatetetgen(1); } if (markers) { trifacemarkerlist = new int[numberoftrifaces * 3]; if (trifacemarkerlist == (int *) NULL) { terminatetetgen(1); } } } // Read the list of faces. index = 0; for (i = 0; i < numberoftrifaces; i++) { // Read face index and the face's three corners. stringptr = readnumberline(inputline, infile, infilename); for (j = 0; j < 3; j++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Face %d is missing vertex %d in %s.\n", i + firstnumber, j + 1, infilename); terminatetetgen(1); } corner = (int) strtol(stringptr, &stringptr, 0); if (corner < firstnumber || corner >= numberofpoints + firstnumber) { printf("Error: Face %d has an invalid vertex index.\n", i + firstnumber); terminatetetgen(1); } trifacelist[index++] = corner; } // Read the boundary marker if it exists. if (markers) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { attrib = 0.0; } else { attrib = (REAL) strtod(stringptr, &stringptr); } trifacemarkerlist[i] = (int) attrib; } } fclose(infile); } // Read the boundary edges from a .edge file if it exists. infilename = inedgefilename; infile = fopen(infilename, "r"); if (infile != (FILE *) NULL) { printf("Opening %s.\n", infilename); // Read number of boundary edges. stringptr = readnumberline(inputline, infile, infilename); numberofedges = (int) strtol (stringptr, &stringptr, 0); if (numberofedges > 0) { edgelist = new int[numberofedges * 2]; if (edgelist == (int *) NULL) { terminatetetgen(1); } stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { markers = 0; // Default value. } else { markers = (int) strtol (stringptr, &stringptr, 0); } if (markers > 0) { edgemarkerlist = new int[numberofedges]; } } // Read the list of faces. index = 0; for (i = 0; i < numberofedges; i++) { // Read face index and the edge's two endpoints. stringptr = readnumberline(inputline, infile, infilename); for (j = 0; j < 2; j++) { stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { printf("Error: Edge %d is missing vertex %d in %s.\n", i + firstnumber, j + 1, infilename); terminatetetgen(1); } corner = (int) strtol(stringptr, &stringptr, 0); if (corner < firstnumber || corner >= numberofpoints + firstnumber) { printf("Error: Edge %d has an invalid vertex index.\n", i + firstnumber); terminatetetgen(1); } edgelist[index++] = corner; } // Read the edge marker if it has. if (markers) { stringptr = findnextnumber(stringptr); edgemarkerlist[i] = (int) strtol(stringptr, &stringptr, 0); } } fclose(infile); } // Read the volume constraints from a .vol file if it exists. infilename = involfilename; infile = fopen(infilename, "r"); if (infile != (FILE *) NULL) { printf("Opening %s.\n", infilename); // Read number of tetrahedra. stringptr = readnumberline(inputline, infile, infilename); volelements = (int) strtol (stringptr, &stringptr, 0); if (volelements != numberoftetrahedra) { printf("Warning: %s and %s disagree on number of tetrahedra.\n", inelefilename, involfilename); volelements = 0; } if (volelements > 0) { tetrahedronvolumelist = new REAL[volelements]; if (tetrahedronvolumelist == (REAL *) NULL) { terminatetetgen(1); } } // Read the list of volume constraints. for (i = 0; i < volelements; i++) { stringptr = readnumberline(inputline, infile, infilename); stringptr = findnextnumber(stringptr); if (*stringptr == '\0') { volume = -1.0; // No constraint on this tetrahedron. } else { volume = (REAL) strtod(stringptr, &stringptr); } tetrahedronvolumelist[i] = volume; } fclose(infile); } // Try to load a .mtr file if it exists. load_mtr(filebasename); // Try to read a .pbc file if it exists. // load_pbc(filebasename); return true; } /////////////////////////////////////////////////////////////////////////////// // // // save_nodes() Save points to a .node file. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenio::save_nodes(char* filebasename) { FILE *fout; char outnodefilename[FILENAMESIZE]; char outmtrfilename[FILENAMESIZE]; int i, j; sprintf(outnodefilename, "%s.node", filebasename); printf("Saving nodes to %s\n", outnodefilename); fout = fopen(outnodefilename, "w"); fprintf(fout, "%d %d %d %d\n", numberofpoints, mesh_dim, numberofpointattributes, pointmarkerlist != NULL ? 1 : 0); for (i = 0; i < numberofpoints; i++) { if (mesh_dim == 2) { fprintf(fout, "%d %.16g %.16g", i + firstnumber, pointlist[i * 3], pointlist[i * 3 + 1]); } else { fprintf(fout, "%d %.16g %.16g %.16g", i + firstnumber, pointlist[i * 3], pointlist[i * 3 + 1], pointlist[i * 3 + 2]); } for (j = 0; j < numberofpointattributes; j++) { fprintf(fout, " %.16g", pointattributelist[i * numberofpointattributes + j]); } if (pointmarkerlist != NULL) { fprintf(fout, " %d", pointmarkerlist[i]); } fprintf(fout, "\n"); } fclose(fout); // If the point metrics exist, output them to a .mtr file. if ((numberofpointmtrs > 0) && (pointmtrlist != (REAL *) NULL)) { sprintf(outmtrfilename, "%s.mtr", filebasename); printf("Saving metrics to %s\n", outmtrfilename); fout = fopen(outmtrfilename, "w"); fprintf(fout, "%d %d\n", numberofpoints, numberofpointmtrs); for (i = 0; i < numberofpoints; i++) { for (j = 0; j < numberofpointmtrs; j++) { fprintf(fout, "%.16g ", pointmtrlist[i * numberofpointmtrs + j]); } fprintf(fout, "\n"); } fclose(fout); } } /////////////////////////////////////////////////////////////////////////////// // // // save_elements() Save elements to a .ele file. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenio::save_elements(char* filebasename) { FILE *fout; char outelefilename[FILENAMESIZE]; int i, j; sprintf(outelefilename, "%s.ele", filebasename); printf("Saving elements to %s\n", outelefilename); fout = fopen(outelefilename, "w"); if (mesh_dim == 3) { fprintf(fout, "%d %d %d\n", numberoftetrahedra, numberofcorners, numberoftetrahedronattributes); for (i = 0; i < numberoftetrahedra; i++) { fprintf(fout, "%d", i + firstnumber); for (j = 0; j < numberofcorners; j++) { fprintf(fout, " %5d", tetrahedronlist[i * numberofcorners + j]); } for (j = 0; j < numberoftetrahedronattributes; j++) { fprintf(fout, " %g", tetrahedronattributelist[i * numberoftetrahedronattributes + j]); } fprintf(fout, "\n"); } } else { // Save a two-dimensional mesh. fprintf(fout, "%d %d %d\n",numberoftrifaces,3,trifacemarkerlist ? 1 : 0); for (i = 0; i < numberoftrifaces; i++) { fprintf(fout, "%d", i + firstnumber); for (j = 0; j < 3; j++) { fprintf(fout, " %5d", trifacelist[i * 3 + j]); } if (trifacemarkerlist != NULL) { fprintf(fout, " %d", trifacemarkerlist[i]); } fprintf(fout, "\n"); } } fclose(fout); } /////////////////////////////////////////////////////////////////////////////// // // // save_faces() Save faces to a .face file. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenio::save_faces(char* filebasename) { FILE *fout; char outfacefilename[FILENAMESIZE]; int i; sprintf(outfacefilename, "%s.face", filebasename); printf("Saving faces to %s\n", outfacefilename); fout = fopen(outfacefilename, "w"); fprintf(fout, "%d %d\n", numberoftrifaces, trifacemarkerlist != NULL ? 1 : 0); for (i = 0; i < numberoftrifaces; i++) { fprintf(fout, "%d %5d %5d %5d", i + firstnumber, trifacelist[i * 3], trifacelist[i * 3 + 1], trifacelist[i * 3 + 2]); if (trifacemarkerlist != NULL) { fprintf(fout, " %d", trifacemarkerlist[i]); } fprintf(fout, "\n"); } fclose(fout); } /////////////////////////////////////////////////////////////////////////////// // // // save_edges() Save egdes to a .edge file. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenio::save_edges(char* filebasename) { FILE *fout; char outedgefilename[FILENAMESIZE]; int i; sprintf(outedgefilename, "%s.edge", filebasename); printf("Saving edges to %s\n", outedgefilename); fout = fopen(outedgefilename, "w"); fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0); for (i = 0; i < numberofedges; i++) { fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2], edgelist[i * 2 + 1]); if (edgemarkerlist != NULL) { fprintf(fout, " %d", edgemarkerlist[i]); } fprintf(fout, "\n"); } fclose(fout); } /////////////////////////////////////////////////////////////////////////////// // // // save_neighbors() Save egdes to a .neigh file. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenio::save_neighbors(char* filebasename) { FILE *fout; char outneighborfilename[FILENAMESIZE]; int i; sprintf(outneighborfilename, "%s.neigh", filebasename); printf("Saving neighbors to %s\n", outneighborfilename); fout = fopen(outneighborfilename, "w"); fprintf(fout, "%d %d\n", numberoftetrahedra, mesh_dim + 1); for (i = 0; i < numberoftetrahedra; i++) { if (mesh_dim == 2) { fprintf(fout, "%d %5d %5d %5d", i + firstnumber, neighborlist[i * 3], neighborlist[i * 3 + 1], neighborlist[i * 3 + 2]); } else { fprintf(fout, "%d %5d %5d %5d %5d", i + firstnumber, neighborlist[i * 4], neighborlist[i * 4 + 1], neighborlist[i * 4 + 2], neighborlist[i * 4 + 3]); } fprintf(fout, "\n"); } fclose(fout); } /////////////////////////////////////////////////////////////////////////////// // // // save_poly() Save segments or facets to a .poly file. // // // // It only save the facets, holes and regions. No .node file is saved. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenio::save_poly(char* filebasename) { FILE *fout; facet *f; polygon *p; char outpolyfilename[FILENAMESIZE]; int i, j, k; sprintf(outpolyfilename, "%s.poly", filebasename); printf("Saving poly to %s\n", outpolyfilename); fout = fopen(outpolyfilename, "w"); // The zero indicates that the vertices are in a separate .node file. // Followed by number of dimensions, number of vertex attributes, // and number of boundary markers (zero or one). fprintf(fout, "%d %d %d %d\n", 0, mesh_dim, numberofpointattributes, pointmarkerlist != NULL ? 1 : 0); // Save segments or facets. if (mesh_dim == 2) { // Number of segments, number of boundary markers (zero or one). fprintf(fout, "%d %d\n", numberofedges, edgemarkerlist != NULL ? 1 : 0); for (i = 0; i < numberofedges; i++) { fprintf(fout, "%d %4d %4d", i + firstnumber, edgelist[i * 2], edgelist[i * 2 + 1]); if (edgemarkerlist != NULL) { fprintf(fout, " %d", edgemarkerlist[i]); } fprintf(fout, "\n"); } } else { // Number of facets, number of boundary markers (zero or one). fprintf(fout, "%d %d\n", numberoffacets, facetmarkerlist != NULL ? 1 : 0); for (i = 0; i < numberoffacets; i++) { f = &(facetlist[i]); fprintf(fout, "%d %d %d # %d\n", f->numberofpolygons,f->numberofholes, facetmarkerlist != NULL ? facetmarkerlist[i] : 0, i + firstnumber); // Output polygons of this facet. for (j = 0; j < f->numberofpolygons; j++) { p = &(f->polygonlist[j]); fprintf(fout, "%d ", p->numberofvertices); for (k = 0; k < p->numberofvertices; k++) { if (((k + 1) % 10) == 0) { fprintf(fout, "\n "); } fprintf(fout, " %d", p->vertexlist[k]); } fprintf(fout, "\n"); } // Output holes of this facet. for (j = 0; j < f->numberofholes; j++) { fprintf(fout, "%d %.12g %.12g %.12g\n", j + firstnumber, f->holelist[j * 3], f->holelist[j * 3 + 1], f->holelist[j * 3 + 2]); } } } // Save holes. fprintf(fout, "%d\n", numberofholes); for (i = 0; i < numberofholes; i++) { // Output x, y coordinates. fprintf(fout, "%d %.12g %.12g", i + firstnumber, holelist[i * mesh_dim], holelist[i * mesh_dim + 1]); if (mesh_dim == 3) { // Output z coordinate. fprintf(fout, " %.12g", holelist[i * mesh_dim + 2]); } fprintf(fout, "\n"); } // Save regions. fprintf(fout, "%d\n", numberofregions); for (i = 0; i < numberofregions; i++) { if (mesh_dim == 2) { // Output the index, x, y coordinates, attribute (region number) // and maximum area constraint (maybe -1). fprintf(fout, "%d %.12g %.12g %.12g %.12g\n", i + firstnumber, regionlist[i * 4], regionlist[i * 4 + 1], regionlist[i * 4 + 2], regionlist[i * 4 + 3]); } else { // Output the index, x, y, z coordinates, attribute (region number) // and maximum volume constraint (maybe -1). fprintf(fout, "%d %.12g %.12g %.12g %.12g %.12g\n", i + firstnumber, regionlist[i * 5], regionlist[i * 5 + 1], regionlist[i * 5 + 2], regionlist[i * 5 + 3], regionlist[i * 5 + 4]); } } fclose(fout); } /////////////////////////////////////////////////////////////////////////////// // // // readline() Read a nonempty line from a file. // // // // A line is considered "nonempty" if it contains something more than white // // spaces. If a line is considered empty, it will be dropped and the next // // line will be read, this process ends until reaching the end-of-file or a // // non-empty line. Return NULL if it is the end-of-file, otherwise, return // // a pointer to the first non-whitespace character of the line. // // // /////////////////////////////////////////////////////////////////////////////// char* tetgenio::readline(char *string, FILE *infile, int *linenumber) { char *result; // Search for a non-empty line. do { result = fgets(string, INPUTLINESIZE - 1, infile); if (linenumber) (*linenumber)++; if (result == (char *) NULL) { return (char *) NULL; } // Skip white spaces. while ((*result == ' ') || (*result == '\t')) result++; // If it's end of line, read another line and try again. } while (*result == '\0'); return result; } /////////////////////////////////////////////////////////////////////////////// // // // findnextfield() Find the next field of a string. // // // // Jumps past the current field by searching for whitespace or a comma, then // // jumps past the whitespace or the comma to find the next field. // // // /////////////////////////////////////////////////////////////////////////////// char* tetgenio::findnextfield(char *string) { char *result; result = string; // Skip the current field. Stop upon reaching whitespace or a comma. while ((*result != '\0') && (*result != ' ') && (*result != '\t') && (*result != ',') && (*result != ';')) { result++; } // Now skip the whitespace or the comma, stop at anything else that looks // like a character, or the end of a line. while ((*result == ' ') || (*result == '\t') || (*result == ',') || (*result == ';')) { result++; } return result; } /////////////////////////////////////////////////////////////////////////////// // // // readnumberline() Read a nonempty number line from a file. // // // // A line is considered "nonempty" if it contains something that looks like // // a number. Comments (prefaced by `#') are ignored. // // // /////////////////////////////////////////////////////////////////////////////// char* tetgenio::readnumberline(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) { if (infilename != (char *) NULL) { printf(" Error: Unexpected end of file in %s.\n", infilename); terminatetetgen(1); } return result; } // 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; } /////////////////////////////////////////////////////////////////////////////// // // // findnextnumber() Find the next field of a number string. // // // // Jumps past the current field by searching for whitespace or a comma, then // // jumps past the whitespace or the comma to find the next field that looks // // like a number. // // // /////////////////////////////////////////////////////////////////////////////// char* tetgenio::findnextnumber(char *string) { char *result; result = string; // Skip the current field. Stop upon reaching whitespace or a comma. while ((*result != '\0') && (*result != '#') && (*result != ' ') && (*result != '\t') && (*result != ',')) { 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; } //// //// //// //// //// io_cxx /////////////////////////////////////////////////////////////////// //// behavior_cxx ///////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // syntax() Print list of command line switches. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenbehavior::syntax() { printf(" tetgen [-prq_a_AiMYS_T_dzo_fenvgGOJBNEFICQVh] input_file\n"); printf(" -p Tetrahedralizes a piecewise linear complex (PLC).\n"); printf(" -r Reconstructs a previously generated mesh.\n"); printf(" -q Refines mesh (to improve mesh quality).\n"); printf(" -a Applies a maximum tetrahedron volume constraint.\n"); printf(" -A Assigns attributes to tetrahedra in different regions.\n"); printf(" -i Inserts a list of additional points into mesh.\n"); printf(" -M No merge of coplanar facets.\n"); printf(" -Y No splitting of input boundaries (facets and segments).\n"); printf(" -S Specifies maximum number of added points.\n"); printf(" -T Sets a tolerance for coplanar test (default 1e-8).\n"); printf(" -d Detects self-intersections of facets of the PLC.\n"); printf(" -z Numbers all output items starting from zero.\n"); printf(" -o2 Generates second-order subparametric elements.\n"); printf(" -f Outputs all faces to .face file.\n"); printf(" -e Outputs all edges to .edge file.\n"); printf(" -n Outputs tetrahedra neighbors to .neigh file.\n"); printf(" -v Outputs Voronoi diagram to files.\n"); printf(" -g Outputs mesh to .mesh file for viewing by Medit.\n"); printf(" -G Outputs mesh to .msh file for viewing by Gid.\n"); printf(" -O Outputs mesh to .off file for viewing by Geomview.\n"); printf(" -K Outputs mesh to .vtk file for viewing by Paraview.\n"); printf(" -J No jettison of unused vertices from output .node file.\n"); printf(" -B Suppresses output of boundary information.\n"); printf(" -N Suppresses output of .node file.\n"); printf(" -E Suppresses output of .ele file.\n"); printf(" -F Suppresses output of .face file.\n"); printf(" -I Suppresses mesh iteration numbers.\n"); printf(" -C Checks the consistency of the final mesh.\n"); printf(" -Q Quiet: No terminal output except errors.\n"); printf(" -V Verbose: Detailed information, more terminal output.\n"); printf(" -h Help: A brief instruction for using TetGen.\n"); } /////////////////////////////////////////////////////////////////////////////// // // // usage() Print a brief instruction for using TetGen. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenbehavior::usage() { printf("TetGen\n"); printf("A Quality Tetrahedral Mesh Generator and 3D Delaunay "); printf("Triangulator\n"); //versioninfo(); printf("Version 1.4.3 (September 6, 2009).\n"); printf("\n"); printf("Copyright (C) 2002 - 2009\n"); printf("Hang Si\n"); printf("Mohrenstr. 39, 10117 Berlin, Germany\n"); printf("si@wias-berlin.de\n"); printf("\n"); printf("What Can TetGen Do?\n"); printf("\n"); printf(" TetGen generates exact Delaunay tetrahedralizations, exact\n"); printf(" constrained Delaunay tetrahedralizations, and quality "); printf("tetrahedral\n meshes. The latter are nicely graded and whose "); printf("tetrahedra have\n radius-edge ratio bounded, thus are suitable "); printf("for finite element and\n finite volume analysis.\n"); printf("\n"); printf("Command Line Syntax:\n"); printf("\n"); printf(" Below is the command line syntax of TetGen with a list of "); printf("short\n"); printf(" descriptions. Underscores indicate that numbers may optionally\n"); printf(" follow certain switches. Do not leave any space between a "); printf("switch\n"); printf(" and its numeric parameter. \'input_file\' contains input data\n"); printf(" depending on the switches you supplied which may be a "); printf(" piecewise\n"); printf(" linear complex or a list of nodes. File formats and detailed\n"); printf(" description of command line switches are found in user's "); printf("manual.\n"); printf("\n"); syntax(); printf("\n"); printf("Examples of How to Use TetGen:\n"); printf("\n"); printf(" \'tetgen object\' reads vertices from object.node, and writes "); printf("their\n Delaunay tetrahedralization to object.1.node and "); printf("object.1.ele.\n"); printf("\n"); printf(" \'tetgen -p object\' reads a PLC from object.poly or object."); printf("smesh (and\n possibly object.node) and writes its constrained "); printf("Delaunay\n tetrahedralization to object.1.node, object.1.ele and "); printf("object.1.face.\n"); printf("\n"); printf(" \'tetgen -pq1.414a.1 object\' reads a PLC from object.poly or\n"); printf(" object.smesh (and possibly object.node), generates a mesh "); printf("whose\n tetrahedra have radius-edge ratio smaller than 1.414 and "); printf("have volume\n of 0.1 or less, and writes the mesh to "); printf("object.1.node, object.1.ele\n and object.1.face.\n"); printf("\n"); printf("Please send bugs/comments to Hang Si \n"); terminatetetgen(0); } /////////////////////////////////////////////////////////////////////////////// // // // parse_commandline() Read the command line, identify switches, and set // // up options and file names. // // // // 'argc' and 'argv' are the same parameters passed to the function main() // // of a C/C++ program. They together represent the command line user invoked // // from an environment in which TetGen is running. // // // // When TetGen is invoked from an environment. 'argc' is nonzero, switches // // and input filename should be supplied as zero-terminated strings in // // argv[0] through argv[argc - 1] and argv[0] shall be the name used to // // invoke TetGen, i.e. "tetgen". Switches are previously started with a // // dash '-' to identify them from the input filename. // // // // When TetGen is called from within another program. 'argc' is set to zero. // // switches are given in one zero-terminated string (no previous dash is // // required.), and 'argv' is a pointer points to this string. No input // // filename is required (usually the input data has been directly created by // // user in the 'tetgenio' structure). A default filename 'tetgen-tmpfile' // // will be created for debugging output purpose. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenbehavior::parse_commandline(int argc, char **argv) { int startindex; int increment; int meshnumber; int scount; int i, j, k; char workstring[1024]; // First determine the input style of the switches. if (argc == 0) { startindex = 0; // Switches are given without a dash. argc = 1; // For running the following for-loop once. commandline[0] = '\0'; } else { startindex = 1; strcpy(commandline, argv[0]); strcat(commandline, " "); } // Rcount used to count the number of '-R' be used. scount = 0; for (i = startindex; i < argc; i++) { // Remember the command line switches. strcat(commandline, argv[i]); strcat(commandline, " "); if (startindex == 1) { // Is this string a filename? if (argv[i][0] != '-') { strncpy(infilename, argv[i], 1024 - 1); infilename[1024 - 1] = '\0'; // Go to the next string directly. continue; } } // Parse the individual switch from the string. for (j = startindex; argv[i][j] != '\0'; j++) { if (argv[i][j] == 'p') { plc = 1; } else if (argv[i][j] == 'r') { refine++; } else if (argv[i][j] == 'R') { coarse = 1; } else if (argv[i][j] == 'q') { quality++; if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { 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'; if (quality == 1) { minratio = (REAL) strtod(workstring, (char **) NULL); } else if (quality == 2) { mindihedral = (REAL) strtod(workstring, (char **) NULL); } else if (quality == 3) { maxdihedral = (REAL) strtod(workstring, (char **) NULL); } } } else if (argv[i][j] == 'm') { metric++; if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { 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'; if (metric == 1) { alpha1 = (REAL) strtod(workstring, (char **) NULL); } else if (metric == 2) { alpha2 = (REAL) strtod(workstring, (char **) NULL); } } } else if (argv[i][j] == 'a') { if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { fixedvolume = 1; k = 0; while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { j++; workstring[k] = argv[i][j]; k++; } workstring[k] = '\0'; maxvolume = (REAL) strtod(workstring, (char **) NULL); } else { varvolume = 1; } } else if (argv[i][j] == 'A') { regionattrib++; } else if (argv[i][j] == 'i') { insertaddpoints = 1; } else if (argv[i][j] == 'd') { diagnose = 1; } else if (argv[i][j] == 'z') { zeroindex = 1; } else if (argv[i][j] == 'f') { facesout = 1; } else if (argv[i][j] == 'e') { edgesout++; } else if (argv[i][j] == 'n') { neighout++; } else if (argv[i][j] == 'v') { voroout = 1; } else if (argv[i][j] == 'g') { meditview = 1; } else if (argv[i][j] == 'G') { gidview = 1; } else if (argv[i][j] == 'O') { geomview = 1; } else if (argv[i][j] == 'K') { vtkview = 1; } else if (argv[i][j] == 'M') { nomerge = 1; } else if (argv[i][j] == 'Y') { nobisect++; } else if (argv[i][j] == 'J') { nojettison = 1; } else if (argv[i][j] == 'B') { nobound = 1; } else if (argv[i][j] == 'N') { nonodewritten = 1; } else if (argv[i][j] == 'E') { noelewritten = 1; if (argv[i][j + 1] == '2') { j++; noelewritten = 2; } } else if (argv[i][j] == 'F') { nofacewritten = 1; } else if (argv[i][j] == 'I') { noiterationnum = 1; } else if (argv[i][j] == 'o') { if (argv[i][j + 1] == '2') { j++; order = 2; } } else if (argv[i][j] == 'S') { if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { k = 0; while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { j++; workstring[k] = argv[i][j]; k++; } workstring[k] = '\0'; steiner = (int) strtol(workstring, (char **) NULL, 0); } } else if (argv[i][j] == 's') { scount++; if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { k = 0; while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { j++; workstring[k] = argv[i][j]; k++; } workstring[k] = '\0'; if (scount == 1) { optlevel = (int) strtol(workstring, (char **) NULL, 0); } else if (scount == 2) { optpasses = (int) strtol(workstring, (char **) NULL, 0); } } } else if (argv[i][j] == 'D') { conformdel++; } else if (argv[i][j] == 'T') { if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.')) { k = 0; while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || (argv[i][j + 1] == '.') || (argv[i][j + 1] == 'e') || (argv[i][j + 1] == '-') || (argv[i][j + 1] == '+')) { j++; workstring[k] = argv[i][j]; k++; } workstring[k] = '\0'; epsilon = (REAL) strtod(workstring, (char **) NULL); } } else if (argv[i][j] == 'C') { docheck++; } else if (argv[i][j] == 'X') { fliprepair = 0; } else if (argv[i][j] == 'Q') { quiet = 1; } else if (argv[i][j] == 'V') { verbose++; } else if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || (argv[i][j] == '?')) { usage(); } else { printf("Warning: Unknown switch -%c.\n", argv[i][j]); } } } if (startindex == 0) { // Set a temporary filename for debugging output. strcpy(infilename, "tetgen-tmpfile"); } else { if (infilename[0] == '\0') { // No input file name. Print the syntax and exit. syntax(); terminatetetgen(0); } // Recognize the object from file extension if it is available. if (!strcmp(&infilename[strlen(infilename) - 5], ".node")) { infilename[strlen(infilename) - 5] = '\0'; object = NODES; } else if (!strcmp(&infilename[strlen(infilename) - 5], ".poly")) { infilename[strlen(infilename) - 5] = '\0'; object = POLY; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 6], ".smesh")) { infilename[strlen(infilename) - 6] = '\0'; object = POLY; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 4], ".off")) { infilename[strlen(infilename) - 4] = '\0'; object = OFF; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ply")) { infilename[strlen(infilename) - 4] = '\0'; object = PLY; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 4], ".stl")) { infilename[strlen(infilename) - 4] = '\0'; object = STL; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 5], ".mesh")) { infilename[strlen(infilename) - 5] = '\0'; object = MEDIT; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 4], ".vtk")) { infilename[strlen(infilename) - 4] = '\0'; object = VTK; plc = 1; } else if (!strcmp(&infilename[strlen(infilename) - 4], ".ele")) { infilename[strlen(infilename) - 4] = '\0'; object = MESH; refine = 1; } } plc = plc || diagnose; useshelles = plc || refine || coarse || quality; goodratio = minratio; goodratio *= goodratio; // Detect improper combinations of switches. if (plc && refine) { printf("Error: Switch -r cannot use together with -p.\n"); return false; } if (refine && (plc || noiterationnum)) { printf("Error: Switches %s cannot use together with -r.\n", "-p, -d, and -I"); return false; } if (diagnose && (quality || insertaddpoints || (order == 2) || neighout || docheck)) { printf("Error: Switches %s cannot use together with -d.\n", "-q, -i, -o2, -n, and -C"); return false; } // Be careful not to allocate space for element area constraints that // will never be assigned any value (other than the default -1.0). if (!refine && !plc) { 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 (refine || !plc) { regionattrib = 0; } // If '-a' or '-aa' is in use, enable '-q' option too. if (fixedvolume || varvolume) { if (quality == 0) { quality = 1; } } // Calculate the goodangle for testing bad subfaces. goodangle = cos(minangle * tetgenmesh::PI / 180.0); goodangle *= goodangle; increment = 0; strcpy(workstring, infilename); j = 1; while (workstring[j] != '\0') { if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { increment = j + 1; } j++; } meshnumber = 0; if (increment > 0) { j = increment; do { if ((workstring[j] >= '0') && (workstring[j] <= '9')) { meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); } else { increment = 0; } j++; } while (workstring[j] != '\0'); } if (noiterationnum) { strcpy(outfilename, infilename); } else if (increment == 0) { strcpy(outfilename, infilename); strcat(outfilename, ".1"); } else { workstring[increment] = '%'; workstring[increment + 1] = 'd'; workstring[increment + 2] = '\0'; sprintf(outfilename, workstring, meshnumber + 1); } // Additional input file name has the end ".a". strcpy(addinfilename, infilename); strcat(addinfilename, ".a"); // Background filename has the form "*.b.ele", "*.b.node", ... strcpy(bgmeshfilename, infilename); strcat(bgmeshfilename, ".b"); return true; } //// //// //// //// //// behavior_cxx ///////////////////////////////////////////////////////////// //// prim_cxx ///////////////////////////////////////////////////////////////// //// //// //// //// // For enumerating three edges of a triangle. int tetgenmesh::plus1mod3[3] = {1, 2, 0}; int tetgenmesh::minus1mod3[3] = {2, 0, 1}; // Table 've' takes an edge version as input, returns the next edge version // in the same edge ring. int tetgenmesh::ve[6] = { 2, 5, 4, 1, 0, 3 }; // Tables 'vo', 'vd' and 'va' take an edge version, return the positions of // the origin, destination and apex in the triangle. int tetgenmesh::vo[6] = { 0, 1, 1, 2, 2, 0 }; int tetgenmesh::vd[6] = { 1, 0, 2, 1, 0, 2 }; int tetgenmesh::va[6] = { 2, 2, 0, 0, 1, 1 }; // The following tables are for tetrahedron primitives (operate on trifaces). // For 'org()', 'dest()' and 'apex()'. Use 'loc' as the first index and // 'ver' as the second index. int tetgenmesh::locver2org[4][6] = { {0, 1, 1, 2, 2, 0}, {0, 3, 3, 1, 1, 0}, {1, 3, 3, 2, 2, 1}, {2, 3, 3, 0, 0, 2} }; int tetgenmesh::locver2dest[4][6] = { {1, 0, 2, 1, 0, 2}, {3, 0, 1, 3, 0, 1}, {3, 1, 2, 3, 1, 2}, {3, 2, 0, 3, 2, 0} }; int tetgenmesh::locver2apex[4][6] = { {2, 2, 0, 0, 1, 1}, {1, 1, 0, 0, 3, 3}, {2, 2, 1, 1, 3, 3}, {0, 0, 2, 2, 3, 3} }; // For oppo() primitives, use 'loc' as the index. int tetgenmesh::loc2oppo[4] = { 3, 2, 0, 1 }; // For fnext() primitive. Use 'loc' as the first index and 'ver' as the // second index. Returns a new 'loc' and new 'ver' in an array. (It is // only valid for edge version equals one of {0, 2, 4}.) int tetgenmesh::locver2nextf[4][6][2] = { { {1, 5}, {-1, -1}, {2, 5}, {-1, -1}, {3, 5}, {-1, -1} }, { {3, 3}, {-1, -1}, {2, 1}, {-1, -1}, {0, 1}, {-1, -1} }, { {1, 3}, {-1, -1}, {3, 1}, {-1, -1}, {0, 3}, {-1, -1} }, { {2, 3}, {-1, -1}, {1, 1}, {-1, -1}, {0, 5}, {-1, -1} } }; // The edge number (from 0 to 5) of a tet is defined as follows: // 0 - (v0, v1), 1 - (v1, v2), 2 - (v2, v0) // 3 - (v3, v0), 4 - (v3, v1), 5 - (v3, v2). int tetgenmesh::locver2edge[4][6] = { {0, 0, 1, 1, 2, 2}, {3, 3, 4, 4, 0, 0}, {4, 4, 5, 5, 1, 1}, {5, 5, 3, 3, 2, 2} }; int tetgenmesh::edge2locver[6][2] = { {0, 0}, // 0 v0 -> v1 (a -> b) {0, 2}, // 1 v1 -> v2 (b -> c) {0, 4}, // 2 v2 -> v0 (c -> a) {1, 0}, // 3 v0 -> v3 (a -> d) {1, 2}, // 4 v1 -> v3 (b -> d {2, 2} // 5 v2 -> v3 (c -> d) }; int tetgenmesh::locpivot[4][3] = { {1, 2, 3}, {0, 2, 3}, {0, 1, 3}, {0, 1, 2} }; int tetgenmesh::locverpivot[4][6][2] = { {{2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 2}, {1, 2}}, {{0, 2}, {0, 2}, {0, 3}, {0, 3}, {2, 3}, {2, 3}}, {{0, 3}, {0, 3}, {0, 1}, {0, 1}, {1, 3}, {1, 3}}, {{0, 1}, {0, 1}, {0, 2}, {0, 2}, {1, 2}, {1, 2}} }; /////////////////////////////////////////////////////////////////////////////// // // // getnextsface() Finds the next subface in the face ring. // // // // For saving space in the data structure of subface, there only exists one // // face ring around a segment (see programming manual). This routine imple- // // ments the double face ring as desired in Muecke's data structure. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::getnextsface(face* s1, face* s2) { face neighsh, spinsh; face testseg; sspivot(*s1, testseg); if (testseg.sh != dummysh) { testseg.shver = 0; if (sorg(testseg) == sorg(*s1)) { spivot(*s1, neighsh); } else { spinsh = *s1; do { neighsh = spinsh; spivotself(spinsh); } while (spinsh.sh != s1->sh); } } else { spivot(*s1, neighsh); } if (sorg(neighsh) != sorg(*s1)) { sesymself(neighsh); } if (s2 != (face *) NULL) { *s2 = neighsh; } else { *s1 = neighsh; } } /////////////////////////////////////////////////////////////////////////////// // // // tsspivot() Finds a subsegment abutting on a tetrahderon's edge. // // // // The edge is represented in the primary edge of 'checkedge'. If there is a // // subsegment bonded at this edge, it is returned in handle 'checkseg', the // // edge direction of 'checkseg' is conformed to 'checkedge'. If there isn't, // // set 'checkseg.sh = dummysh' to indicate it is not a subsegment. // // // // To find whether an edge of a tetrahedron is a subsegment or not. First we // // need find a subface around this edge to see if it contains a subsegment. // // The reason is there is no direct connection between a tetrahedron and its // // adjoining subsegments. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::tsspivot(triface* checkedge, face* checkseg) { triface spintet; face parentsh; point tapex; int hitbdry; spintet = *checkedge; tapex = apex(*checkedge); hitbdry = 0; do { tspivot(spintet, parentsh); // Does spintet have a (non-fake) subface attached? if ((parentsh.sh != dummysh) && (sapex(parentsh) != NULL)) { // Find a subface! Find the edge in it. findedge(&parentsh, org(*checkedge), dest(*checkedge)); sspivot(parentsh, *checkseg); if (checkseg->sh != dummysh) { // Find a subsegment! Correct its edge direction before return. if (sorg(*checkseg) != org(*checkedge)) { sesymself(*checkseg); } } return; } if (!fnextself(spintet)) { hitbdry++; if (hitbdry < 2) { esym(*checkedge, spintet); if (!fnextself(spintet)) { hitbdry++; } } } } while ((apex(spintet) != tapex) && (hitbdry < 2)); // Not find. checkseg->sh = dummysh; } /////////////////////////////////////////////////////////////////////////////// // // // sstpivot() Finds a tetrahedron abutting a subsegment. // // // // This is the inverse operation of 'tsspivot()'. One subsegment shared by // // arbitrary number of tetrahedron, the returned tetrahedron is not unique. // // The edge direction of the returned tetrahedron is conformed to the given // // subsegment. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::sstpivot(face* checkseg, triface* retedge) { face parentsh; // Get the subface which holds the subsegment. sdecode(checkseg->sh[0], parentsh); #ifdef SELF_CHECK assert(parentsh.sh != dummysh); #endif // Get a tetraheron to which the subface attches. stpivot(parentsh, *retedge); if (retedge->tet == dummytet) { sesymself(parentsh); stpivot(parentsh, *retedge); #ifdef SELF_CHECK assert(retedge->tet != dummytet); #endif } // Correct the edge direction before return. findedge(retedge, sorg(*checkseg), sdest(*checkseg)); } /////////////////////////////////////////////////////////////////////////////// // // // point2tetorg(), point2shorg(), point2segorg() // // // // Return a tet, a subface, or a subsegment whose origin is the given point. // // These routines assume the maps between points to tets (subfaces, segments // // ) have been built and maintained. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::point2tetorg(point pa, triface& searchtet) { int i; // Search a tet whose origin is pa. decode(point2tet(pa), searchtet); if (searchtet.tet == NULL) { printf("Internal error: %d contains bad tet pointer.\n", pointmark(pa)); terminatetetgen(2); } for (i = 4; i < 8; i++) { if ((point) searchtet.tet[i] == pa) { // Found. Set pa as its origin. switch (i) { case 4: searchtet.loc = 0; searchtet.ver = 0; break; case 5: searchtet.loc = 0; searchtet.ver = 2; break; case 6: searchtet.loc = 0; searchtet.ver = 4; break; case 7: searchtet.loc = 1; searchtet.ver = 2; break; } break; } } if (i == 8) { printf("Internal error: %d contains bad tet pointer.\n", pointmark(pa)); terminatetetgen(2); } } void tetgenmesh::point2shorg(point pa, face& searchsh) { sdecode(point2sh(pa), searchsh); if (searchsh.sh == NULL) { printf("Internal error: %d contains bad sub pointer.\n", pointmark(pa)); terminatetetgen(2); } if (((point) searchsh.sh[3]) == pa) { searchsh.shver = 0; } else if (((point) searchsh.sh[4]) == pa) { searchsh.shver = 2; } else if (((point) searchsh.sh[5]) == pa) { searchsh.shver = 4; } else { printf("Internal error: %d contains bad sub pointer.\n", pointmark(pa)); terminatetetgen(2); } } void tetgenmesh::point2segorg(point pa, face& searchsh) { sdecode(point2seg(pa), searchsh); if (searchsh.sh == NULL) { printf("Internal error: %d contains bad seg pointer.\n", pointmark(pa)); terminatetetgen(2); } if (((point) searchsh.sh[3]) == pa) { searchsh.shver = 0; } else if (((point) searchsh.sh[4]) == pa) { searchsh.shver = 1; } else { printf("Internal error: %d contains bad sub pointer.\n", pointmark(pa)); terminatetetgen(2); } } /////////////////////////////////////////////////////////////////////////////// // // // findorg() Find a point in the given tet or subface. // // // // If 'dorg' is a one of vertices of the given handle, set the origin of // // this handle be that point and return TRUE. Otherwise, return FALSE and // // 'tface' remains unchanged. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::findorg(triface* tface, point dorg) { if (org(*tface) == dorg) { return true; } else { if (dest(*tface) == dorg) { enextself(*tface); return true; } else { if (apex(*tface) == dorg) { enext2self(*tface); return true; } else { if (oppo(*tface) == dorg) { // Keep 'tface' referring to the same tet after fnext(). adjustedgering(*tface, CCW); fnextself(*tface); enext2self(*tface); return true; } } } } return false; } bool tetgenmesh::findorg(face* sface, point dorg) { if (sorg(*sface) == dorg) { return true; } else { if (sdest(*sface) == dorg) { senextself(*sface); return true; } else { if (sapex(*sface) == dorg) { senext2self(*sface); return true; } } } return false; } /////////////////////////////////////////////////////////////////////////////// // // // findedge() Find an edge in the given tet or subface. // // // // The edge is given in two points 'eorg' and 'edest'. It is assumed that // // the edge must exist in the given handle (tetrahedron or subface). This // // routine sets the right edge version for the input handle. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::findedge(triface* tface, point eorg, point edest) { int i; for (i = 0; i < 3; i++) { if (org(*tface) == eorg) { if (dest(*tface) == edest) { // Edge is found, return. return; } } else { if (org(*tface) == edest) { if (dest(*tface) == eorg) { // Edge is found, inverse the direction and return. esymself(*tface); return; } } } enextself(*tface); } // It should never be here. printf("Internalerror in findedge(): Unable to find an edge in tet.\n"); terminatetetgen(2); } void tetgenmesh::findedge(face* sface, point eorg, point edest) { int i; for (i = 0; i < 3; i++) { if (sorg(*sface) == eorg) { if (sdest(*sface) == edest) { // Edge is found, return. return; } } else { if (sorg(*sface) == edest) { if (sdest(*sface) == eorg) { // Edge is found, inverse the direction and return. sesymself(*sface); return; } } } senextself(*sface); } printf("Internalerror in findedge(): Unable to find an edge in subface.\n"); terminatetetgen(2); } /////////////////////////////////////////////////////////////////////////////// // // // getonextseg() Get the next segment counterclockwise with the same org. // // // // 's' is a subface. This routine reteuns the segment which is counterclock- // // wise with the origin of s. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::getonextseg(face* s, face* lseg) { face checksh, checkseg; point forg; forg = sorg(*s); checksh = *s; do { // Go to the edge at forg's left side. senext2self(checksh); // Check if there is a segment attaching this edge. sspivot(checksh, checkseg); if (checkseg.sh != dummysh) break; // No segment! Go to the neighbor of this subface. spivotself(checksh); #ifdef SELF_CHECK // It should always meet a segment before come back. assert(checksh.sh != s->sh); #endif if (sorg(checksh) != forg) { sesymself(checksh); #ifdef SELF_CHECK assert(sorg(checksh) == forg); #endif } } while (true); if (sorg(checkseg) != forg) sesymself(checkseg); *lseg = checkseg; } /////////////////////////////////////////////////////////////////////////////// // // // getseghasorg() Get the segment containing the given point. // // // // 'dorg' is an endpoint of a segment S. 'sseg' is a subsegment of S. This // // routine search a subsegment (along sseg) of S containing dorg. On return, // // 'sseg' contains 'dorg' as its origin. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::getseghasorg(face* sseg, point dorg) { face nextseg; point checkpt; nextseg = *sseg; checkpt = sorg(nextseg); while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) { // Search dorg along the original direction of sseg. senext2self(nextseg); spivotself(nextseg); nextseg.shver = 0; if (sdest(nextseg) != checkpt) sesymself(nextseg); checkpt = sorg(nextseg); } if (checkpt == dorg) { *sseg = nextseg; return; } nextseg = *sseg; checkpt = sdest(nextseg); while ((checkpt != dorg) && (pointtype(checkpt) == FREESEGVERTEX)) { // Search dorg along the destinational direction of sseg. senextself(nextseg); spivotself(nextseg); nextseg.shver = 0; if (sorg(nextseg) != checkpt) sesymself(nextseg); checkpt = sdest(nextseg); } if (checkpt == dorg) { sesym(nextseg, *sseg); return; } // Should never be here. printf("Internalerror in getseghasorg(): Unable to find the subseg.\n"); terminatetetgen(2); } /////////////////////////////////////////////////////////////////////////////// // // // getsubsegfarorg() Get the origin of the parent segment of a subseg. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::point tetgenmesh::getsubsegfarorg(face* sseg) { face prevseg; point checkpt; checkpt = sorg(*sseg); senext2(*sseg, prevseg); spivotself(prevseg); // Search dorg along the original direction of sseg. while (prevseg.sh != dummysh) { prevseg.shver = 0; if (sdest(prevseg) != checkpt) sesymself(prevseg); checkpt = sorg(prevseg); senext2self(prevseg); spivotself(prevseg); } return checkpt; } /////////////////////////////////////////////////////////////////////////////// // // // getsubsegfardest() Get the dest. of the parent segment of a subseg. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::point tetgenmesh::getsubsegfardest(face* sseg) { face nextseg; point checkpt; checkpt = sdest(*sseg); senext(*sseg, nextseg); spivotself(nextseg); // Search dorg along the destinational direction of sseg. while (nextseg.sh != dummysh) { nextseg.shver = 0; if (sorg(nextseg) != checkpt) sesymself(nextseg); checkpt = sdest(nextseg); senextself(nextseg); spivotself(nextseg); } return checkpt; } /////////////////////////////////////////////////////////////////////////////// // // // printtet() Print out the details of a tetrahedron on screen. // // // // It's also used when the highest level of verbosity (`-VVV') is specified. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::printtet(triface* tface) { triface tmpface, prtface; shellface *shells; point tmppt; face checksh; int facecount; printf("Tetra x%lx with loc(%i) and ver(%i):", (uintptr_t)(tface->tet), tface->loc, tface->ver); if (infected(*tface)) { printf(" (infected)"); } if (marktested(*tface)) { printf(" (marked)"); } printf("\n"); tmpface = *tface; facecount = 0; while(facecount < 4) { tmpface.loc = facecount; sym(tmpface, prtface); if(prtface.tet == dummytet) { printf(" [%i] Outer space.\n", facecount); } else { if (!isdead(&prtface)) { printf(" [%i] x%lx loc(%i).", facecount, (uintptr_t)(prtface.tet), prtface.loc); if (infected(prtface)) { printf(" (infected)"); } printf("\n"); } else { printf(" [%i] NULL\n", facecount); } } facecount ++; } tmppt = org(*tface); if(tmppt == (point) NULL) { printf(" Org [%i] NULL\n", locver2org[tface->loc][tface->ver]); } else { printf(" Org [%i] x%lx (%.12g,%.12g,%.12g) %d\n", locver2org[tface->loc][tface->ver], (uintptr_t)(tmppt), tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); } tmppt = dest(*tface); if(tmppt == (point) NULL) { printf(" Dest[%i] NULL\n", locver2dest[tface->loc][tface->ver]); } else { printf(" Dest[%i] x%lx (%.12g,%.12g,%.12g) %d\n", locver2dest[tface->loc][tface->ver], (uintptr_t)(tmppt), tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); } tmppt = apex(*tface); if(tmppt == (point) NULL) { printf(" Apex[%i] NULL\n", locver2apex[tface->loc][tface->ver]); } else { printf(" Apex[%i] x%lx (%.12g,%.12g,%.12g) %d\n", locver2apex[tface->loc][tface->ver], (uintptr_t)(tmppt), tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); } tmppt = oppo(*tface); if(tmppt == (point) NULL) { printf(" Oppo[%i] NULL\n", loc2oppo[tface->loc]); } else { printf(" Oppo[%i] x%lx (%.12g,%.12g,%.12g) %d\n", loc2oppo[tface->loc], (uintptr_t)(tmppt), tmppt[0], tmppt[1], tmppt[2], pointmark(tmppt)); } if (b->useshelles) { if (tface->tet[8] != NULL) { shells = (shellface *) tface->tet[8]; for (facecount = 0; facecount < 6; facecount++) { sdecode(shells[facecount], checksh); if (checksh.sh != dummysh) { printf(" [%d] x%lx %d.", facecount, (uintptr_t) checksh.sh, checksh.shver); } else { printf(" [%d] NULL.", facecount); } if (locver2edge[tface->loc][tface->ver] == facecount) { printf(" (*)"); // It is the current edge. } printf("\n"); } } if (tface->tet[9] != NULL) { shells = (shellface *) tface->tet[9]; for (facecount = 0; facecount < 4; facecount++) { sdecode(shells[facecount], checksh); if (checksh.sh != dummysh) { printf(" [%d] x%lx %d.", facecount, (uintptr_t) checksh.sh, checksh.shver); } else { printf(" [%d] NULL.", facecount); } if (tface->loc == facecount) { printf(" (*)"); // It is the current face. } printf("\n"); } } } } /////////////////////////////////////////////////////////////////////////////// // // // printsh() Print out the details of a subface or subsegment on screen. // // // // It's also used when the highest level of verbosity (`-VVV') is specified. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::printsh(face* sface) { face prtsh; triface prttet; point printpoint; if (sapex(*sface) != NULL) { printf("subface x%lx, ver %d, mark %d:", (uintptr_t)(sface->sh), sface->shver, shellmark(*sface)); } else { printf("Subsegment x%lx, ver %d, mark %d:", (uintptr_t)(sface->sh), sface->shver, shellmark(*sface)); } if (sinfected(*sface)) { printf(" (infected)"); } if (smarktested(*sface)) { printf(" (marked)"); } if (shell2badface(*sface)) { printf(" (queued)"); } if (sapex(*sface) != NULL) { if (shelltype(*sface) == SHARP) { printf(" (sharp)"); } } else { if (shelltype(*sface) == SHARP) { printf(" (sharp)"); } } if (checkpbcs) { if (shellpbcgroup(*sface) >= 0) { printf(" (pbc %d)", shellpbcgroup(*sface)); } } printf("\n"); sdecode(sface->sh[0], prtsh); if (prtsh.sh == dummysh) { printf(" [0] = No shell\n"); } else { printf(" [0] = x%lx %d\n", (uintptr_t)(prtsh.sh), prtsh.shver); } sdecode(sface->sh[1], prtsh); if (prtsh.sh == dummysh) { printf(" [1] = No shell\n"); } else { printf(" [1] = x%lx %d\n", (uintptr_t)(prtsh.sh), prtsh.shver); } sdecode(sface->sh[2], prtsh); if (prtsh.sh == dummysh) { printf(" [2] = No shell\n"); } else { printf(" [2] = x%lx %d\n", (uintptr_t)(prtsh.sh), prtsh.shver); } printpoint = sorg(*sface); if (printpoint == (point) NULL) printf(" Org [%d] = NULL\n", vo[sface->shver]); else printf(" Org [%d] = x%lx (%.12g,%.12g,%.12g) %d\n", vo[sface->shver], (uintptr_t)(printpoint), printpoint[0], printpoint[1], printpoint[2], pointmark(printpoint)); printpoint = sdest(*sface); if (printpoint == (point) NULL) printf(" Dest[%d] = NULL\n", vd[sface->shver]); else printf(" Dest[%d] = x%lx (%.12g,%.12g,%.12g) %d\n", vd[sface->shver], (uintptr_t)(printpoint), printpoint[0], printpoint[1], printpoint[2], pointmark(printpoint)); if (sapex(*sface) != NULL) { printpoint = sapex(*sface); if (printpoint == (point) NULL) printf(" Apex[%d] = NULL\n", va[sface->shver]); else printf(" Apex[%d] = x%lx (%.12g,%.12g,%.12g) %d\n", va[sface->shver], (uintptr_t)(printpoint), printpoint[0], printpoint[1], printpoint[2], pointmark(printpoint)); decode(sface->sh[6], prttet); if (prttet.tet == dummytet) { printf(" [6] = Outer space\n"); } else { printf(" [6] = x%lx %d\n", (uintptr_t)(prttet.tet), prttet.loc); } decode(sface->sh[7], prttet); if (prttet.tet == dummytet) { printf(" [7] = Outer space\n"); } else { printf(" [7] = x%lx %d\n", (uintptr_t)(prttet.tet), prttet.loc); } sdecode(sface->sh[8], prtsh); if (prtsh.sh == dummysh) { printf(" [8] = No subsegment\n"); } else { printf(" [8] = x%lx %d\n", (uintptr_t)(prtsh.sh), prtsh.shver); } sdecode(sface->sh[9], prtsh); if (prtsh.sh == dummysh) { printf(" [9] = No subsegment\n"); } else { printf(" [9] = x%lx %d\n", (uintptr_t)(prtsh.sh), prtsh.shver); } sdecode(sface->sh[10], prtsh); if (prtsh.sh == dummysh) { printf(" [10]= No subsegment\n"); } else { printf(" [10]= x%lx %d\n", (uintptr_t)(prtsh.sh), prtsh.shver); } } } //// //// //// //// //// prim_cxx ///////////////////////////////////////////////////////////////// //// mempool_cxx ////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // restart() Deallocate all objects in this pool. // // // // The pool returns to a fresh state, like after it was initialized, except // // that no memory is freed to the operating system. Rather, the previously // // allocated blocks are ready to be used. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::arraypool::restart() { objects = 0l; } /////////////////////////////////////////////////////////////////////////////// // // // poolinit() Initialize an arraypool for allocation of objects. // // // // Before the pool may be used, it must be initialized by this procedure. // // After initialization, memory can be allocated and freed in this pool. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::arraypool::poolinit(int sizeofobject, int log2objperblk) { // Each object must be at least one byte long. objectbytes = sizeofobject > 1 ? sizeofobject : 1; log2objectsperblock = log2objperblk; // Compute the number of objects in each block. objectsperblock = ((int) 1) << log2objectsperblock; // No memory has been allocated. totalmemory = 0l; // The top array has not been allocated yet. toparray = (char **) NULL; toparraylen = 0; // Ready all indices to be allocated. restart(); } /////////////////////////////////////////////////////////////////////////////// // // // arraypool() The constructor and destructor. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::arraypool::arraypool(int sizeofobject, int log2objperblk) { poolinit(sizeofobject, log2objperblk); } tetgenmesh::arraypool::~arraypool() { int i; // Has anything been allocated at all? if (toparray != (char **) NULL) { // Walk through the top array. for (i = 0; i < toparraylen; i++) { // Check every pointer; NULLs may be scattered randomly. if (toparray[i] != (char *) NULL) { // Free an allocated block. free((void *) toparray[i]); } } // Free the top array. free((void *) toparray); } // The top array is no longer allocated. toparray = (char **) NULL; toparraylen = 0; objects = 0; totalmemory = 0; } /////////////////////////////////////////////////////////////////////////////// // // // getblock() Return (and perhaps create) the block containing the object // // with a given index. // // // // This function takes care of allocating or resizing the top array if nece- // // ssary, and of allocating the block if it hasn't yet been allocated. // // // // Return a pointer to the beginning of the block (NOT the object). // // // /////////////////////////////////////////////////////////////////////////////// char* tetgenmesh::arraypool::getblock(int objectindex) { char **newarray; char *block; int newsize; int topindex; int i; // Compute the index in the top array (upper bits). topindex = objectindex >> log2objectsperblock; // Does the top array need to be allocated or resized? if (toparray == (char **) NULL) { // Allocate the top array big enough to hold 'topindex', and NULL out // its contents. newsize = topindex + 128; toparray = (char **) malloc((size_t) (newsize * sizeof(char *))); toparraylen = newsize; for (i = 0; i < newsize; i++) { toparray[i] = (char *) NULL; } // Account for the memory. totalmemory = newsize * (unsigned long) sizeof(char *); } else if (topindex >= toparraylen) { // Resize the top array, making sure it holds 'topindex'. newsize = 3 * toparraylen; if (topindex >= newsize) { newsize = topindex + 128; } // Allocate the new array, copy the contents, NULL out the rest, and // free the old array. newarray = (char **) malloc((size_t) (newsize * sizeof(char *))); for (i = 0; i < toparraylen; i++) { newarray[i] = toparray[i]; } for (i = toparraylen; i < newsize; i++) { newarray[i] = (char *) NULL; } free(toparray); // Account for the memory. totalmemory += (newsize - toparraylen) * sizeof(char *); toparray = newarray; toparraylen = newsize; } // Find the block, or learn that it hasn't been allocated yet. block = toparray[topindex]; if (block == (char *) NULL) { // Allocate a block at this index. block = (char *) malloc((size_t) (objectsperblock * objectbytes)); toparray[topindex] = block; // Account for the memory. totalmemory += objectsperblock * objectbytes; } // Return a pointer to the block. return block; } /////////////////////////////////////////////////////////////////////////////// // // // lookup() Return the pointer to the object with a given index, or NULL // // if the object's block doesn't exist yet. // // // /////////////////////////////////////////////////////////////////////////////// void* tetgenmesh::arraypool::lookup(int objectindex) { char *block; int topindex; // Has the top array been allocated yet? if (toparray == (char **) NULL) { return (void *) NULL; } // Compute the index in the top array (upper bits). topindex = objectindex >> log2objectsperblock; // Does the top index fit in the top array? if (topindex >= toparraylen) { return (void *) NULL; } // Find the block, or learn that it hasn't been allocated yet. block = toparray[topindex]; if (block == (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 *)(block + (objectindex & (objectsperblock - 1)) * objectbytes); } /////////////////////////////////////////////////////////////////////////////// // // // newindex() Allocate space for a fresh object from the pool. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::arraypool::newindex(void **newptr) { void *newobject; int newindex; // Allocate an object at index 'firstvirgin'. newindex = objects; newobject = (void *) (getblock(objects) + (objects & (objectsperblock - 1)) * objectbytes); objects++; // If 'newptr' is not NULL, use it to return a pointer to the object. if (newptr != (void **) NULL) { *newptr = newobject; } return newindex; } /////////////////////////////////////////////////////////////////////////////// // // // listinit() Initialize a list for storing a data type. // // // // Determine the size of each item, set the maximum size allocated at onece, // // set the expand size in case the list is full, and set the linear order // // function if it is provided (default is NULL). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::list::listinit(int itbytes, compfunc pcomp, int mitems, int exsize) { itembytes = itbytes; comp = pcomp; maxitems = mitems; expandsize = exsize; base = (char *) malloc(maxitems * itembytes); if (base == (char *) NULL) { terminatetetgen(1); } items = 0; } /////////////////////////////////////////////////////////////////////////////// // // // append() Add a new item at the end of the list. // // // // A new space at the end of this list will be allocated for storing the new // // item. If the memory is not sufficient, reallocation will be performed. If // // 'appitem' is not NULL, the contents of this pointer will be copied to the // // new allocated space. Returns the pointer to the new allocated space. // // // /////////////////////////////////////////////////////////////////////////////// void* tetgenmesh::list::append(void *appitem) { // Do we have enough space? if (items == maxitems) { char* newbase = (char *) realloc(base, (maxitems + expandsize) * itembytes); if (newbase == (char *) NULL) { terminatetetgen(1); } base = newbase; maxitems += expandsize; } if (appitem != (void *) NULL) { memcpy(base + items * itembytes, appitem, itembytes); } items++; return (void *) (base + (items - 1) * itembytes); } /////////////////////////////////////////////////////////////////////////////// // // // insert() Insert an item before 'pos' (range from 0 to items - 1). // // // // A new space will be inserted at the position 'pos', that is, items lie // // after pos (including the item at pos) will be moved one space downwords. // // If 'insitem' is not NULL, its contents will be copied into the new // // inserted space. Return a pointer to the new inserted space. // // // /////////////////////////////////////////////////////////////////////////////// void* tetgenmesh::list::insert(int pos, void* insitem) { if (pos >= items) { return append(insitem); } // Do we have enough space. if (items == maxitems) { char* newbase = (char *) realloc(base, (maxitems + expandsize) * itembytes); if (newbase == (char *) NULL) { terminatetetgen(1); } base = newbase; maxitems += expandsize; } // Do block move. memmove(base + (pos + 1) * itembytes, // dest base + pos * itembytes, // src (items - pos) * itembytes); // size in bytes // Insert the item. if (insitem != (void *) NULL) { memcpy(base + pos * itembytes, insitem, itembytes); } items++; return (void *) (base + pos * itembytes); } /////////////////////////////////////////////////////////////////////////////// // // // del() Delete an item at 'pos' (range from 0 to items - 1). // // // // The space at 'pos' will be overlapped by other item. If 'order' is 1, the // // remaining items of the list have the same order as usual, i.e., items lie // // after pos will be moved one space upwords. If 'order' is 0, the last item // // of the list will be moved up to pos. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::list::del(int pos, int order) { // If 'pos' is the last item of the list, nothing need to do. if (pos >= 0 && pos < items - 1) { if (order == 1) { // Do block move. memmove(base + pos * itembytes, // dest base + (pos + 1) * itembytes, // src (items - pos - 1) * itembytes); } else { // Use the last item to overlap the del item. memcpy(base + pos * itembytes, // item at pos base + (items - 1) * itembytes, // item at last itembytes); } } if (items > 0) { items--; } } /////////////////////////////////////////////////////////////////////////////// // // // hasitem() Search in this list to find if 'checkitem' exists. // // // // This routine assumes that a linear order function has been set. It loops // // through the entire list, compares each item to 'checkitem'. If it exists, // // return its position (between 0 to items - 1), otherwise, return -1. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::list::hasitem(void* checkitem) { int i; for (i = 0; i < items; i++) { if (comp != (compfunc) NULL) { if ((* comp)((void *)(base + i * itembytes), checkitem) == 0) { return i; } } } return -1; } /////////////////////////////////////////////////////////////////////////////// // // // memorypool() The constructors of memorypool. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::memorypool::memorypool() { firstblock = nowblock = (void **) NULL; nextitem = (void *) NULL; deaditemstack = (void *) NULL; pathblock = (void **) NULL; pathitem = (void *) NULL; itemwordtype = POINTER; alignbytes = 0; itembytes = itemwords = 0; itemsperblock = 0; items = maxitems = 0l; unallocateditems = 0; pathitemsleft = 0; } tetgenmesh::memorypool:: memorypool(int bytecount, int itemcount, enum wordtype wtype, int alignment) { poolinit(bytecount, itemcount, wtype, alignment); } /////////////////////////////////////////////////////////////////////////////// // // // ~memorypool() Free to the operating system all memory taken by a pool. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::memorypool::~memorypool() { while (firstblock != (void **) NULL) { nowblock = (void **) *(firstblock); free(firstblock); firstblock = nowblock; } } /////////////////////////////////////////////////////////////////////////////// // // // poolinit() Initialize a pool of memory for allocation of items. // // // // A `pool' is created whose records have size at least `bytecount'. Items // // will be allocated in `itemcount'-item blocks. Each item is assumed to be // // a collection of words, and either pointers or floating-point values are // // assumed to be the "primary" word type. (The "primary" word type is used // // to determine alignment of items.) If `alignment' isn't zero, all items // // will be `alignment'-byte aligned in memory. `alignment' must be either a // // multiple or a factor of the primary word size; powers of two are safe. // // `alignment' is normally used to create a few unused bits at the bottom of // // each item's pointer, in which information may be stored. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::memorypool:: poolinit(int bytecount, int itemcount, enum wordtype wtype, int alignment) { int wordsize; // Initialize values in the pool. itemwordtype = wtype; wordsize = (itemwordtype == POINTER) ? sizeof(void *) : sizeof(REAL); // Find the proper alignment, which must be at least as large as: // - The parameter `alignment'. // - The primary word type, to avoid unaligned accesses. // - sizeof(void *), so the stack of dead items can be maintained // without unaligned accesses. if (alignment > wordsize) { alignbytes = alignment; } else { alignbytes = wordsize; } if ((int) sizeof(void *) > alignbytes) { alignbytes = (int) sizeof(void *); } itemwords = ((bytecount + alignbytes - 1) / alignbytes) * (alignbytes / wordsize); itembytes = itemwords * wordsize; itemsperblock = itemcount; // Allocate a block of items. Space for `itemsperblock' items and one // pointer (to point to the next block) are allocated, as well as space // to ensure alignment of the items. firstblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) + alignbytes); if (firstblock == (void **) NULL) { terminatetetgen(1); } // Set the next block pointer to NULL. *(firstblock) = (void *) NULL; restart(); } /////////////////////////////////////////////////////////////////////////////// // // // restart() Deallocate all items in this pool. // // // // The pool is returned to its starting state, except that no memory is // // freed to the operating system. Rather, the previously allocated blocks // // are ready to be reused. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::memorypool::restart() { // unsigned long alignptr; uintptr_t alignptr; items = 0; maxitems = 0; // Set the currently active block. nowblock = firstblock; // Find the first item in the pool. Increment by the size of (void *). // alignptr = (unsigned long) (nowblock + 1); alignptr = (uintptr_t) (nowblock + 1); // Align the item on an `alignbytes'-byte boundary. // nextitem = (void *) // (alignptr + (unsigned long) alignbytes - // (alignptr % (unsigned long) alignbytes)); nextitem = (void *) (alignptr + (uintptr_t) alignbytes - (alignptr % (uintptr_t) alignbytes)); // There are lots of unallocated items left in this block. unallocateditems = itemsperblock; // The stack of deallocated items is empty. deaditemstack = (void *) NULL; } /////////////////////////////////////////////////////////////////////////////// // // // alloc() Allocate space for an item. // // // /////////////////////////////////////////////////////////////////////////////// void* tetgenmesh::memorypool::alloc() { void *newitem; void **newblock; // unsigned long alignptr; uintptr_t alignptr; // First check the linked list of dead items. If the list is not // empty, allocate an item from the list rather than a fresh one. if (deaditemstack != (void *) NULL) { newitem = deaditemstack; // Take first item in list. deaditemstack = * (void **) deaditemstack; } else { // Check if there are any free items left in the current block. if (unallocateditems == 0) { // Check if another block must be allocated. if (*nowblock == (void *) NULL) { // Allocate a new block of items, pointed to by the previous block. newblock = (void **) malloc(itemsperblock * itembytes + sizeof(void *) + alignbytes); if (newblock == (void **) NULL) { terminatetetgen(1); } *nowblock = (void *) newblock; // The next block pointer is NULL. *newblock = (void *) NULL; } // Move to the new block. nowblock = (void **) *nowblock; // Find the first item in the block. // Increment by the size of (void *). // alignptr = (unsigned long) (nowblock + 1); alignptr = (uintptr_t) (nowblock + 1); // Align the item on an `alignbytes'-byte boundary. // nextitem = (void *) // (alignptr + (unsigned long) alignbytes - // (alignptr % (unsigned long) alignbytes)); nextitem = (void *) (alignptr + (uintptr_t) alignbytes - (alignptr % (uintptr_t) alignbytes)); // There are lots of unallocated items left in this block. unallocateditems = itemsperblock; } // Allocate a new item. newitem = nextitem; // Advance `nextitem' pointer to next free item in block. if (itemwordtype == POINTER) { nextitem = (void *) ((void **) nextitem + itemwords); } else { nextitem = (void *) ((REAL *) nextitem + itemwords); } unallocateditems--; maxitems++; } items++; return newitem; } /////////////////////////////////////////////////////////////////////////////// // // // dealloc() Deallocate space for an item. // // // // The deallocated space is stored in a queue for later reuse. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::memorypool::dealloc(void *dyingitem) { // Push freshly killed item onto stack. *((void **) dyingitem) = deaditemstack; deaditemstack = dyingitem; items--; } /////////////////////////////////////////////////////////////////////////////// // // // traversalinit() Prepare to traverse the entire list of items. // // // // This routine is used in conjunction with traverse(). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::memorypool::traversalinit() { // unsigned long alignptr; uintptr_t alignptr; // Begin the traversal in the first block. pathblock = firstblock; // Find the first item in the block. Increment by the size of (void *). // alignptr = (unsigned long) (pathblock + 1); alignptr = (uintptr_t) (pathblock + 1); // Align with item on an `alignbytes'-byte boundary. // pathitem = (void *) // (alignptr + (unsigned long) alignbytes - // (alignptr % (unsigned long) alignbytes)); pathitem = (void *) (alignptr + (uintptr_t) alignbytes - (alignptr % (uintptr_t) alignbytes)); // Set the number of items left in the current block. pathitemsleft = itemsperblock; } /////////////////////////////////////////////////////////////////////////////// // // // traverse() Find the next item in the list. // // // // This routine is used in conjunction with traversalinit(). Be forewarned // // that this routine successively returns all items in the list, including // // deallocated ones on the deaditemqueue. It's up to you to figure out which // // ones are actually dead. It can usually be done more space-efficiently by // // a routine that knows something about the structure of the item. // // // /////////////////////////////////////////////////////////////////////////////// void* tetgenmesh::memorypool::traverse() { void *newitem; // unsigned long alignptr; uintptr_t alignptr; // Stop upon exhausting the list of items. if (pathitem == nextitem) { return (void *) NULL; } // Check whether any untraversed items remain in the current block. if (pathitemsleft == 0) { // Find the next block. pathblock = (void **) *pathblock; // Find the first item in the block. Increment by the size of (void *). // alignptr = (unsigned long) (pathblock + 1); alignptr = (uintptr_t) (pathblock + 1); // Align with item on an `alignbytes'-byte boundary. // pathitem = (void *) // (alignptr + (unsigned long) alignbytes - // (alignptr % (unsigned long) alignbytes)); pathitem = (void *) (alignptr + (uintptr_t) alignbytes - (alignptr % (uintptr_t) alignbytes)); // Set the number of items left in the current block. pathitemsleft = itemsperblock; } newitem = pathitem; // Find the next item in the block. if (itemwordtype == POINTER) { pathitem = (void *) ((void **) pathitem + itemwords); } else { pathitem = (void *) ((REAL *) pathitem + itemwords); } pathitemsleft--; return newitem; } /////////////////////////////////////////////////////////////////////////////// // // // makepoint2tetmap() Construct a mapping from points to tetrahedra. // // // // Traverses all the tetrahedra, provides each corner of each tetrahedron // // with a pointer to that tetrahedera. Some pointers will be overwritten by // // other pointers because each point may be a corner of several tetrahedra, // // but in the end every point will point to a tetrahedron that contains it. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::makepoint2tetmap() { triface tetloop; point pointptr; if (b->verbose > 2) { printf(" Constructing mapping from points to tetrahedra.\n"); } // Initialize the point2tet field of each point. points->traversalinit(); pointptr = pointtraverse(); while (pointptr != (point) NULL) { setpoint2tet(pointptr, (tetrahedron) NULL); pointptr = pointtraverse(); } tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Check all four points of the tetrahedron. tetloop.loc = 0; pointptr = org(tetloop); setpoint2tet(pointptr, encode(tetloop)); pointptr = dest(tetloop); setpoint2tet(pointptr, encode(tetloop)); pointptr = apex(tetloop); setpoint2tet(pointptr, encode(tetloop)); pointptr = oppo(tetloop); setpoint2tet(pointptr, encode(tetloop)); // Get the next tetrahedron in the list. tetloop.tet = tetrahedrontraverse(); } } void tetgenmesh::makepoint2segmap() { face segloop; point *ppt; if (b->verbose > 2) { printf(" Constructing mapping from points to segments.\n"); } segloop.shver = 0; subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != NULL) { ppt = (point *) &(segloop.sh[3]); setpoint2seg(ppt[0], sencode(segloop)); setpoint2seg(ppt[1], sencode(segloop)); segloop.sh = shellfacetraverse(subsegs); } } /////////////////////////////////////////////////////////////////////////////// // // // makeindex2pointmap() Create a map from index to vertices. // // // // 'idx2verlist' returns the created map. Traverse all vertices, a pointer // // to each vertex is set into the array. The pointer to the first vertex is // // saved in 'idx2verlist[0]'. Don't forget to minus 'in->firstnumber' when // // to get the vertex form its index. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::makeindex2pointmap(point*& idx2verlist) { point pointloop; int idx; if (b->verbose > 1) { printf(" Constructing mapping from indices to points.\n"); } idx2verlist = new point[points->items]; points->traversalinit(); pointloop = pointtraverse(); idx = 0; while (pointloop != (point) NULL) { idx2verlist[idx] = pointloop; idx++; pointloop = pointtraverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // makesegmentmap(), makesubfacemap(), maketetrahedronmap() // // // // Create a map from vertex indices to segments, subfaces, and tetrahedra // // sharing at the same vertices. // // // // The map is stored in two arrays: 'idx2___list' and '___sperverlist', they // // form a sparse matrix whose size is (n+1)x(n+1), where n is the number of // // segments, subfaces, or tetrahedra. 'idx2___list' contains row information // // and '___sperverlist' contains all non-zero elements. The i-th entry of // // 'idx2___list' is the starting position of i-th row's non-zero elements in // // '___sperverlist'. The number of elements of i-th row is (i+1)-th entry // // minus i-th entry of 'idx2___list'. // // // // NOTE: These two arrays will be created inside this routine, don't forget // // to free them after using. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::makesegmentmap(int*& idx2seglist, shellface**& segsperverlist) { shellface *shloop; int i, j, k; if (b->verbose > 1) { printf(" Constructing mapping from points to segments.\n"); } // Create and initialize 'idx2seglist'. idx2seglist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) idx2seglist[i] = 0; // Loop the set of segments once, counter the number of segments sharing // each vertex. subsegs->traversalinit(); shloop = shellfacetraverse(subsegs); while (shloop != (shellface *) NULL) { // Increment the number of sharing segments for each endpoint. for (i = 0; i < 2; i++) { j = pointmark((point) shloop[3 + i]) - in->firstnumber; idx2seglist[j]++; } shloop = shellfacetraverse(subsegs); } // Calculate the total length of array 'facesperverlist'. j = idx2seglist[0]; idx2seglist[0] = 0; // Array starts from 0 element. for (i = 0; i < points->items; i++) { k = idx2seglist[i + 1]; idx2seglist[i + 1] = idx2seglist[i] + j; j = k; } // The total length is in the last unit of idx2seglist. segsperverlist = new shellface*[idx2seglist[i]]; // Loop the set of segments again, set the info. of segments per vertex. subsegs->traversalinit(); shloop = shellfacetraverse(subsegs); while (shloop != (shellface *) NULL) { for (i = 0; i < 2; i++) { j = pointmark((point) shloop[3 + i]) - in->firstnumber; segsperverlist[idx2seglist[j]] = shloop; idx2seglist[j]++; } shloop = shellfacetraverse(subsegs); } // Contents in 'idx2seglist' are shifted, now shift them back. for (i = points->items - 1; i >= 0; i--) { idx2seglist[i + 1] = idx2seglist[i]; } idx2seglist[0] = 0; } void tetgenmesh::makesubfacemap(int*& idx2facelist, shellface**& facesperverlist) { shellface *shloop; int i, j, k; if (b->verbose > 1) { printf(" Constructing mapping from points to subfaces.\n"); } // Create and initialize 'idx2facelist'. idx2facelist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) idx2facelist[i] = 0; // Loop the set of subfaces once, counter the number of subfaces sharing // each vertex. subfaces->traversalinit(); shloop = shellfacetraverse(subfaces); while (shloop != (shellface *) NULL) { // Increment the number of sharing segments for each endpoint. for (i = 0; i < 3; i++) { j = pointmark((point) shloop[3 + i]) - in->firstnumber; idx2facelist[j]++; } shloop = shellfacetraverse(subfaces); } // Calculate the total length of array 'facesperverlist'. j = idx2facelist[0]; idx2facelist[0] = 0; // Array starts from 0 element. for (i = 0; i < points->items; i++) { k = idx2facelist[i + 1]; idx2facelist[i + 1] = idx2facelist[i] + j; j = k; } // The total length is in the last unit of idx2facelist. facesperverlist = new shellface*[idx2facelist[i]]; // Loop the set of segments again, set the info. of segments per vertex. subfaces->traversalinit(); shloop = shellfacetraverse(subfaces); while (shloop != (shellface *) NULL) { for (i = 0; i < 3; i++) { j = pointmark((point) shloop[3 + i]) - in->firstnumber; facesperverlist[idx2facelist[j]] = shloop; idx2facelist[j]++; } shloop = shellfacetraverse(subfaces); } // Contents in 'idx2facelist' are shifted, now shift them back. for (i = points->items - 1; i >= 0; i--) { idx2facelist[i + 1] = idx2facelist[i]; } idx2facelist[0] = 0; } void tetgenmesh::maketetrahedronmap(int*& idx2tetlist, tetrahedron**& tetsperverlist) { tetrahedron *tetloop; int i, j, k; if (b->verbose > 1) { printf(" Constructing mapping from points to tetrahedra.\n"); } // Create and initialize 'idx2tetlist'. idx2tetlist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) idx2tetlist[i] = 0; // Loop the set of tetrahedra once, counter the number of tetrahedra // sharing each vertex. tetrahedrons->traversalinit(); tetloop = tetrahedrontraverse(); while (tetloop != (tetrahedron *) NULL) { // Increment the number of sharing tetrahedra for each endpoint. for (i = 0; i < 4; i++) { j = pointmark((point) tetloop[4 + i]) - in->firstnumber; idx2tetlist[j]++; } tetloop = tetrahedrontraverse(); } // Calculate the total length of array 'tetsperverlist'. j = idx2tetlist[0]; idx2tetlist[0] = 0; // Array starts from 0 element. for (i = 0; i < points->items; i++) { k = idx2tetlist[i + 1]; idx2tetlist[i + 1] = idx2tetlist[i] + j; j = k; } // The total length is in the last unit of idx2tetlist. tetsperverlist = new tetrahedron*[idx2tetlist[i]]; // Loop the set of tetrahedra again, set the info. of tet. per vertex. tetrahedrons->traversalinit(); tetloop = tetrahedrontraverse(); while (tetloop != (tetrahedron *) NULL) { for (i = 0; i < 4; i++) { j = pointmark((point) tetloop[4 + i]) - in->firstnumber; tetsperverlist[idx2tetlist[j]] = tetloop; idx2tetlist[j]++; } tetloop = tetrahedrontraverse(); } // Contents in 'idx2tetlist' are shifted, now shift them back. for (i = points->items - 1; i >= 0; i--) { idx2tetlist[i + 1] = idx2tetlist[i]; } idx2tetlist[0] = 0; } /////////////////////////////////////////////////////////////////////////////// // // // dummyinit() Initialize the tetrahedron that fills "outer space" and // // the omnipresent subface. // // // // The tetrahedron that fills "outer space" called 'dummytet', is pointed to // // by every tetrahedron and subface on a boundary (be it outer or inner) of // // the tetrahedralization. Also, 'dummytet' points to one of the tetrahedron // // on the convex hull(until the holes and concavities are carved), making it // // possible to find a starting tetrahedron for point location. // // // // The omnipresent subface,'dummysh', is pointed to by every tetrahedron or // // subface that doesn't have a full complement of real subface to point to. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::dummyinit(int tetwords, int shwords) { unsigned long alignptr; // Set up 'dummytet', the 'tetrahedron' that occupies "outer space". dummytetbase = (tetrahedron *) new char[tetwords * sizeof(tetrahedron) + tetrahedrons->alignbytes]; // Align 'dummytet' on a 'tetrahedrons->alignbytes'-byte boundary. alignptr = (unsigned long) dummytetbase; dummytet = (tetrahedron *) (alignptr + (unsigned long) tetrahedrons->alignbytes - (alignptr % (unsigned long) tetrahedrons->alignbytes)); // Initialize the four adjoining tetrahedra to be "outer space". These // will eventually be changed by various bonding operations, but their // values don't really matter, as long as they can legally be // dereferenced. dummytet[0] = (tetrahedron) dummytet; dummytet[1] = (tetrahedron) dummytet; dummytet[2] = (tetrahedron) dummytet; dummytet[3] = (tetrahedron) dummytet; // Four null vertex points. dummytet[4] = (tetrahedron) NULL; dummytet[5] = (tetrahedron) NULL; dummytet[6] = (tetrahedron) NULL; dummytet[7] = (tetrahedron) NULL; if (b->useshelles) { // Set up 'dummysh', the omnipresent "subface" pointed to by any // tetrahedron side or subface end that isn't attached to a real // subface. dummyshbase = (shellface *) new char[shwords * sizeof(shellface) + subfaces->alignbytes]; // Align 'dummysh' on a 'subfaces->alignbytes'-byte boundary. alignptr = (unsigned long) dummyshbase; dummysh = (shellface *) (alignptr + (unsigned long) subfaces->alignbytes - (alignptr % (unsigned long) subfaces->alignbytes)); // Initialize the three adjoining subfaces to be the omnipresent // subface. These will eventually be changed by various bonding // operations, but their values don't really matter, as long as they // can legally be dereferenced. dummysh[0] = (shellface) dummysh; dummysh[1] = (shellface) dummysh; dummysh[2] = (shellface) dummysh; // Three null vertex points. dummysh[3] = (shellface) NULL; dummysh[4] = (shellface) NULL; dummysh[5] = (shellface) NULL; // Initialize the two adjoining tetrahedra to be "outer space". dummysh[6] = (shellface) dummytet; dummysh[7] = (shellface) dummytet; // Initialize the three adjoining subsegments to be "out boundary". dummysh[8] = (shellface) dummysh; dummysh[9] = (shellface) dummysh; dummysh[10] = (shellface) dummysh; // Initialize the pointer to badface structure. dummysh[11] = (shellface) NULL; // Initialize the four adjoining subfaces of 'dummytet' to be the // omnipresent subface. dummytet[8 ] = NULL; dummytet[9 ] = NULL; } } /////////////////////////////////////////////////////////////////////////////// // // // initializepools() Calculate the sizes of the point, tetrahedron, and // // subface. Initialize their memory pools. // // // // This routine also computes the indices 'pointmarkindex', 'point2simindex',// // and 'point2pbcptindex' used to find values within each point; computes // // indices 'highorderindex', 'elemattribindex', and 'volumeboundindex' used // // to find values within each tetrahedron. // // // // There are two types of boundary elements, which are subfaces and subsegs, // // they are stored in seperate pools. However, the data structures of them // // are the same. A subsegment can be regarded as a degenerate subface, i.e.,// // one of its three corners is not used. We set the apex of it be 'NULL' to // // distinguish it's a subsegment. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::initializepools() { enum wordtype wtype; int pointsize, elesize, shsize; // Default checkpbc = 0; if ((b->plc || b->refine) && (in->pbcgrouplist != NULL)) { checkpbcs = 1; } // Default varconstraint = 0; if (in->segmentconstraintlist || in->facetconstraintlist) { varconstraint = 1; } // The index within each point at which its metric tensor is found. It is // saved directly after the list of point attributes. pointmtrindex = 3 + in->numberofpointattributes; // Decide the size (1, 3, or 6) of the metric tensor. if (b->metric) { // For '-m' option. A tensor field is provided (*.mtr or *.b.mtr file). if (bgm != (tetgenmesh *) NULL) { // A background mesh is allocated. It may not exist though. sizeoftensor = (bgm->in != (tetgenio *) NULL) ? bgm->in->numberofpointmtrs : in->numberofpointmtrs; } else { // No given background mesh - Itself is a background mesh. sizeoftensor = in->numberofpointmtrs; } // Make sure sizeoftensor is at least 1. sizeoftensor = (sizeoftensor > 0) ? sizeoftensor : 1; } else { // For '-q' option. Make sure to have space for saving a scalar value. sizeoftensor = b->quality ? 1 : 0; } // The index within each point at which an element pointer is found, where // the index is measured in pointers. Ensure the index is aligned to a // sizeof(tetrahedron)-byte address. point2simindex = ((pointmtrindex + sizeoftensor) * sizeof(REAL) + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); if (b->plc || b->refine || b->voroout) { // Increase the point size by four pointers, which are: // - a pointer to a tet, read by point2tet(); // - a pointer to a subface, read by point2sh(); // - a pointer to a subsegment, read by point2seg(); // - a pointer to a parent point, read by point2ppt()). if (b->metric) { // Increase one pointer to a tet of the background mesh. pointsize = (point2simindex + 5) * sizeof(tetrahedron); } else { pointsize = (point2simindex + 4) * sizeof(tetrahedron); } // The index within each point at which a pbc point is found. point2pbcptindex = (pointsize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); if (checkpbcs) { // Increase the size by one pointer to a corresponding pbc point, // read by point2pbcpt(). pointsize = (point2pbcptindex + 1) * sizeof(tetrahedron); } } else { // Increase the point size by one pointer, which is: // - a pointer to a tet, read by point2tet(); pointsize = (point2simindex + 1) * sizeof(tetrahedron); } // The index within each point at which the boundary marker is found, // Ensure the point marker is aligned to a sizeof(int)-byte address. pointmarkindex = (pointsize + sizeof(int) - 1) / sizeof(int); // Now point size is the ints (inidcated by pointmarkindex) plus: // - an integer for boundary marker; // - an integer for vertex type; pointsize = (pointmarkindex + 2) * sizeof(int); // Decide the wordtype used in vertex pool. wtype = (sizeof(REAL) >= sizeof(tetrahedron)) ? FLOATINGPOINT : POINTER; // Initialize the pool of vertices. points = new memorypool(pointsize, VERPERBLOCK, wtype, 0); if (b->useshelles) { dummypoint = (point) new char[pointsize]; // For abovepoint. } // The number of bytes occupied by a tetrahedron. There are four pointers // to other tetrahedra, four pointers to corners, and possibly four // pointers to subfaces (or six pointers to subsegments (used in // segment recovery only)). elesize = (8 + b->useshelles * 2) * sizeof(tetrahedron); // If Voronoi diagram is wanted, make sure we have additional space. if (b->voroout) { elesize = (8 + 4) * sizeof(tetrahedron); } // The index within each element at which its attributes are found, where // the index is measured in REALs. elemattribindex = (elesize + sizeof(REAL) - 1) / sizeof(REAL); // The index within each element at which the maximum voulme bound is // found, where the index is measured in REALs. Note that if the // `b->regionattrib' flag is set, an additional attribute will be added. volumeboundindex = elemattribindex + in->numberoftetrahedronattributes + (b->regionattrib > 0); // If element attributes or an constraint are needed, increase the number // of bytes occupied by an element. if (b->varvolume) { elesize = (volumeboundindex + 1) * sizeof(REAL); } else if (in->numberoftetrahedronattributes + b->regionattrib > 0) { elesize = volumeboundindex * sizeof(REAL); } // If element neighbor graph is requested (-n switch), an additional // integer is allocated for each element. elemmarkerindex = (elesize + sizeof(int) - 1) / sizeof(int); // if (b->neighout || b->voroout) { elesize = (elemmarkerindex + 1) * sizeof(int); // } // If -o2 switch is used, an additional pointer pointed to the list of // higher order nodes is allocated for each element. highorderindex = (elesize + sizeof(tetrahedron) - 1) / sizeof(tetrahedron); if (b->order == 2) { elesize = (highorderindex + 1) * sizeof(tetrahedron); } // Having determined the memory size of an element, initialize the pool. tetrahedrons = new memorypool(elesize, ELEPERBLOCK, POINTER, 8); if (b->useshelles) { // The number of bytes occupied by a subface. The list of pointers // stored in a subface are: three to other subfaces, three to corners, // three to subsegments, two to tetrahedra, and one to a badface. shsize = 12 * sizeof(shellface); // The index within each subface at which the maximum area bound is // found, where the index is measured in REALs. areaboundindex = (shsize + sizeof(REAL) - 1) / sizeof(REAL); // If -q switch is in use, increase the number of bytes occupied by // a subface for saving maximum area bound. if (b->quality && varconstraint) { shsize = (areaboundindex + 1) * sizeof(REAL); } else { shsize = areaboundindex * sizeof(REAL); } // The index within subface at which the facet marker is found. Ensure // the marker is aligned to a sizeof(int)-byte address. shmarkindex = (shsize + sizeof(int) - 1) / sizeof(int); // Increase the number of bytes by two or three integers, one for facet // marker, one for shellface type, and optionally one for pbc group. shsize = (shmarkindex + 2 + checkpbcs) * sizeof(int); // Initialize the pool of subfaces. Each subface record is eight-byte // aligned so it has room to store an edge version (from 0 to 5) in // the least three bits. subfaces = new memorypool(shsize, SUBPERBLOCK, POINTER, 8); // Initialize the pool of subsegments. The subsegment's record is same // with subface. subsegs = new memorypool(shsize, SUBPERBLOCK, POINTER, 8); // Initialize the pool for tet-subseg connections. tet2segpool = new memorypool(6*sizeof(shellface), SUBPERBLOCK, POINTER, 0); // Initialize the pool for tet-subface connections. tet2subpool = new memorypool(4*sizeof(shellface), SUBPERBLOCK, POINTER, 0); // Initialize arraypools for segment & facet recovery. subsegstack = new arraypool(sizeof(face), 10); subfacstack = new arraypool(sizeof(face), 10); // Initialize the "outer space" tetrahedron and omnipresent subface. dummyinit(tetrahedrons->itemwords, subfaces->itemwords); } else { // Initialize the "outer space" tetrahedron. dummyinit(tetrahedrons->itemwords, 0); } } /////////////////////////////////////////////////////////////////////////////// // // // tetrahedrondealloc() Deallocate space for a tet., marking it dead. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::tetrahedrondealloc(tetrahedron *dyingtetrahedron) { // Set tetrahedron's vertices to NULL. This makes it possible to detect // dead tetrahedra when traversing the list of all tetrahedra. dyingtetrahedron[4] = (tetrahedron) NULL; // dyingtetrahedron[5] = (tetrahedron) NULL; // dyingtetrahedron[6] = (tetrahedron) NULL; dyingtetrahedron[7] = (tetrahedron) NULL; if (b->useshelles) { // Dealloc the space to subfaces/subsegments. if (dyingtetrahedron[8] != NULL) { tet2segpool->dealloc((shellface *) dyingtetrahedron[8]); } if (dyingtetrahedron[9] != NULL) { tet2subpool->dealloc((shellface *) dyingtetrahedron[9]); } } tetrahedrons->dealloc((void *) dyingtetrahedron); } /////////////////////////////////////////////////////////////////////////////// // // // tetrahedrontraverse() Traverse the tetrahedra, skipping dead ones. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::tetrahedron* tetgenmesh::tetrahedrontraverse() { tetrahedron *newtetrahedron; do { newtetrahedron = (tetrahedron *) tetrahedrons->traverse(); if (newtetrahedron == (tetrahedron *) NULL) { return (tetrahedron *) NULL; } } while (newtetrahedron[7] == (tetrahedron) NULL); // Skip dead ones. return newtetrahedron; } /////////////////////////////////////////////////////////////////////////////// // // // shellfacedealloc() Deallocate space for a shellface, marking it dead. // // Used both for dealloc a subface and subsegment. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::shellfacedealloc(memorypool *pool, shellface *dyingsh) { // Set shellface's vertices to NULL. This makes it possible to detect dead // shellfaces when traversing the list of all shellfaces. dyingsh[3] = (shellface) NULL; dyingsh[4] = (shellface) NULL; dyingsh[5] = (shellface) NULL; pool->dealloc((void *) dyingsh); } /////////////////////////////////////////////////////////////////////////////// // // // shellfacetraverse() Traverse the subfaces, skipping dead ones. Used // // for both subfaces and subsegments pool traverse. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::shellface* tetgenmesh::shellfacetraverse(memorypool *pool) { shellface *newshellface; do { newshellface = (shellface *) pool->traverse(); if (newshellface == (shellface *) NULL) { return (shellface *) NULL; } } while (newshellface[3] == (shellface) NULL); // Skip dead ones. return newshellface; } /////////////////////////////////////////////////////////////////////////////// // // // badfacedealloc() Deallocate space for a badface, marking it dead. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::badfacedealloc(memorypool *pool, badface *dying) { // Set badface's forg to NULL. This makes it possible to detect dead // ones when traversing the list of all items. dying->forg = (point) NULL; pool->dealloc((void *) dying); } /////////////////////////////////////////////////////////////////////////////// // // // badfacetraverse() Traverse the pools, skipping dead ones. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::badface* tetgenmesh::badfacetraverse(memorypool *pool) { badface *newsh; do { newsh = (badface *) pool->traverse(); if (newsh == (badface *) NULL) { return (badface *) NULL; } } while (newsh->forg == (point) NULL); // Skip dead ones. return newsh; } /////////////////////////////////////////////////////////////////////////////// // // // pointdealloc() Deallocate space for a point, marking it dead. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::pointdealloc(point dyingpoint) { // Mark the point as dead. This makes it possible to detect dead points // when traversing the list of all points. setpointtype(dyingpoint, DEADVERTEX); points->dealloc((void *) dyingpoint); } /////////////////////////////////////////////////////////////////////////////// // // // pointtraverse() Traverse the points, skipping dead ones. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::point tetgenmesh::pointtraverse() { point newpoint; do { newpoint = (point) points->traverse(); if (newpoint == (point) NULL) { return (point) NULL; } } while (pointtype(newpoint) == DEADVERTEX); // Skip dead ones. return newpoint; } /////////////////////////////////////////////////////////////////////////////// // // // maketetrahedron() Create a new tetrahedron. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::maketetrahedron(triface *newtet) { newtet->tet = (tetrahedron *) tetrahedrons->alloc(); // Initialize the four adjoining tetrahedra to be "outer space". newtet->tet[0] = (tetrahedron) dummytet; newtet->tet[1] = (tetrahedron) dummytet; newtet->tet[2] = (tetrahedron) dummytet; newtet->tet[3] = (tetrahedron) dummytet; // Four NULL vertices. newtet->tet[4] = (tetrahedron) NULL; newtet->tet[5] = (tetrahedron) NULL; newtet->tet[6] = (tetrahedron) NULL; newtet->tet[7] = (tetrahedron) NULL; // Initialize the four adjoining subfaces to be the omnipresent subface. if (b->useshelles) { newtet->tet[8 ] = NULL; newtet->tet[9 ] = NULL; } for (int i = 0; i < in->numberoftetrahedronattributes; i++) { setelemattribute(newtet->tet, i, 0.0); } if (b->varvolume) { setvolumebound(newtet->tet, -1.0); } // Initialize the marker (for flags). setelemmarker(newtet->tet, 0); // Initialize the location and version to be Zero. newtet->loc = 0; newtet->ver = 0; } /////////////////////////////////////////////////////////////////////////////// // // // makeshellface() Create a new shellface with version zero. Used for // // both subfaces and seusegments. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::makeshellface(memorypool *pool, face *newface) { newface->sh = (shellface *) pool->alloc(); //Initialize the three adjoining subfaces to be the omnipresent subface. newface->sh[0] = (shellface) dummysh; newface->sh[1] = (shellface) dummysh; newface->sh[2] = (shellface) dummysh; // Three NULL vertices. newface->sh[3] = (shellface) NULL; newface->sh[4] = (shellface) NULL; newface->sh[5] = (shellface) NULL; // Initialize the two adjoining tetrahedra to be "outer space". newface->sh[6] = (shellface) dummytet; newface->sh[7] = (shellface) dummytet; // Initialize the three adjoining subsegments to be the omnipresent // subsegments. newface->sh [8] = (shellface) dummysh; newface->sh [9] = (shellface) dummysh; newface->sh[10] = (shellface) dummysh; // Initialize the pointer to badface structure. newface->sh[11] = (shellface) NULL; if (b->quality && varconstraint) { // Initialize the maximum area bound. setareabound(*newface, 0.0); } // Clear the infection and marktest bits. suninfect(*newface); sunmarktest(*newface); // Set the boundary marker to zero. setshellmark(*newface, 0); // Set the type. setshelltype(*newface, NSHARP); if (checkpbcs) { // Set the pbcgroup be ivalid. setshellpbcgroup(*newface, -1); } // Initialize the version to be Zero. newface->shver = 0; } /////////////////////////////////////////////////////////////////////////////// // // // makepoint() Create a new point. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::makepoint(point* pnewpoint) { int ptmark, i; *pnewpoint = (point) points->alloc(); // Initialize three coordinates. (*pnewpoint)[0] = 0.0; (*pnewpoint)[1] = 0.0; (*pnewpoint)[2] = 0.0; // Initialize the list of user-defined attributes. for (i = 0; i < in->numberofpointattributes; i++) { (*pnewpoint)[3 + i] = 0.0; } // Initialize the metric tensor. for (i = 0; i < sizeoftensor; i++) { (*pnewpoint)[pointmtrindex + i] = 0.0; } if (b->plc || b->refine) { // Initialize the point-to-simplex filed. setpoint2tet(*pnewpoint, NULL); setpoint2sh(*pnewpoint, NULL); setpoint2seg(*pnewpoint, NULL); setpoint2ppt(*pnewpoint, NULL); if (b->metric) { setpoint2bgmtet(*pnewpoint, NULL); } if (checkpbcs) { // Initialize the other pointer to its pbc point. setpoint2pbcpt(*pnewpoint, NULL); } } // Initialize the point marker (starting from in->firstnumber). ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); setpointmark(*pnewpoint, ptmark); // Initialize the point type. setpointtype(*pnewpoint, UNUSEDVERTEX); } //// //// //// //// //// mempool_cxx ////////////////////////////////////////////////////////////// //// geom_cxx ///////////////////////////////////////////////////////////////// //// //// //// //// // PI is the ratio of a circle's circumference to its diameter. REAL tetgenmesh::PI = 3.14159265358979323846264338327950288419716939937510582; /////////////////////////////////////////////////////////////////////////////// // // // Triangle-triangle intersection test // // // // The triangle-triangle intersection test is implemented with exact arithm- // // etic. It exactly tells whether or not two triangles in three dimensions // // intersect. Before implementing this test myself, I tried two C codes // // (implemented by Thomas Moeller and Philippe Guigue, respectively), which // // are all public available. However both of them failed frequently. Another // // unconvenience is both codes only tell whether or not the two triangles // // intersect without distinguishing the cases whether they exactly intersect // // in interior or they just share a vertex or share an edge. The two latter // // cases are acceptable and should return not intersection in TetGen. // // // /////////////////////////////////////////////////////////////////////////////// // All the following routines require the input objects are not degenerate. // i.e., a triangle must has three non-collinear corners; an edge must // has two identical endpoints. Degenerate cases should have to detect // first and then handled as special cases. /////////////////////////////////////////////////////////////////////////////// // // // edge_vert_col_inter() Test whether an edge (ab) and a collinear vertex // // (p) are intersecting or not. // // // // Possible cases are p is coincident to a (p = a), or to b (p = b), or p is // // inside ab (a < p < b), or outside ab (p < a or p > b). These cases can be // // quickly determined by comparing the corresponding coords of a, b, and p // // (which are not all equal). // // // // The return value indicates one of the three cases: DISJOINT, SHAREVERTEX // // (p = a or p = b), and INTERSECT (a < p < b). // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::edge_vert_col_inter(REAL* A, REAL* B, REAL* P) { int i = 0; do { if (A[i] < B[i]) { if (P[i] < A[i]) { return DISJOINT; } else if (P[i] > A[i]) { if (P[i] < B[i]) { return INTERSECT; } else if (P[i] > B[i]) { return DISJOINT; } else { // assert(P[i] == B[i]); return SHAREVERTEX; } } else { // assert(P[i] == A[i]); return SHAREVERTEX; } } else if (A[i] > B[i]) { if (P[i] < B[i]) { return DISJOINT; } else if (P[i] > B[i]) { if (P[i] < A[i]) { return INTERSECT; } else if (P[i] > A[i]) { return DISJOINT; } else { // assert(P[i] == A[i]); return SHAREVERTEX; } } else { // assert(P[i] == B[i]); return SHAREVERTEX; } } // i-th coordinates are equal, try i+1-th; i++; } while (i < 3); // Should never be here. return DISJOINT; } /////////////////////////////////////////////////////////////////////////////// // // // edge_edge_cop_inter() Test whether two coplanar edges (ab, and pq) are // // intersecting or not. // // // // Possible cases are ab and pq are disjointed, or proper intersecting (int- // // ersect at a point other than their endpoints), or both collinear and int- // // ersecting, or sharing at a common endpoint, or are coincident. // // // // A reference point R is required, which is exactly not coplanar with these // // two edges. Since the caller knows these two edges are coplanar, it must // // be able to provide (or calculate) such a point. // // // // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // // SHAREEDGE, and INTERSECT. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh:: edge_edge_cop_inter(REAL* A, REAL* B, REAL* P, REAL* Q, REAL* R) { REAL s1, s2, s3, s4; #ifdef SELF_CHECK assert(R != NULL); #endif s1 = orient3d(A, B, R, P); s2 = orient3d(A, B, R, Q); if (s1 * s2 > 0.0) { // Both p and q are at the same side of ab. return DISJOINT; } s3 = orient3d(P, Q, R, A); s4 = orient3d(P, Q, R, B); if (s3 * s4 > 0.0) { // Both a and b are at the same side of pq. return DISJOINT; } // Possible degenerate cases are: // (1) Only one of p and q is collinear with ab; // (2) Both p and q are collinear with ab; // (3) Only one of a and b is collinear with pq. enum interresult abp, abq; enum interresult pqa, pqb; if (s1 == 0.0) { // p is collinear with ab. abp = edge_vert_col_inter(A, B, P); if (abp == INTERSECT) { // p is inside ab. return INTERSECT; } if (s2 == 0.0) { // q is collinear with ab. Case (2). abq = edge_vert_col_inter(A, B, Q); if (abq == INTERSECT) { // q is inside ab. return INTERSECT; } if (abp == SHAREVERTEX && abq == SHAREVERTEX) { // ab and pq are identical. return SHAREEDGE; } pqa = edge_vert_col_inter(P, Q, A); if (pqa == INTERSECT) { // a is inside pq. return INTERSECT; } pqb = edge_vert_col_inter(P, Q, B); if (pqb == INTERSECT) { // b is inside pq. return INTERSECT; } if (abp == SHAREVERTEX || abq == SHAREVERTEX) { // either p or q is coincident with a or b. #ifdef SELF_CHECK // ONLY one case is possible, otherwise, shoule be SHAREEDGE. assert(abp ^ abq); #endif return SHAREVERTEX; } // The last case. They are disjointed. #ifdef SELF_CHECK assert((abp == DISJOINT) && (abp == abq && abq == pqa && pqa == pqb)); #endif return DISJOINT; } else { // p is collinear with ab. Case (1). #ifdef SELF_CHECK assert(abp == SHAREVERTEX || abp == DISJOINT); #endif return abp; } } // p is NOT collinear with ab. if (s2 == 0.0) { // q is collinear with ab. Case (1). abq = edge_vert_col_inter(A, B, Q); #ifdef SELF_CHECK assert(abq == SHAREVERTEX || abq == DISJOINT || abq == INTERSECT); #endif return abq; } // We have found p and q are not collinear with ab. However, it is still // possible that a or b is collinear with pq (ONLY one of a and b). if (s3 == 0.0) { // a is collinear with pq. Case (3). #ifdef SELF_CHECK assert(s4 != 0.0); #endif pqa = edge_vert_col_inter(P, Q, A); #ifdef SELF_CHECK // This case should have been detected in above. assert(pqa != SHAREVERTEX); assert(pqa == INTERSECT || pqa == DISJOINT); #endif return pqa; } if (s4 == 0.0) { // b is collinear with pq. Case (3). #ifdef SELF_CHECK assert(s3 != 0.0); #endif pqb = edge_vert_col_inter(P, Q, B); #ifdef SELF_CHECK // This case should have been detected in above. assert(pqb != SHAREVERTEX); assert(pqb == INTERSECT || pqb == DISJOINT); #endif return pqb; } // ab and pq are intersecting properly. return INTERSECT; } /////////////////////////////////////////////////////////////////////////////// // // // Notations // // // // Let ABC be the plane passes through a, b, and c; ABC+ be the halfspace // // including the set of all points x, such that orient3d(a, b, c, x) > 0; // // ABC- be the other halfspace, such that for each point x in ABC-, // // orient3d(a, b, c, x) < 0. For the set of x which are on ABC, orient3d(a, // // b, c, x) = 0. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // tri_vert_copl_inter() Test whether a triangle (abc) and a coplanar // // point (p) are intersecting or not. // // // // Possible cases are p is inside abc, or on an edge of, or coincident with // // a vertex of, or outside abc. // // // // A reference point R is required. R is exactly not coplanar with abc and p.// // Since the caller knows they are coplanar, it must be able to provide (or // // calculate) such a point. // // // // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // // and INTERSECT. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::tri_vert_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* R) { REAL s1, s2, s3; int sign; #ifdef SELF_CHECK assert(R != (REAL *) NULL); #endif // Adjust the orientation of a, b, c and r, so that we can assume that // r is strictly in ABC- (i.e., r is above ABC wrt. right-hand rule). s1 = orient3d(A, B, C, R); #ifdef SELF_CHECK assert(s1 != 0.0); #endif sign = s1 < 0.0 ? 1 : -1; // Test starts from here. s1 = orient3d(A, B, R, P) * sign; if (s1 < 0.0) { // p is in ABR-. return DISJOINT; } s2 = orient3d(B, C, R, P) * sign; if (s2 < 0.0) { // p is in BCR-. return DISJOINT; } s3 = orient3d(C, A, R, P) * sign; if (s3 < 0.0) { // p is in CAR-. return DISJOINT; } if (s1 == 0.0) { // p is on ABR. if (s2 == 0.0) { // p is on BCR. #ifdef SELF_CHECK assert(s3 > 0.0); #endif // p is coincident with b. return SHAREVERTEX; } if (s3 == 0.0) { // p is on CAR. // p is coincident with a. return SHAREVERTEX; } // p is on edge ab. return INTERSECT; } // p is in ABR+. if (s2 == 0.0) { // p is on BCR. if (s3 == 0.0) { // p is on CAR. // p is coincident with c. return SHAREVERTEX; } // p is on edge bc. return INTERSECT; } if (s3 == 0.0) { // p is on CAR. // p is on edge ca. return INTERSECT; } // p is strictly inside abc. return INTERSECT; } /////////////////////////////////////////////////////////////////////////////// // // // tri_edge_cop_inter() Test whether a triangle (abc) and a coplanar edge // // (pq) are intersecting or not. // // // // A reference point R is required. R is exactly not coplanar with abc and // // pq. Since the caller knows they are coplanar, it must be able to provide // // (or calculate) such a point. // // // // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // // SHAREEDGE, and INTERSECT. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::tri_edge_cop_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL* R) { enum interresult abpq, bcpq, capq; enum interresult abcp, abcq; // Test if pq is intersecting one of edges of abc. abpq = edge_edge_cop_inter(A, B, P, Q, R); if (abpq == INTERSECT || abpq == SHAREEDGE) { return abpq; } bcpq = edge_edge_cop_inter(B, C, P, Q, R); if (bcpq == INTERSECT || bcpq == SHAREEDGE) { return bcpq; } capq = edge_edge_cop_inter(C, A, P, Q, R); if (capq == INTERSECT || capq == SHAREEDGE) { return capq; } // Test if p and q is inside abc. abcp = tri_vert_cop_inter(A, B, C, P, R); if (abcp == INTERSECT) { return INTERSECT; } abcq = tri_vert_cop_inter(A, B, C, Q, R); if (abcq == INTERSECT) { return INTERSECT; } // Combine the test results of edge intersectings and triangle insides // to detect whether abc and pq are sharing vertex or disjointed. if (abpq == SHAREVERTEX) { // p or q is coincident with a or b. #ifdef SELF_CHECK assert(abcp ^ abcq); #endif return SHAREVERTEX; } if (bcpq == SHAREVERTEX) { // p or q is coincident with b or c. #ifdef SELF_CHECK assert(abcp ^ abcq); #endif return SHAREVERTEX; } if (capq == SHAREVERTEX) { // p or q is coincident with c or a. #ifdef SELF_CHECK assert(abcp ^ abcq); #endif return SHAREVERTEX; } // They are disjointed. return DISJOINT; } /////////////////////////////////////////////////////////////////////////////// // // // tri_edge_inter_tail() Test whether a triangle (abc) and an edge (pq) // // are intersecting or not. // // // // s1 and s2 are results of pre-performed orientation tests. s1 = orient3d( // // a, b, c, p); s2 = orient3d(a, b, c, q). To separate this routine from // // tri_edge_inter() can save two orientation tests in tri_tri_inter(). // // // // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // // SHAREEDGE, and INTERSECT. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::tri_edge_inter_tail(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q, REAL s1, REAL s2) { REAL s3, s4, s5; int sign; if (s1 * s2 > 0.0) { // p, q are at the same halfspace of ABC, no intersection. return DISJOINT; } if (s1 * s2 < 0.0) { // p, q are both not on ABC (and not sharing vertices, edges of abc). // Adjust the orientation of a, b, c and p, so that we can assume that // p is strictly in ABC-, and q is strictly in ABC+. sign = s1 < 0.0 ? 1 : -1; s3 = orient3d(A, B, P, Q) * sign; if (s3 < 0.0) { // q is at ABP-. return DISJOINT; } s4 = orient3d(B, C, P, Q) * sign; if (s4 < 0.0) { // q is at BCP-. return DISJOINT; } s5 = orient3d(C, A, P, Q) * sign; if (s5 < 0.0) { // q is at CAP-. return DISJOINT; } if (s3 == 0.0) { // q is on ABP. if (s4 == 0.0) { // q is on BCP (and q must in CAP+). #ifdef SELF_CHECK assert(s5 > 0.0); #endif // pq intersects abc at vertex b. return SHAREVERTEX; } if (s5 == 0.0) { // q is on CAP (and q must in BCP+). // pq intersects abc at vertex a. return SHAREVERTEX; } // q in both BCP+ and CAP+. // pq crosses ab properly. return INTERSECT; } // q is in ABP+; if (s4 == 0.0) { // q is on BCP. if (s5 == 0.0) { // q is on CAP. // pq intersects abc at vertex c. return SHAREVERTEX; } // pq crosses bc properly. return INTERSECT; } // q is in BCP+; if (s5 == 0.0) { // q is on CAP. // pq crosses ca properly. return INTERSECT; } // q is in CAP+; // pq crosses abc properly. return INTERSECT; } if (s1 != 0.0 || s2 != 0.0) { // Either p or q is coplanar with abc. ONLY one of them is possible. if (s1 == 0.0) { // p is coplanar with abc, q can be used as reference point. #ifdef SELF_CHECK assert(s2 != 0.0); #endif return tri_vert_cop_inter(A, B, C, P, Q); } else { // q is coplanar with abc, p can be used as reference point. #ifdef SELF_CHECK assert(s2 == 0.0); #endif return tri_vert_cop_inter(A, B, C, Q, P); } } // pq is coplanar with abc. Calculate a point which is exactly not // coplanar with a, b, and c. REAL R[3], N[3]; REAL ax, ay, az, bx, by, bz; ax = A[0] - B[0]; ay = A[1] - B[1]; az = A[2] - B[2]; bx = A[0] - C[0]; by = A[1] - C[1]; bz = A[2] - C[2]; N[0] = ay * bz - by * az; N[1] = az * bx - bz * ax; N[2] = ax * by - bx * ay; // The normal should not be a zero vector (otherwise, abc are collinear). #ifdef SELF_CHECK assert((fabs(N[0]) + fabs(N[1]) + fabs(N[2])) > 0.0); #endif // The reference point R is lifted from A to the normal direction with // a distance d = average edge length of the triangle abc. R[0] = N[0] + A[0]; R[1] = N[1] + A[1]; R[2] = N[2] + A[2]; // Becareful the case: if the non-zero component(s) in N is smaller than // the machine epsilon (i.e., 2^(-16) for double), R will exactly equal // to A due to the round-off error. Do check if it is. if (R[0] == A[0] && R[1] == A[1] && R[2] == A[2]) { int i, j; for (i = 0; i < 3; i++) { #ifdef SELF_CHECK assert (R[i] == A[i]); #endif j = 2; do { if (N[i] > 0.0) { N[i] += (j * macheps); } else { N[i] -= (j * macheps); } R[i] = N[i] + A[i]; j *= 2; } while (R[i] == A[i]); } } return tri_edge_cop_inter(A, B, C, P, Q, R); } /////////////////////////////////////////////////////////////////////////////// // // // tri_edge_inter() Test whether a triangle (abc) and an edge (pq) are // // intersecting or not. // // // // The return value indicates one of the four cases: DISJOINT, SHAREVERTEX, // // SHAREEDGE, and INTERSECT. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::tri_edge_inter(REAL* A, REAL* B, REAL* C, REAL* P, REAL* Q) { REAL s1, s2; // Test the locations of p and q with respect to ABC. s1 = orient3d(A, B, C, P); s2 = orient3d(A, B, C, Q); return tri_edge_inter_tail(A, B, C, P, Q, s1, s2); } /////////////////////////////////////////////////////////////////////////////// // // // tri_tri_inter() Test whether two triangle (abc) and (opq) are // // intersecting or not. // // // // The return value indicates one of the five cases: DISJOINT, SHAREVERTEX, // // SHAREEDGE, SHAREFACE, and INTERSECT. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::tri_tri_inter(REAL* A, REAL* B, REAL* C, REAL* O, REAL* P, REAL* Q) { REAL s_o, s_p, s_q; REAL s_a, s_b, s_c; s_o = orient3d(A, B, C, O); s_p = orient3d(A, B, C, P); s_q = orient3d(A, B, C, Q); if ((s_o * s_p > 0.0) && (s_o * s_q > 0.0)) { // o, p, q are all in the same halfspace of ABC. return DISJOINT; } s_a = orient3d(O, P, Q, A); s_b = orient3d(O, P, Q, B); s_c = orient3d(O, P, Q, C); if ((s_a * s_b > 0.0) && (s_a * s_c > 0.0)) { // a, b, c are all in the same halfspace of OPQ. return DISJOINT; } enum interresult abcop, abcpq, abcqo; int shareedge = 0; abcop = tri_edge_inter_tail(A, B, C, O, P, s_o, s_p); if (abcop == INTERSECT) { return INTERSECT; } else if (abcop == SHAREEDGE) { shareedge++; } abcpq = tri_edge_inter_tail(A, B, C, P, Q, s_p, s_q); if (abcpq == INTERSECT) { return INTERSECT; } else if (abcpq == SHAREEDGE) { shareedge++; } abcqo = tri_edge_inter_tail(A, B, C, Q, O, s_q, s_o); if (abcqo == INTERSECT) { return INTERSECT; } else if (abcqo == SHAREEDGE) { shareedge++; } if (shareedge == 3) { // opq are coincident with abc. return SHAREFACE; } #ifdef SELF_CHECK // It is only possible either no share edge or one. assert(shareedge == 0 || shareedge == 1); #endif // Continue to detect whether opq and abc are intersecting or not. enum interresult opqab, opqbc, opqca; opqab = tri_edge_inter_tail(O, P, Q, A, B, s_a, s_b); if (opqab == INTERSECT) { return INTERSECT; } opqbc = tri_edge_inter_tail(O, P, Q, B, C, s_b, s_c); if (opqbc == INTERSECT) { return INTERSECT; } opqca = tri_edge_inter_tail(O, P, Q, C, A, s_c, s_a); if (opqca == INTERSECT) { return INTERSECT; } // At this point, two triangles are not intersecting and not coincident. // They may be share an edge, or share a vertex, or disjoint. if (abcop == SHAREEDGE) { #ifdef SELF_CHECK assert(abcpq == SHAREVERTEX && abcqo == SHAREVERTEX); #endif // op is coincident with an edge of abc. return SHAREEDGE; } if (abcpq == SHAREEDGE) { #ifdef SELF_CHECK assert(abcop == SHAREVERTEX && abcqo == SHAREVERTEX); #endif // pq is coincident with an edge of abc. return SHAREEDGE; } if (abcqo == SHAREEDGE) { #ifdef SELF_CHECK assert(abcop == SHAREVERTEX && abcpq == SHAREVERTEX); #endif // qo is coincident with an edge of abc. return SHAREEDGE; } // They may share a vertex or disjoint. if (abcop == SHAREVERTEX) { // o or p is coincident with a vertex of abc. if (abcpq == SHAREVERTEX) { // p is the coincident vertex. #ifdef SELF_CHECK assert(abcqo != SHAREVERTEX); #endif } else { // o is the coincident vertex. #ifdef SELF_CHECK assert(abcqo == SHAREVERTEX); #endif } return SHAREVERTEX; } if (abcpq == SHAREVERTEX) { // q is the coincident vertex. #ifdef SELF_CHECK assert(abcqo == SHAREVERTEX); #endif return SHAREVERTEX; } // They are disjoint. return DISJOINT; } /////////////////////////////////////////////////////////////////////////////// // // // tri_edge_2d() Triangle-edge coplanar intersection test. // // // // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, // // Q) in a plane in 3D, and tests if they intersect each other. Return 1 if // // they are intersected, i.e., T \cap E is not empty, otherwise, return 0. // // // // If the point 'R' is not NULL, it lies strictly above T [A, B, C]. // // // // If T1 and T2 intersect each other (return 1), they may intersect in diff- // // erent ways. If 'level' > 0, their intersection type will be reported in // // combinations of 'types' and 'pos'. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::tri_edge_2d(point A, point B, point C, point P, point Q, point R, int level, int *types, int *pos) { point U[3], V[3]; // The permuted vectors of points. int pu[3], pv[3]; // The original positions of points. REAL sA, sB, sC; REAL s1, s2, s3, s4; int z1; if (R == NULL) { REAL n[3], len; // Calculate a lift point, saved in dummypoint. facenormal2(A, B, C, n, 1); len = sqrt(DOT(n, n)); n[0] /= len; n[1] /= len; n[2] /= len; len = DIST(A, B); len += DIST(B, C); len += DIST(C, A); len /= 3.0; R = dummypoint; R[0] = A[0] + len * n[0]; R[1] = A[1] + len * n[1]; R[2] = A[2] + len * n[2]; } // Test A's, B's, and C's orientations wrt plane PQR. sA = orient3d(P, Q, R, A); sB = orient3d(P, Q, R, B); sC = orient3d(P, Q, R, C); orient3dcount+=3; if (b->verbose > 2) { printf(" Tri-edge-2d (%d %d %d)-(%d %d)-(%d) (%c%c%c)", pointmark(A), pointmark(B), pointmark(C), pointmark(P), pointmark(Q), pointmark(R), sA > 0 ? '+' : (sA < 0 ? '-' : '0'), sB>0 ? '+' : (sB<0 ? '-' : '0'), sC>0 ? '+' : (sC<0 ? '-' : '0')); } // triedgcopcount++; if (sA < 0) { if (sB < 0) { if (sC < 0) { // (---). return 0; } else { if (sC > 0) { // (--+). // All points are in the right positions. SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 0; } else { // (--0). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 1; } } } else { if (sB > 0) { if (sC < 0) { // (-+-). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 0, 1, 2); z1 = 0; } else { if (sC > 0) { // (-++). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 1, 0, 2); z1 = 0; } else { // (-+0). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 0, 1, 2); z1 = 2; } } } else { if (sC < 0) { // (-0-). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 0, 1, 2); z1 = 1; } else { if (sC > 0) { // (-0+). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 1, 0, 2); z1 = 2; } else { // (-00). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 1, 0, 2); z1 = 3; } } } } } else { if (sA > 0) { if (sB < 0) { if (sC < 0) { // (+--). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 0, 1, 2); z1 = 0; } else { if (sC > 0) { // (+-+). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 1, 0, 2); z1 = 0; } else { // (+-0). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 1, 0, 2); z1 = 2; } } } else { if (sB > 0) { if (sC < 0) { // (++-). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 0; } else { if (sC > 0) { // (+++). return 0; } else { // (++0). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 1; } } } else { // (+0#) if (sC < 0) { // (+0-). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 0, 1, 2); z1 = 2; } else { if (sC > 0) { // (+0+). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 1, 0, 2); z1 = 1; } else { // (+00). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 0, 1, 2); z1 = 3; } } } } } else { if (sB < 0) { if (sC < 0) { // (0--). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 0, 1, 2); z1 = 1; } else { if (sC > 0) { // (0-+). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 2; } else { // (0-0). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 1, 0, 2); z1 = 3; } } } else { if (sB > 0) { if (sC < 0) { // (0+-). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 2; } else { if (sC > 0) { // (0++). SETVECTOR3(U, B, C, A); // PT = ST x ST SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 1, 2, 0); SETVECTOR3(pv, 1, 0, 2); z1 = 1; } else { // (0+0). SETVECTOR3(U, C, A, B); // PT = ST SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 2, 0, 1); SETVECTOR3(pv, 0, 1, 2); z1 = 3; } } } else { // (00#) if (sC < 0) { // (00-). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, Q, P, R); // PL = SL SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 3; } else { if (sC > 0) { // (00+). SETVECTOR3(U, A, B, C); // I3 SETVECTOR3(V, P, Q, R); // I2 SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 3; } else { // (000) // Not possible unless ABC is degenerate. z1 = 4; } } } } } } s1 = orient3d(U[0], U[2], R, V[1]); // A, C, R, Q s2 = orient3d(U[1], U[2], R, V[0]); // B, C, R, P orient3dcount+=2; if (b->verbose > 2) { printf(" Tri-edge-2d (%d %d %d)-(%d %d %d) (%d) (%c%c)\n", pointmark(U[0]), pointmark(U[1]), pointmark(U[2]), pointmark(V[0]), pointmark(V[1]), pointmark(V[2]), z1, s1>0 ? '+' : (s1<0 ? '-' : '0'), s2>0 ? '+' : (s2<0 ? '-' : '0')); } assert(z1 != 4); // SELF_CHECK if (s1 > 0) { return 0; } if (s2 < 0) { return 0; } if (level == 0) { return 1; // They are intersected. } if (z1 == 1) { if (s1 == 0) { // (0###) // C = Q. types[0] = (int) SHAREVERTEX; pos[0] = pu[2]; // C pos[1] = pv[1]; // Q types[1] = (int) DISJOINT; } else { if (s2 == 0) { // (#0##) // C = P. types[0] = (int) SHAREVERTEX; pos[0] = pu[2]; // C pos[1] = pv[0]; // P types[1] = (int) DISJOINT; } else { // (-+##) // C in [P, Q]. types[0] = (int) INTERVERT; pos[0] = pu[2]; // C pos[1] = pv[0]; // [P, Q] types[1] = (int) DISJOINT; } } return 1; } s3 = orient3d(U[0], U[2], R, V[0]); // A, C, R, P s4 = orient3d(U[1], U[2], R, V[1]); // B, C, R, Q orient3dcount+=2; if (z1 == 0) { // (tritri-03) if (s1 < 0) { if (s3 > 0) { assert(s2 > 0); // SELF_CHECK if (s4 > 0) { // [P, Q] overlaps [k, l] (-+++). types[0] = (int) INTEREDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[0]; // [P, Q] types[1] = (int) TOUCHFACE; pos[2] = 3; // [A, B, C] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // Q = l, [P, Q] contains [k, l] (-++0). types[0] = (int) INTEREDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[0]; // [P, Q] types[1] = (int) TOUCHEDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[1]; // Q } else { // s4 < 0 // [P, Q] contains [k, l] (-++-). types[0] = (int) INTEREDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[0]; // [P, Q] types[1] = (int) INTEREDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[0]; // [P, Q] } } } else { if (s3 == 0) { assert(s2 > 0); // SELF_CHECK if (s4 > 0) { // P = k, [P, Q] in [k, l] (-+0+). types[0] = (int) TOUCHEDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[0]; // P types[1] = (int) TOUCHFACE; pos[2] = 3; // [A, B, C] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // [P, Q] = [k, l] (-+00). types[0] = (int) TOUCHEDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[0]; // P types[1] = (int) TOUCHEDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[1]; // Q } else { // P = k, [P, Q] contains [k, l] (-+0-). types[0] = (int) TOUCHEDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[0]; // P types[1] = (int) INTEREDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[0]; // [P, Q] } } } else { // s3 < 0 if (s2 > 0) { if (s4 > 0) { // [P, Q] in [k, l] (-+-+). types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[0]; // P types[1] = (int) TOUCHFACE; pos[2] = 3; // [A, B, C] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // Q = l, [P, Q] in [k, l] (-+-0). types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[0]; // P types[1] = (int) TOUCHEDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[1]; // Q } else { // s4 < 0 // [P, Q] overlaps [k, l] (-+--). types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[0]; // P types[1] = (int) INTEREDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[0]; // [P, Q] } } } else { // s2 == 0 // P = l (#0##). types[0] = (int) TOUCHEDGE; pos[0] = pu[1]; // [B, C] pos[1] = pv[0]; // P types[1] = (int) DISJOINT; } } } } else { // s1 == 0 // Q = k (0####) types[0] = (int) TOUCHEDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[1]; // Q types[1] = (int) DISJOINT; } } else if (z1 == 2) { // (tritri-23) if (s1 < 0) { if (s3 > 0) { assert(s2 > 0); // SELF_CHECK if (s4 > 0) { // [P, Q] overlaps [A, l] (-+++). types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = pv[0]; // [P, Q] types[1] = (int) TOUCHFACE; pos[2] = 3; // [A, B, C] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // Q = l, [P, Q] contains [A, l] (-++0). types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = pv[0]; // [P, Q] types[1] = (int) TOUCHEDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[1]; // Q } else { // s4 < 0 // [P, Q] contains [A, l] (-++-). types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = pv[0]; // [P, Q] types[1] = (int) INTEREDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[0]; // [P, Q] } } } else { if (s3 == 0) { assert(s2 > 0); // SELF_CHECK if (s4 > 0) { // P = A, [P, Q] in [A, l] (-+0+). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[0]; // P types[1] = (int) TOUCHFACE; pos[2] = 3; // [A, B, C] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // [P, Q] = [A, l] (-+00). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[0]; // P types[1] = (int) TOUCHEDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[1]; // Q } else { // s4 < 0 // Q = l, [P, Q] in [A, l] (-+0-). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[0]; // P types[1] = (int) INTEREDGE; pos[2] = pu[1]; // [B, C] pos[3] = pv[0]; // [P, Q] } } } else { // s3 < 0 if (s2 > 0) { if (s4 > 0) { // [P, Q] in [A, l] (-+-+). types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[0]; // P types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[1]; // Q } else { if (s4 == 0) { // Q = l, [P, Q] in [A, l] (-+-0). types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[0]; // P types[0] = (int) TOUCHEDGE; pos[0] = pu[1]; // [B, C] pos[1] = pv[1]; // Q } else { // s4 < 0 // [P, Q] overlaps [A, l] (-+--). types[0] = (int) TOUCHFACE; pos[0] = 3; // [A, B, C] pos[1] = pv[0]; // P types[0] = (int) INTEREDGE; pos[0] = pu[1]; // [B, C] pos[1] = pv[0]; // [P, Q] } } } else { // s2 == 0 // P = l (#0##). types[0] = (int) TOUCHEDGE; pos[0] = pu[1]; // [B, C] pos[1] = pv[0]; // P types[1] = (int) DISJOINT; } } } } else { // s1 == 0 // Q = A (0###). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[1]; // Q types[1] = (int) DISJOINT; } } else if (z1 == 3) { // (tritri-33) if (s1 < 0) { if (s3 > 0) { assert(s2 > 0); // SELF_CHECK if (s4 > 0) { // [P, Q] overlaps [A, B] (-+++). types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = pv[0]; // [P, Q] types[1] = (int) TOUCHEDGE; pos[2] = pu[0]; // [A, B] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // Q = B, [P, Q] contains [A, B] (-++0). types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = pv[0]; // [P, Q] types[1] = (int) SHAREVERTEX; pos[2] = pu[1]; // B pos[3] = pv[1]; // Q } else { // s4 < 0 // [P, Q] contains [A, B] (-++-). types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = pv[0]; // [P, Q] types[1] = (int) INTERVERT; pos[2] = pu[1]; // B pos[3] = pv[0]; // [P, Q] } } } else { if (s3 == 0) { assert(s2 > 0); // SELF_CHECK if (s4 > 0) { // P = A, [P, Q] in [A, B] (-+0+). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[0]; // P types[1] = (int) TOUCHEDGE; pos[2] = pu[0]; // [A, B] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // [P, Q] = [A, B] (-+00). types[0] = (int) SHAREEDGE; pos[0] = pu[0]; // [A, B] pos[1] = pv[0]; // [P, Q] types[1] = (int) DISJOINT; } else { // s4 < 0 // P= A, [P, Q] in [A, B] (-+0-). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[0]; // P types[1] = (int) INTERVERT; pos[2] = pu[1]; // B pos[3] = pv[0]; // [P, Q] } } } else { // s3 < 0 if (s2 > 0) { if (s4 > 0) { // [P, Q] in [A, B] (-+-+). types[0] = (int) TOUCHEDGE; pos[0] = pu[0]; // [A, B] pos[1] = pv[0]; // P types[1] = (int) TOUCHEDGE; pos[2] = pu[0]; // [A, B] pos[3] = pv[1]; // Q } else { if (s4 == 0) { // Q = B, [P, Q] in [A, B] (-+-0). types[0] = (int) TOUCHEDGE; pos[0] = pu[0]; // [A, B] pos[1] = pv[0]; // P types[1] = (int) SHAREVERTEX; pos[2] = pu[1]; // B pos[3] = pv[1]; // Q } else { // s4 < 0 // [P, Q] overlaps [A, B] (-+--). types[0] = (int) TOUCHEDGE; pos[0] = pu[0]; // [A, B] pos[1] = pv[0]; // P types[1] = (int) INTERVERT; pos[2] = pu[1]; // B pos[3] = pv[0]; // [P, Q] } } } else { // s2 == 0 // P = B (#0##). types[0] = (int) SHAREVERTEX; pos[0] = pu[1]; // B pos[1] = pv[0]; // P types[1] = (int) DISJOINT; } } } } else { // s1 == 0 // Q = A (0###). types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[1]; // Q types[1] = (int) DISJOINT; } } return 1; } /////////////////////////////////////////////////////////////////////////////// // // // tri_edge_test() Triangle-edge intersection test. // // // // This routine takes a triangle T (with vertices A, B, C) and an edge E (P, // // Q) in 3D, and tests if they intersect each other. Return 1 if they are // // intersected, i.e., T \cap E is not empty, otherwise, return 0. // // // // If the point 'R' is not NULL, it lies strictly above the plane defined by // // A, B, C. It is used in test when T and E are coplanar. // // // // If T1 and T2 intersect each other (return 1), they may intersect in diff- // // erent ways. If 'level' > 0, their intersection type will be reported in // // combinations of 'types' and 'pos'. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::tri_edge_test(point A, point B, point C, point P, point Q, point R, int level, int *types, int *pos) { point U[3], V[3]; //, Ptmp; int pu[3], pv[3]; //, itmp; REAL sP, sQ, s1, s2, s3; int z1; // Test the locations of P and Q with respect to ABC. sP = orient3d(A, B, C, P); sQ = orient3d(A, B, C, Q); orient3dcount+=2; if (b->verbose > 2) { printf(" Tri-edge (%d %d %d)-(%d %d) (%c%c).\n", pointmark(A), pointmark(B), pointmark(C), pointmark(P), pointmark(Q), sP>0 ? '+' : (sP<0 ? '-' : '0'), sQ>0 ? '+' : (sQ<0 ? '-' : '0')); } // triedgcount++; if (sP < 0) { if (sQ < 0) { // (--) disjoint return 0; } else { if (sQ > 0) { // (-+) SETVECTOR3(U, A, B, C); SETVECTOR3(V, P, Q, R); SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 0; } else { // (-0) SETVECTOR3(U, A, B, C); SETVECTOR3(V, P, Q, R); SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 1; } } } else { if (sP > 0) { // (+-) if (sQ < 0) { SETVECTOR3(U, A, B, C); SETVECTOR3(V, Q, P, R); // P and Q are flipped. SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 0; } else { if (sQ > 0) { // (++) disjoint return 0; } else { // (+0) SETVECTOR3(U, B, A, C); // A and B are flipped. SETVECTOR3(V, P, Q, R); SETVECTOR3(pu, 1, 0, 2); SETVECTOR3(pv, 0, 1, 2); z1 = 1; } } } else { // sP == 0 if (sQ < 0) { // (0-) SETVECTOR3(U, A, B, C); SETVECTOR3(V, Q, P, R); // P and Q are flipped. SETVECTOR3(pu, 0, 1, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 1; } else { if (sQ > 0) { // (0+) SETVECTOR3(U, B, A, C); // A and B are flipped. SETVECTOR3(V, Q, P, R); // P and Q are flipped. SETVECTOR3(pu, 1, 0, 2); SETVECTOR3(pv, 1, 0, 2); z1 = 1; } else { // (00) // A, B, C, P, and Q are coplanar. z1 = 2; } } } } if (z1 == 2) { // The triangle and the edge are coplanar. return tri_edge_2d(A, B, C, P, Q, R, level, types, pos); } s1 = orient3d(U[0], U[1], V[0], V[1]); orient3dcount++; if (s1 < 0) { return 0; } s2 = orient3d(U[1], U[2], V[0], V[1]); orient3dcount++; if (s2 < 0) { return 0; } s3 = orient3d(U[2], U[0], V[0], V[1]); orient3dcount++; if (s3 < 0) { return 0; } if (b->verbose > 2) { printf(" Tri-edge (%d %d %d)-(%d %d) (%c%c%c).\n", pointmark(U[0]), pointmark(U[1]), pointmark(U[2]), pointmark(V[0]), pointmark(V[1]), s1>0 ? '+' : (s1<0 ? '-' : '0'), s2>0 ? '+' : (s2<0 ? '-' : '0'), s3>0 ? '+' : (s3<0 ? '-' : '0')); } if (level == 0) { return 1; // The are intersected. } types[1] = (int) DISJOINT; // No second intersection point. if (z1 == 0) { if (s1 > 0) { if (s2 > 0) { if (s3 > 0) { // (+++) // [P, Q] passes interior of [A, B, C]. types[0] = (int) INTERFACE; pos[0] = 3; // interior of [A, B, C] pos[1] = 0; // [P, Q] } else { // s3 == 0 (++0) // [P, Q] intersects [C, A]. types[0] = (int) INTEREDGE; pos[0] = pu[2]; // [C, A] pos[1] = 0; // [P, Q] } } else { // s2 == 0 if (s3 > 0) { // (+0+) // [P, Q] intersects [B, C]. types[0] = (int) INTEREDGE; pos[0] = pu[1]; // [B, C] pos[1] = 0; // [P, Q] } else { // s3 == 0 (+00) // [P, Q] passes C. types[0] = (int) INTERVERT; pos[0] = pu[2]; // C pos[1] = 0; // [P, Q] } } } else { // s1 == 0 if (s2 > 0) { if (s3 > 0) { // (0++) // [P, Q] intersects [A, B]. types[0] = (int) INTEREDGE; pos[0] = pu[0]; // [A, B] pos[1] = 0; // [P, Q] } else { // s3 == 0 (0+0) // [P, Q] passes A. types[0] = (int) INTERVERT; pos[0] = pu[0]; // A pos[1] = 0; // [P, Q] } } else { // s2 == 0 if (s3 > 0) { // (00+) // [P, Q] passes B. types[0] = (int) INTERVERT; pos[0] = pu[1]; // B pos[1] = 0; // [P, Q] } else { // s3 == 0 (000) // Impossible. assert(0); } } } } else { // z1 == 1 if (s1 > 0) { if (s2 > 0) { if (s3 > 0) { // (+++) // Q lies in [A, B, C]. types[0] = (int) TOUCHFACE; pos[0] = 0; // [A, B, C] pos[1] = pv[1]; // Q } else { // s3 == 0 (++0) // Q lies on [C, A]. types[0] = (int) TOUCHEDGE; pos[0] = pu[2]; // [C, A] pos[1] = pv[1]; // Q } } else { // s2 == 0 if (s3 > 0) { // (+0+) // Q lies on [B, C]. types[0] = (int) TOUCHEDGE; pos[0] = pu[1]; // [B, C] pos[1] = pv[1]; // Q } else { // s3 == 0 (+00) // Q = C. types[0] = (int) SHAREVERTEX; pos[0] = pu[2]; // C pos[1] = pv[1]; // Q } } } else { // s1 == 0 if (s2 > 0) { if (s3 > 0) { // (0++) // Q lies on [A, B]. types[0] = (int) TOUCHEDGE; pos[0] = pu[0]; // [A, B] pos[1] = pv[1]; // Q } else { // s3 == 0 (0+0) // Q = A. types[0] = (int) SHAREVERTEX; pos[0] = pu[0]; // A pos[1] = pv[1]; // Q } } else { // s2 == 0 if (s3 > 0) { // (00+) // Q = B. types[0] = (int) SHAREVERTEX; pos[0] = pu[1]; // B pos[1] = pv[1]; // Q } else { // s3 == 0 (000) // Impossible. assert(0); } } } } return 1; } /////////////////////////////////////////////////////////////////////////////// // // // incircle3d() 3D in-circle test. // // // // Return a negative value if pd is inside the circumcircle of the triangle // // pa, pb, and pc. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::incircle3d(point pa, point pb, point pc, point pd) { REAL area2[2], n1[3], n2[3], c[3]; REAL sign, r, d; // Calculate the areas of the two triangles [a, b, c] and [b, a, d]. facenormal2(pa, pb, pc, n1, 1); area2[0] = DOT(n1, n1); facenormal2(pb, pa, pd, n2, 1); area2[1] = DOT(n2, n2); if (area2[0] > area2[1]) { // Choose [a, b, c] as the base triangle. circumsphere(pa, pb, pc, NULL, c, &r); d = DIST(c, pd); } else { // Choose [b, a, d] as the base triangle. if (area2[1] > 0) { circumsphere(pb, pa, pd, NULL, c, &r); d = DIST(c, pc); } else { // The four points are collinear. This case only happens on the boundary. return 0; // Return "not inside". } } sign = d - r; if (fabs(sign) / r < b->epsilon) { sign = 0; } return sign; } /////////////////////////////////////////////////////////////////////////////// // // // insphere_s() Insphere test with symbolic perturbation. // // // // Given four points pa, pb, pc, and pd, test if the point pe lies inside or // // outside the circumscirbed sphere of the four points. Here we assume that // // the orientation of the sequence {pa, pb, pc, pd} is negative (NOT zero), // // i.e., pd lies at the negative side of the plane defined by pa, pb, and pc.// // // // Return a positive value (> 0) if pe lies outside, a negative value (< 0) // // if pe lies inside the sphere, the returned value will not be zero. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::insphere_s(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* pe) { REAL sign; inspherecount++; sign = insphere(pa, pb, pc, pd, pe); if (sign != 0.0) { return sign; } insphere_sos_count++; // Symbolic perturbation. point pt[5], swappt; REAL oriA, oriB; int swaps, count; int n, i; pt[0] = pa; pt[1] = pb; pt[2] = pc; pt[3] = pd; pt[4] = pe; // Sort the five points such that their indices are in the increasing // order. An optimized bubble sort algorithm is used, i.e., it has // the worst case O(n^2) runtime, but it is usually much faster. swaps = 0; // Record the total number of swaps. n = 5; do { count = 0; n = n - 1; for (i = 0; i < n; i++) { if (pointmark(pt[i]) > pointmark(pt[i+1])) { swappt = pt[i]; pt[i] = pt[i+1]; pt[i+1] = swappt; count++; } } swaps += count; } while (count > 0); // Continue if some points are swapped. oriA = orient3d(pt[1], pt[2], pt[3], pt[4]); if (oriA != 0.0) { // Flip the sign if there are odd number of swaps. if ((swaps % 2) != 0) oriA = -oriA; return oriA; } oriB = -orient3d(pt[0], pt[2], pt[3], pt[4]); assert(oriB != 0.0); // SELF_CHECK // Flip the sign if there are odd number of swaps. if ((swaps % 2) != 0) oriB = -oriB; return oriB; } /////////////////////////////////////////////////////////////////////////////// // // // iscollinear() Check if three points are approximately collinear. // // // // 'eps' is a relative error tolerance. The collinearity is determined by // // the value q = cos(theta), where theta is the angle between two vectors // // A->B and A->C. They're collinear if 1.0 - q <= epspp. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::iscollinear(REAL* A, REAL* B, REAL* C, REAL eps) { REAL abx, aby, abz; REAL acx, acy, acz; REAL Lv, Lw, dd; REAL d, q; // Limit of two closed points. q = longest * eps; q *= q; abx = A[0] - B[0]; aby = A[1] - B[1]; abz = A[2] - B[2]; acx = A[0] - C[0]; acy = A[1] - C[1]; acz = A[2] - C[2]; Lv = abx * abx + aby * aby + abz * abz; // Is AB (nearly) indentical? if (Lv < q) return true; Lw = acx * acx + acy * acy + acz * acz; // Is AC (nearly) indentical? if (Lw < q) return true; dd = abx * acx + aby * acy + abz * acz; d = (dd * dd) / (Lv * Lw); if (d > 1.0) d = 1.0; // Rounding. q = 1.0 - sqrt(d); // Notice 0 < q < 1.0. return q <= eps; } /////////////////////////////////////////////////////////////////////////////// // // // iscoplanar() Check if four points are approximately coplanar. // // // // 'vol6' is six times of the signed volume of the tetrahedron formed by the // // four points. 'eps' is the relative error tolerance. The coplanarity is // // determined by the value: q = fabs(vol6) / L^3, where L is the average // // edge length of the tet. They're coplanar if q <= eps. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh:: iscoplanar(REAL* k, REAL* l, REAL* m, REAL* n, REAL vol6, REAL eps) { REAL L, q; REAL x, y, z; if (vol6 == 0.0) return true; x = k[0] - l[0]; y = k[1] - l[1]; z = k[2] - l[2]; L = sqrt(x * x + y * y + z * z); x = l[0] - m[0]; y = l[1] - m[1]; z = l[2] - m[2]; L += sqrt(x * x + y * y + z * z); x = m[0] - k[0]; y = m[1] - k[1]; z = m[2] - k[2]; L += sqrt(x * x + y * y + z * z); x = k[0] - n[0]; y = k[1] - n[1]; z = k[2] - n[2]; L += sqrt(x * x + y * y + z * z); x = l[0] - n[0]; y = l[1] - n[1]; z = l[2] - n[2]; L += sqrt(x * x + y * y + z * z); x = m[0] - n[0]; y = m[1] - n[1]; z = m[2] - n[2]; L += sqrt(x * x + y * y + z * z); #ifdef SELF_CHECK assert(L > 0.0); #endif L /= 6.0; q = fabs(vol6) / (L * L * L); return q <= eps; } /////////////////////////////////////////////////////////////////////////////// // // // iscospheric() Check if five points are approximately coplanar. // // // // 'vol24' is the 24 times of the signed volume of the 4-dimensional simplex // // formed by the five points. 'eps' is the relative tolerance. The cosphere // // case is determined by the value: q = fabs(vol24) / L^4, where L is the // // average edge length of the simplex. They're cosphere if q <= eps. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh:: iscospheric(REAL* k, REAL* l, REAL* m, REAL* n, REAL* o, REAL vol24, REAL eps) { REAL L, q; // A 4D simplex has 10 edges. L = distance(k, l); L += distance(l, m); L += distance(m, k); L += distance(k, n); L += distance(l, n); L += distance(m, n); L += distance(k, o); L += distance(l, o); L += distance(m, o); L += distance(n, o); #ifdef SELF_CHECK assert(L > 0.0); #endif L /= 10.0; q = fabs(vol24) / (L * L * L * L); return q < eps; } /////////////////////////////////////////////////////////////////////////////// // // // lu_decmp() Compute the LU decomposition of a matrix. // // // // Compute the LU decomposition of a (non-singular) square matrix A using // // partial pivoting and implicit row exchanges. The result is: // // A = P * L * U, // // where P is a permutation matrix, L is unit lower triangular, and U is // // upper triangular. The factored form of A is used in combination with // // 'lu_solve()' to solve linear equations: Ax = b, or invert a matrix. // // // // The inputs are a square matrix 'lu[N..n+N-1][N..n+N-1]', it's size is 'n'.// // On output, 'lu' is replaced by the LU decomposition of a rowwise permuta- // // tion of itself, 'ps[N..n+N-1]' is an output vector that records the row // // permutation effected by the partial pivoting, effectively, 'ps' array // // tells the user what the permutation matrix P is; 'd' is output as +1/-1 // // depending on whether the number of row interchanges was even or odd, // // respectively. // // // // Return true if the LU decomposition is successfully computed, otherwise, // // return false in case that A is a singular matrix. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N) { REAL scales[4]; REAL pivot, biggest, mult, tempf; int pivotindex = 0; int i, j, k; *d = 1.0; // No row interchanges yet. for (i = N; i < n + N; i++) { // For each row. // Find the largest element in each row for row equilibration biggest = 0.0; for (j = N; j < n + N; j++) if (biggest < (tempf = fabs(lu[i][j]))) biggest = tempf; if (biggest != 0.0) scales[i] = 1.0 / biggest; else { scales[i] = 0.0; return false; // Zero row: singular matrix. } ps[i] = i; // Initialize pivot sequence. } for (k = N; k < n + N - 1; k++) { // For each column. // Find the largest element in each column to pivot around. biggest = 0.0; for (i = k; i < n + N; i++) { if (biggest < (tempf = fabs(lu[ps[i]][k]) * scales[ps[i]])) { biggest = tempf; pivotindex = i; } } if (biggest == 0.0) { return false; // Zero column: singular matrix. } if (pivotindex != k) { // Update pivot sequence. j = ps[k]; ps[k] = ps[pivotindex]; ps[pivotindex] = j; *d = -(*d); // ...and change the parity of d. } // Pivot, eliminating an extra variable each time pivot = lu[ps[k]][k]; for (i = k + 1; i < n + N; i++) { lu[ps[i]][k] = mult = lu[ps[i]][k] / pivot; if (mult != 0.0) { for (j = k + 1; j < n + N; j++) lu[ps[i]][j] -= mult * lu[ps[k]][j]; } } } // (lu[ps[n + N - 1]][n + N - 1] == 0.0) ==> A is singular. return lu[ps[n + N - 1]][n + N - 1] != 0.0; } /////////////////////////////////////////////////////////////////////////////// // // // lu_solve() Solves the linear equation: Ax = b, after the matrix A // // has been decomposed into the lower and upper triangular // // matrices L and U, where A = LU. // // // // 'lu[N..n+N-1][N..n+N-1]' is input, not as the matrix 'A' but rather as // // its LU decomposition, computed by the routine 'lu_decmp'; 'ps[N..n+N-1]' // // is input as the permutation vector returned by 'lu_decmp'; 'b[N..n+N-1]' // // is input as the right-hand side vector, and returns with the solution // // vector. 'lu', 'n', and 'ps' are not modified by this routine and can be // // left in place for successive calls with different right-hand sides 'b'. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N) { int i, j; REAL X[4], dot; for (i = N; i < n + N; i++) X[i] = 0.0; // Vector reduction using U triangular matrix. for (i = N; i < n + N; i++) { dot = 0.0; for (j = N; j < i + N; j++) dot += lu[ps[i]][j] * X[j]; X[i] = b[ps[i]] - dot; } // Back substitution, in L triangular matrix. for (i = n + N - 1; i >= N; i--) { dot = 0.0; for (j = i + 1; j < n + N; j++) dot += lu[ps[i]][j] * X[j]; X[i] = (X[i] - dot) / lu[ps[i]][i]; } for (i = N; i < n + N; i++) b[i] = X[i]; } // initm44() initializes a 4x4 matrix. static void initm44(REAL a00, REAL a01, REAL a02, REAL a03, REAL a10, REAL a11, REAL a12, REAL a13, REAL a20, REAL a21, REAL a22, REAL a23, REAL a30, REAL a31, REAL a32, REAL a33, REAL M[4][4]) { M[0][0] = a00; M[0][1] = a01; M[0][2] = a02; M[0][3] = a03; M[1][0] = a10; M[1][1] = a11; M[1][2] = a12; M[1][3] = a13; M[2][0] = a20; M[2][1] = a21; M[2][2] = a22; M[2][3] = a23; M[3][0] = a30; M[3][1] = a31; M[3][2] = a32; M[3][3] = a33; } // m4xv4() multiplies a 4x4 matrix and 4x1 vector: v2 = m * v1 static void m4xv4(REAL v2[4], REAL m[4][4], REAL v1[4]) { v2[0] = m[0][0]*v1[0] + m[0][1]*v1[1] + m[0][2]*v1[2] + m[0][3]*v1[3]; v2[1] = m[1][0]*v1[0] + m[1][1]*v1[1] + m[1][2]*v1[2] + m[1][3]*v1[3]; v2[2] = m[2][0]*v1[0] + m[2][1]*v1[1] + m[2][2]*v1[2] + m[2][3]*v1[3]; v2[3] = m[3][0]*v1[0] + m[3][1]*v1[1] + m[3][2]*v1[2] + m[3][3]*v1[3]; } /////////////////////////////////////////////////////////////////////////////// // // // shortdistance() Returns the shortest distance from point p to a line // // defined by two points e1 and e2. // // // // First compute the projection length l_p of the vector v1 = p - e1 along // // the vector v2 = e2 - e1. Then Pythagoras' Theorem is used to compute the // // shortest distance. // // // // This routine allows that p is collinear with the line. In this case, the // // return value is zero. The two points e1 and e2 should not be identical. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2) { REAL v1[3], v2[3]; REAL len, l_p; v1[0] = e2[0] - e1[0]; v1[1] = e2[1] - e1[1]; v1[2] = e2[2] - e1[2]; v2[0] = p[0] - e1[0]; v2[1] = p[1] - e1[1]; v2[2] = p[2] - e1[2]; len = sqrt(dot(v1, v1)); #ifdef SELF_CHECK assert(len != 0.0); #endif v1[0] /= len; v1[1] /= len; v1[2] /= len; l_p = dot(v1, v2); return sqrt(dot(v2, v2) - l_p * l_p); } /////////////////////////////////////////////////////////////////////////////// // // // shortdistance() Returns the shortest distance from point p to a face. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3) { REAL prj[3]; projpt2face(p, e1, e2, e3, prj); return distance(p, prj); } /////////////////////////////////////////////////////////////////////////////// // // // interiorangle() Return the interior angle (0 - 2 * PI) between vectors // // o->p1 and o->p2. // // // // 'n' is the normal of the plane containing face (o, p1, p2). The interior // // angle is the total angle rotating from o->p1 around n to o->p2. Exchange // // the position of p1 and p2 will get the complement angle of the other one. // // i.e., interiorangle(o, p1, p2) = 2 * PI - interiorangle(o, p2, p1). Set // // 'n' be NULL if you only want the interior angle between 0 - PI. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n) { REAL v1[3], v2[3], np[3]; REAL theta, costheta, lenlen; REAL ori, len1, len2; // Get the interior angle (0 - PI) between o->p1, and o->p2. v1[0] = p1[0] - o[0]; v1[1] = p1[1] - o[1]; v1[2] = p1[2] - o[2]; v2[0] = p2[0] - o[0]; v2[1] = p2[1] - o[1]; v2[2] = p2[2] - o[2]; len1 = sqrt(dot(v1, v1)); len2 = sqrt(dot(v2, v2)); lenlen = len1 * len2; #ifdef SELF_CHECK assert(lenlen != 0.0); #endif costheta = dot(v1, v2) / lenlen; if (costheta > 1.0) { costheta = 1.0; // Roundoff. } else if (costheta < -1.0) { costheta = -1.0; // Roundoff. } theta = acos(costheta); if (n != NULL) { // Get a point above the face (o, p1, p2); np[0] = o[0] + n[0]; np[1] = o[1] + n[1]; np[2] = o[2] + n[2]; // Adjust theta (0 - 2 * PI). ori = orient3d(p1, o, np, p2); if (ori > 0.0) { theta = 2 * PI - theta; } } return theta; } /////////////////////////////////////////////////////////////////////////////// // // // projpt2edge() Return the projection point from a point to an edge. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj) { REAL v1[3], v2[3]; REAL len, l_p; v1[0] = e2[0] - e1[0]; v1[1] = e2[1] - e1[1]; v1[2] = e2[2] - e1[2]; v2[0] = p[0] - e1[0]; v2[1] = p[1] - e1[1]; v2[2] = p[2] - e1[2]; len = sqrt(dot(v1, v1)); #ifdef SELF_CHECK assert(len != 0.0); #endif v1[0] /= len; v1[1] /= len; v1[2] /= len; l_p = dot(v1, v2); prj[0] = e1[0] + l_p * v1[0]; prj[1] = e1[1] + l_p * v1[1]; prj[2] = e1[2] + l_p * v1[2]; } /////////////////////////////////////////////////////////////////////////////// // // // projpt2face() Return the projection point from a point to a face. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj) { REAL fnormal[3], v1[3]; REAL len, dist; // Get the unit face normal. // facenormal(f1, f2, f3, fnormal, &len); facenormal2(f1, f2, f3, fnormal, 1); len = sqrt(fnormal[0]*fnormal[0] + fnormal[1]*fnormal[1] + fnormal[2]*fnormal[2]); fnormal[0] /= len; fnormal[1] /= len; fnormal[2] /= len; // Get the vector v1 = |p - f1|. v1[0] = p[0] - f1[0]; v1[1] = p[1] - f1[1]; v1[2] = p[2] - f1[2]; // Get the project distance. dist = dot(fnormal, v1); // Get the project point. prj[0] = p[0] - dist * fnormal[0]; prj[1] = p[1] - dist * fnormal[1]; prj[2] = p[2] - dist * fnormal[2]; } /////////////////////////////////////////////////////////////////////////////// // // // facenormal() Calculate the normal of a face given by three points. // // // // In general, the face normal can be calculate by the cross product of any // // pair of the three edge vectors. However, if the three points are nearly // // collinear, the rounding error may harm the result. To choose a good pair // // of vectors is helpful to reduce the error. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen) { REAL v1[3], v2[3]; v1[0] = pb[0] - pa[0]; v1[1] = pb[1] - pa[1]; v1[2] = pb[2] - pa[2]; v2[0] = pc[0] - pa[0]; v2[1] = pc[1] - pa[1]; v2[2] = pc[2] - pa[2]; cross(v1, v2, n); if (nlen != (REAL *) NULL) { *nlen = sqrt(dot(n, n)); } } /////////////////////////////////////////////////////////////////////////////// // // // facenormal() Calculate the normal of the face. // // // // The normal of the face abc can be calculated by the cross product of 2 of // // its 3 edge vectors. A better choice of two edge vectors will reduce the // // numerical error during the calculation. Burdakov proved that the optimal // // basis problem is equivalent to the minimum spanning tree problem with the // // edge length be the functional, see Burdakov, "A greedy algorithm for the // // optimal basis problem", BIT 37:3 (1997), 591-599. If 'pivot' > 0, the two // // short edges in abc are chosen for the calculation. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::facenormal2(point pa, point pb, point pc, REAL *n, int pivot) { REAL v1[3], v2[3], v3[3], *pv1, *pv2; REAL L1, L2, L3; v1[0] = pb[0] - pa[0]; // edge vector v1: a->b v1[1] = pb[1] - pa[1]; v1[2] = pb[2] - pa[2]; v2[0] = pa[0] - pc[0]; // edge vector v2: c->a v2[1] = pa[1] - pc[1]; v2[2] = pa[2] - pc[2]; // Default, normal is calculated by: v1 x (-v2) (see Fig. fnormal). if (pivot > 0) { // Choose edge vectors by Burdakov's algorithm. v3[0] = pc[0] - pb[0]; // edge vector v3: b->c v3[1] = pc[1] - pb[1]; v3[2] = pc[2] - pb[2]; L1 = DOT(v1, v1); L2 = DOT(v2, v2); L3 = DOT(v3, v3); // Sort the three edge lengths. if (L1 < L2) { if (L2 < L3) { pv1 = v1; pv2 = v2; // n = v1 x (-v2). } else { pv1 = v3; pv2 = v1; // n = v3 x (-v1). } } else { if (L1 < L3) { pv1 = v1; pv2 = v2; // n = v1 x (-v2). } else { pv1 = v2; pv2 = v3; // n = v2 x (-v3). } } } else { pv1 = v1; pv2 = v2; // n = v1 x (-v2). } // Calculate the face normal. CROSS(pv1, pv2, n); // Inverse the direction; n[0] = -n[0]; n[1] = -n[1]; n[2] = -n[2]; } /////////////////////////////////////////////////////////////////////////////// // // // edgeorthonormal() Return the unit normal of an edge in a given plane. // // // // The edge is from e1 to e2, the plane is defined by given an additional // // point op, which is non-collinear with the edge. In addition, the side of // // the edge in which op lies defines the positive position of the normal. // // // // Let v1 be the unit vector from e1 to e2, v2 be the unit edge vector from // // e1 to op, fn be the unit face normal calculated by fn = v1 x v2. Then the // // unit edge normal of e1e2 pointing to op is n = fn x v1. Note, we should // // not change the position of fn and v1, otherwise, we get the edge normal // // pointing to the other side of op. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n) { REAL v1[3], v2[3], fn[3]; REAL len; // Get the edge vector v1. v1[0] = e2[0] - e1[0]; v1[1] = e2[1] - e1[1]; v1[2] = e2[2] - e1[2]; // Get the edge vector v2. v2[0] = op[0] - e1[0]; v2[1] = op[1] - e1[1]; v2[2] = op[2] - e1[2]; // Get the face normal fn = v1 x v2. cross(v1, v2, fn); // Get the edge normal n pointing to op. n = fn x v1. cross(fn, v1, n); // Normalize the vector. len = sqrt(dot(n, n)); n[0] /= len; n[1] /= len; n[2] /= len; } /////////////////////////////////////////////////////////////////////////////// // // // facedihedral() Return the dihedral angle (in radian) between two // // adjoining faces. // // // // 'pa', 'pb' are the shared edge of these two faces, 'pc1', and 'pc2' are // // apexes of these two faces. Return the angle (between 0 to 2*pi) between // // the normal of face (pa, pb, pc1) and normal of face (pa, pb, pc2). // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2) { REAL n1[3], n2[3]; REAL n1len, n2len; REAL costheta, ori; REAL theta; facenormal(pa, pb, pc1, n1, &n1len); facenormal(pa, pb, pc2, n2, &n2len); costheta = dot(n1, n2) / (n1len * n2len); // Be careful rounding error! if (costheta > 1.0) { costheta = 1.0; } else if (costheta < -1.0) { costheta = -1.0; } theta = acos(costheta); ori = orient3d(pa, pb, pc1, pc2); if (ori > 0.0) { theta = 2 * PI - theta; } return theta; } /////////////////////////////////////////////////////////////////////////////// // // // tetalldihedral() Get all (six) dihedral angles of a tet. // // // // The tet is given by its four corners a, b, c, and d. If 'cosdd' is not // // NULL, it returns the cosines of the 6 dihedral angles, the corresponding // // edges are: ab, bc, ca, ad, bd, and cd. If 'cosmaxd' (or 'cosmind') is not // // NULL, it returns the cosine of the maximal (or minimal) dihedral angle. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::tetalldihedral(point pa, point pb, point pc, point pd, REAL* cosdd, REAL* cosmaxd, REAL* cosmind) { REAL N[4][3], vol, cosd, len; int f1, f2, i, j; vol = 0; // Check if the tet is valid or not. // Get four normals of faces of the tet. tetallnormal(pa, pb, pc, pd, N, &vol); if (vol == 0.0) { // This tet is not valid. if (cosdd != NULL) { for (i = 0; i < 6; i++) { cosdd[i] = -1.0; // 180 degree. } } // This tet has zero volume. if (cosmaxd != NULL) { *cosmaxd = -1.0; // 180 degree. } if (cosmind != NULL) { *cosmind = 1.0; // 0 degree. } return; } // Normalize the normals. for (i = 0; i < 4; i++) { len = sqrt(dot(N[i], N[i])); if (len != 0.0) { for (j = 0; j < 3; j++) N[i][j] /= len; } } for (i = 0; i < 6; i++) { switch (i) { case 0: f1 = 2; f2 = 3; break; // edge ab. case 1: f1 = 0; f2 = 3; break; // edge bc. case 2: f1 = 1; f2 = 3; break; // edge ca. case 3: f1 = 1; f2 = 2; break; // edge ad. case 4: f1 = 2; f2 = 0; break; // edge bd. case 5: f1 = 0; f2 = 1; break; // edge cd. } cosd = -dot(N[f1], N[f2]); if (cosdd) cosdd[i] = cosd; if (i == 0) { if (cosmaxd) *cosmaxd = cosd; if (cosmind) *cosmind = cosd; } else { if (cosmaxd) *cosmaxd = cosd < *cosmaxd ? cosd : *cosmaxd; if (cosmind) *cosmind = cosd > *cosmind ? cosd : *cosmind; } } } /////////////////////////////////////////////////////////////////////////////// // // // tetallnormal() Get the in-noramls of the four faces of a given tet. // // // // Let tet be abcd. N[4][3] returns the four normals, which are: N[0] cbd, // // N[1] acd, N[2] bad, N[3] abc. These normals are unnormalized. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::tetallnormal(point pa, point pb, point pc, point pd, REAL N[4][3], REAL* volume) { REAL A[4][4], rhs[4], D; int indx[4]; int i, j; // get the entries of A[3][3]. for (i = 0; i < 3; i++) A[0][i] = pa[i] - pd[i]; // d->a vec for (i = 0; i < 3; i++) A[1][i] = pb[i] - pd[i]; // d->b vec for (i = 0; i < 3; i++) A[2][i] = pc[i] - pd[i]; // d->c vec // Compute the inverse of matrix A, to get 3 normals of the 4 faces. lu_decmp(A, 3, indx, &D, 0); // Decompose the matrix just once. if (volume != NULL) { // Get the volume of the tet. *volume = fabs((A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2])) / 6.0; } for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) rhs[i] = 0.0; rhs[j] = 1.0; // Positive means the inside direction lu_solve(A, 3, indx, rhs, 0); for (i = 0; i < 3; i++) N[j][i] = rhs[i]; } // Get the fourth normal by summing up the first three. for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; } /////////////////////////////////////////////////////////////////////////////// // // // tetaspectratio() Calculate the aspect ratio of the tetrahedron. // // // // The aspect ratio of a tet is R/h, where R is the circumradius and h is // // the shortest height of the tet. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::tetaspectratio(point pa, point pb, point pc, point pd) { REAL vda[3], vdb[3], vdc[3]; REAL N[4][3], A[4][4], rhs[4], D; REAL H[4], volume, radius2, minheightinv; int indx[4]; int i, j; // Set the matrix A = [vda, vdb, vdc]^T. for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i]; for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i]; for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i]; // Lu-decompose the matrix A. lu_decmp(A, 3, indx, &D, 0); // Get the volume of abcd. volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; // Check if it is zero. if (volume == 0.0) return 1.0e+200; // A degenerate tet. // if (volume < 0.0) volume = -volume; // Check the radiu-edge ratio of the tet. rhs[0] = 0.5 * dot(vda, vda); rhs[1] = 0.5 * dot(vdb, vdb); rhs[2] = 0.5 * dot(vdc, vdc); lu_solve(A, 3, indx, rhs, 0); // Get the circumcenter. // for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i]; // Get the square of the circumradius. radius2 = dot(rhs, rhs); // Compute the 4 face normals (N[0], ..., N[3]). for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) rhs[i] = 0.0; rhs[j] = 1.0; // Positive means the inside direction lu_solve(A, 3, indx, rhs, 0); for (i = 0; i < 3; i++) N[j][i] = rhs[i]; } // Get the fourth normal by summing up the first three. for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; // Normalized the normals. for (i = 0; i < 4; i++) { // H[i] is the inverse of the height of its corresponding face. H[i] = sqrt(dot(N[i], N[i])); // if (H[i] > 0.0) { // for (j = 0; j < 3; j++) N[i][j] /= H[i]; // } } // Get the radius of the inscribed sphere. // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]); // Get the biggest H[i] (corresponding to the smallest height). minheightinv = H[0]; for (i = 1; i < 3; i++) { if (H[i] > minheightinv) minheightinv = H[i]; } return sqrt(radius2) * minheightinv; } /////////////////////////////////////////////////////////////////////////////// // // // circumsphere() Calculate the smallest circumsphere (center and radius) // // of the given three or four points. // // // // The circumsphere of four points (a tetrahedron) is unique if they are not // // degenerate. If 'pd = NULL', the smallest circumsphere of three points is // // the diametral sphere of the triangle if they are not degenerate. // // // // Return TRUE if the input points are not degenerate and the circumcenter // // and circumradius are returned in 'cent' and 'radius' respectively if they // // are not NULLs. Otherwise, return FALSE indicated the points are degenrate.// // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh:: circumsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius) { REAL A[4][4], rhs[4], D; int indx[4]; // Compute the coefficient matrix A (3x3). A[0][0] = pb[0] - pa[0]; A[0][1] = pb[1] - pa[1]; A[0][2] = pb[2] - pa[2]; A[1][0] = pc[0] - pa[0]; A[1][1] = pc[1] - pa[1]; A[1][2] = pc[2] - pa[2]; if (pd != NULL) { A[2][0] = pd[0] - pa[0]; A[2][1] = pd[1] - pa[1]; A[2][2] = pd[2] - pa[2]; } else { cross(A[0], A[1], A[2]); } // Compute the right hand side vector b (3x1). rhs[0] = 0.5 * dot(A[0], A[0]); rhs[1] = 0.5 * dot(A[1], A[1]); if (pd != NULL) { rhs[2] = 0.5 * dot(A[2], A[2]); } else { rhs[2] = 0.0; } // Solve the 3 by 3 equations use LU decomposition with partial pivoting // and backward and forward substitute.. if (!lu_decmp(A, 3, indx, &D, 0)) { if (radius != (REAL *) NULL) *radius = 0.0; return false; } lu_solve(A, 3, indx, rhs, 0); if (cent != (REAL *) NULL) { cent[0] = pa[0] + rhs[0]; cent[1] = pa[1] + rhs[1]; cent[2] = pa[2] + rhs[2]; } if (radius != (REAL *) NULL) { *radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); } return true; } /////////////////////////////////////////////////////////////////////////////// // // // inscribedsphere() Compute the radius and center of the biggest // // inscribed sphere of a given tetrahedron. // // // // The tetrahedron is given by its four points, it must not be degenerate. // // The center and radius are returned in 'cent' and 'radius' respectively if // // they are not NULLs. // // // // Geometrical fact. For any simplex in d dimension, // // r/h1 + r/h2 + ... r/hn = 1 (n <= d + 1); // // where r is the radius of inscribed ball, and h is the height of each side // // of the simplex. The value of 'r/h' is just the barycenter coordinates of // // each vertex of the simplex. Therefore, we can compute the radius and // // center of the smallest inscribed ball as following equations: // // r = 1.0 / (1/h1 + 1/h2 + ... + 1/hn); (1) // // C = r/h1 * P1 + r/h2 * P2 + ... + r/hn * Pn; (2) // // where C is the vector of center, P1, P2, .. Pn are vectors of vertices. // // Here (2) contains n linear equations with n variables. (h, P) must be a // // pair, h is the height from P to its opposite face. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::inscribedsphere(REAL* pa, REAL* pb, REAL* pc, REAL* pd, REAL* cent, REAL* radius) { REAL N[4][3], H[4]; // Normals (colume vectors) and heights of each face. REAL rd; int i; // Get the all normals of the tet. tetallnormal(pa, pb, pc, pd, N, NULL); for (i = 0; i < 4; i++) { // H[i] is the inverse of height of its corresponding face. H[i] = sqrt(dot(N[i], N[i])); } // Compute the radius use eq. (1). rd = 1.0 / (H[0] + H[1] + H[2] + H[3]); if (radius != (REAL*) NULL) *radius = rd; if (cent != (REAL*) NULL) { // Compute the center use eq. (2). cent[0] = rd * (H[0] * pa[0] + H[1] * pb[0] + H[2] * pc[0] + H[3] * pd[0]); cent[1] = rd * (H[0] * pa[1] + H[1] * pb[1] + H[2] * pc[1] + H[3] * pd[1]); cent[2] = rd * (H[0] * pa[2] + H[1] * pb[2] + H[2] * pc[2] + H[3] * pd[2]); } } /////////////////////////////////////////////////////////////////////////////// // // // rotatepoint() Create a point by rotating an existing point. // // // // Create a 3D point by rotating point 'p' with an angle 'rotangle' (in arc // // degree) around a rotating axis given by a vector from point 'p1' to 'p2'. // // The rotation is according with right-hand rule, i.e., use your right-hand // // to grab the axis with your thumber pointing to its positive direction, // // your fingers indicate the rotating direction. // // // // The rotating steps are the following: // // 1. Translate vector 'p1->p2' to origin, M1; // // 2. Rotate vector around the Y-axis until it lies in the YZ plane, M2; // // 3. Rotate vector around the X-axis until it lies on the Z axis, M3; // // 4. Perform the rotation of 'p' around the z-axis, M4; // // 5. Undo Step 3, M5; // // 6. Undo Step 2, M6; // // 7. Undo Step 1, M7; // // Use matrix multiplication to combine the above sequences, we get: // // p0' = T * p0, where T = M7 * M6 * M5 * M4 * M3 * M2 * M1 // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2) { REAL T[4][4], pp0[4], p0t[4], p2t[4]; REAL roty, rotx, alphaR, projlen; REAL dx, dy, dz; initm44(1, 0, 0, -p1[0], 0, 1, 0, -p1[1], 0, 0, 1, -p1[2], 0, 0, 0, 1, T); pp0[0] = p[0]; pp0[1] = p[1]; pp0[2] = p[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 1 pp0[0] = p2[0]; pp0[1] = p2[1]; pp0[2] = p2[2]; pp0[3] = 1.0; m4xv4(p2t, T, pp0); // Step 1 // Get the rotation angle around y-axis; dx = p2t[0]; dz = p2t[2]; projlen = sqrt(dx * dx + dz * dz); if (projlen <= (b->epsilon * 1e-2) * longest) { roty = 0; } else { roty = acos(dz / projlen); if (dx < 0) { roty = -roty; } } initm44(cos(-roty), 0, sin(-roty), 0, 0, 1, 0, 0, -sin(-roty), 0, cos(-roty), 0, 0, 0, 0, 1, T); pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 2 pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0; m4xv4(p2t, T, pp0); // Step 2 // Get the rotation angle around x-axis dy = p2t[1]; dz = p2t[2]; projlen = sqrt(dy * dy + dz * dz); if (projlen <= (b->epsilon * 1e-2) * longest) { rotx = 0; } else { rotx = acos(dz / projlen); if (dy < 0) { rotx = -rotx; } } initm44(1, 0, 0, 0, 0, cos(rotx), -sin(rotx), 0, 0, sin(rotx), cos(rotx), 0, 0, 0, 0, 1, T); pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 3 // pp0[0] = p2t[0]; pp0[1] = p2t[1]; pp0[2] = p2t[2]; pp0[3] = 1.0; // m4xv4(p2t, T, pp0); // Step 3 alphaR = rotangle; initm44(cos(alphaR), -sin(alphaR), 0, 0, sin(alphaR), cos(alphaR), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, T); pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 4 initm44(1, 0, 0, 0, 0, cos(-rotx), -sin(-rotx), 0, 0, sin(-rotx), cos(-rotx), 0, 0, 0, 0, 1, T); pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 5 initm44(cos(roty), 0, sin(roty), 0, 0, 1, 0, 0, -sin(roty), 0, cos(roty), 0, 0, 0, 0, 1, T); pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 6 initm44(1, 0, 0, p1[0], 0, 1, 0, p1[1], 0, 0, 1, p1[2], 0, 0, 0, 1, T); pp0[0] = p0t[0]; pp0[1] = p0t[1]; pp0[2] = p0t[2]; pp0[3] = 1.0; m4xv4(p0t, T, pp0); // Step 7 p[0] = p0t[0]; p[1] = p0t[1]; p[2] = p0t[2]; } /////////////////////////////////////////////////////////////////////////////// // // // planelineint() Calculate the intersection of a line and a plane. // // // // The equation of a plane (points P are on the plane with normal N and P3 // // on the plane) can be written as: N dot (P - P3) = 0. The equation of the // // line (points P on the line passing through P1 and P2) can be written as: // // P = P1 + u (P2 - P1). The intersection of these two occurs when: // // N dot (P1 + u (P2 - P1)) = N dot P3. // // Solving for u gives: // // N dot (P3 - P1) // // u = ------------------. // // N dot (P2 - P1) // // If the denominator is 0 then N (the normal to the plane) is perpendicular // // to the line. Thus the line is either parallel to the plane and there are // // no solutions or the line is on the plane in which case there are an infi- // // nite number of solutions. // // // // The plane is given by three points pa, pb, and pc, e1 and e2 defines the // // line. If u is non-zero, The intersection point (if exists) returns in ip. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::planelineint(REAL* pa, REAL* pb, REAL* pc, REAL* e1, REAL* e2, REAL* ip, REAL* u) { REAL n[3], det, det1; // Calculate N. facenormal2(pa, pb, pc, n, 1); // Calculate N dot (e2 - e1). det = n[0] * (e2[0] - e1[0]) + n[1] * (e2[1] - e1[1]) + n[2] * (e2[2] - e1[2]); if (det != 0.0) { // Calculate N dot (pa - e1) det1 = n[0] * (pa[0] - e1[0]) + n[1] * (pa[1] - e1[1]) + n[2] * (pa[2] - e1[2]); *u = det1 / det; ip[0] = e1[0] + *u * (e2[0] - e1[0]); ip[1] = e1[1] + *u * (e2[1] - e1[1]); ip[2] = e1[2] + *u * (e2[2] - e1[2]); } else { *u = 0.0; } } /////////////////////////////////////////////////////////////////////////////// // // // randomnation() Generate a random number between 0 and 'choices' - 1. // // // /////////////////////////////////////////////////////////////////////////////// unsigned long tetgenmesh::randomnation(unsigned int choices) { unsigned long newrandom; if (choices >= 714025l) { newrandom = (randomseed * 1366l + 150889l) % 714025l; randomseed = (newrandom * 1366l + 150889l) % 714025l; newrandom = newrandom * (choices / 714025l) + randomseed; if (newrandom >= choices) { return newrandom - choices; } else { return newrandom; } } else { randomseed = (randomseed * 1366l + 150889l) % 714025l; return randomseed % choices; } } /////////////////////////////////////////////////////////////////////////////// // // // distance2() Returns the square "distance" of a tetrahedron to point p. // // // /////////////////////////////////////////////////////////////////////////////// REAL tetgenmesh::distance2(tetrahedron* tetptr, point p) { point p1, p2, p3, p4; REAL dx, dy, dz; p1 = (point) tetptr[4]; p2 = (point) tetptr[5]; p3 = (point) tetptr[6]; p4 = (point) tetptr[7]; dx = p[0] - 0.25 * (p1[0] + p2[0] + p3[0] + p4[0]); dy = p[1] - 0.25 * (p1[1] + p2[1] + p3[1] + p4[1]); dz = p[2] - 0.25 * (p1[2] + p2[2] + p3[2] + p4[2]); return dx * dx + dy * dy + dz * dz; } /////////////////////////////////////////////////////////////////////////////// // // // preciselocate() Find a simplex containing a given point. // // // // This routine implements the simple Walk-through point location algorithm. // // Begins its search from 'searchtet', assume there is a line segment L from // // a vertex of 'searchtet' to the query point 'searchpt', and simply walk // // towards 'searchpt' by traversing all faces intersected by L. // // // // On completion, 'searchtet' is a tetrahedron that contains 'searchpt'. The // // returned value indicates one of the following cases: // // - ONVERTEX, the search point lies on the origin of 'searchtet'. // // - ONEDGE, the search point lies on an edge of 'searchtet'. // // - ONFACE, the search point lies on a face of 'searchtet'. // // - INTET, the search point lies in the interior of 'searchtet'. // // - OUTSIDE, the search point lies outside the mesh. 'searchtet' is a // // hull tetrahedron whose base face is visible by the search point. // // // // WARNING: This routine is designed for convex triangulations, and will not // // generally work after the holes and concavities have been carved. // // // // If 'maxtetnumber' > 0, stop the searching process if the number of passed // // tets is larger than it and return OUTSIDE. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::preciselocate(point searchpt, triface* searchtet, long maxtetnumber) { triface backtracetet; triface walkthroface; point forg, fdest, fapex, toppo; REAL ori1, ori2, ori3, ori4; long tetnumber; int side; if (isdead(searchtet)) searchtet->tet = dummytet; if (searchtet->tet == dummytet) { searchtet->loc = 0; symself(*searchtet); } // 'searchtet' should be a valid tetrahedron now. #ifdef SELF_CHECK assert(searchtet->tet != dummytet); #endif searchtet->ver = 0; // Keep in CCW edge ring. // Find a face of 'searchtet' such that the 'searchpt' lies strictly // above it. Such face should always exist. for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) { forg = org(*searchtet); fdest = dest(*searchtet); fapex = apex(*searchtet); ori1 = orient3d(forg, fdest, fapex, searchpt); if (ori1 < 0.0) break; } #ifdef SELF_CHECK assert(searchtet->loc < 4); #endif backtracetet = *searchtet; // Initialize backtracetet. // Define 'tetnumber' for exit the loop when it's running endless. tetnumber = 0l; while ((maxtetnumber > 0l) && (tetnumber <= maxtetnumber)) { ptloc_count++; // Algorithimic count. // Check if we are reaching the boundary of the triangulation. if (searchtet->tet == dummytet) { *searchtet = backtracetet; return OUTSIDE; } // Initialize the face for returning the walk-through face. walkthroface.tet = (tetrahedron *) NULL; // Adjust the edge ring, so that 'ori1 < 0.0' holds. searchtet->ver = 0; // 'toppo' remains unchange for the following orientation tests. toppo = oppo(*searchtet); // Check the three sides of 'searchtet' to find the face through which // we can walk next. for (side = 0; side < 3; side++) { forg = org(*searchtet); fdest = dest(*searchtet); ori2 = orient3d(forg, fdest, toppo, searchpt); if (ori2 == 0.0) { // They are coplanar, check if 'searchpt' lies inside, or on an edge, // or coindice with a vertex of face (forg, fdest, toppo). fapex = apex(*searchtet); ori3 = orient3d(fdest, fapex, toppo, searchpt); if (ori3 < 0.0) { // Outside the face (fdest, fapex, toppo), walk through it. enextself(*searchtet); fnext(*searchtet, walkthroface); break; } ori4 = orient3d(fapex, forg, toppo, searchpt); if (ori4 < 0.0) { // Outside the face (fapex, forg, toppo), walk through it. enext2self(*searchtet); fnext(*searchtet, walkthroface); break; } // Remember, ori1 < 0.0, which means that 'searchpt' will not on edge // (forg, fdest) or on vertex forg or fdest. // The rest possible cases are: // (1) 'searchpt' lies on edge (fdest, toppo); // (2) 'searchpt' lies on edge (toppo, forg); // (3) 'searchpt' coincident with toppo; // (4) 'searchpt' lies inside face (forg, fdest, toppo). fnextself(*searchtet); if (ori3 == 0.0) { if (ori4 == 0.0) { // Case (4). enext2self(*searchtet); return ONVERTEX; } else { // Case (1). enextself(*searchtet); return ONEDGE; } } if (ori4 == 0.0) { // Case (2). enext2self(*searchtet); return ONEDGE; } // Case (4). return ONFACE; } else if (ori2 < 0.0) { // Outside the face (forg, fdest, toppo), walk through it. fnext(*searchtet, walkthroface); break; } // Go to check next side. enextself(*searchtet); } if (side == 3) { // Found! Inside tetrahedron. return INTETRAHEDRON; } // We walk through the face 'walkthroface' and continue the searching. // Store the face handle in 'backtracetet' before we take the real walk. // So we are able to restore the handle to 'searchtet' if we are // reaching the outer boundary. backtracetet = walkthroface; sym(walkthroface, *searchtet); tetnumber++; } if (!b->quiet && b->verbose) { printf("Warning: Point location stopped after searching %ld tets.\n", maxtetnumber); } // terminatetetgen(2); return OUTSIDE; } /////////////////////////////////////////////////////////////////////////////// // // // randomsample() Randomly sample the tetrahedra for point loation. // // // // This routine implements Muecke's Jump-and-walk point location algorithm. // // It improves the simple walk-through by "jumping" to a good starting point // // via random sampling. Searching begins from one of handles: the input // // 'searchtet', a recently encountered tetrahedron 'recenttet', or from one // // chosen from a random sample. The choice is made by determining which one // // 's origin is closest to the point we are searcing for. Having chosen the // // starting tetrahedron, the simple Walk-through algorithm is executed. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::randomsample(point searchpt, triface *searchtet) { tetrahedron *firsttet, *tetptr; void **sampleblock; long sampleblocks, samplesperblock, samplenum; long tetblocks, i, j; unsigned long alignptr; REAL searchdist, dist; // 'searchtet' should be a valid tetrahedron. if (isdead(searchtet)) { searchtet->tet = dummytet; } if (searchtet->tet == dummytet) { // This is an 'Outer Space' handle, get a hull tetrahedron. searchtet->loc = 0; symself(*searchtet); } // Note 'searchtet' may be dead (chnaged in constrainedcavity2()). if (!isdead(searchtet)) { // Get the distance from the suggested starting tet to the point we seek. searchdist = distance2(searchtet->tet, searchpt); } else { searchdist = longest * longest; } // If a recently encountered tetrahedron has been recorded and has not // been deallocated, test it as a good starting point. if (!isdead(&recenttet) && (recenttet.tet != searchtet->tet)) { dist = distance2(recenttet.tet, searchpt); if (dist < searchdist) { *searchtet = recenttet; searchdist = dist; } } // Select "good" candidate using k random samples, taking the closest one. // The number of random samples taken is proportional to the fourth root // of the number of tetrahedra in the mesh. The next bit of code assumes // that the number of tetrahedra increases monotonically. while (SAMPLEFACTOR * samples * samples * samples * samples < tetrahedrons->items) { samples++; } // Find how much blocks in current tet pool. tetblocks = (tetrahedrons->maxitems + ELEPERBLOCK - 1) / ELEPERBLOCK; // Find the average samles per block. Each block at least have 1 sample. samplesperblock = 1 + (samples / tetblocks); sampleblocks = samples / samplesperblock; sampleblock = tetrahedrons->firstblock; for (i = 0; i < sampleblocks; i++) { alignptr = (unsigned long) (sampleblock + 1); firsttet = (tetrahedron *) (alignptr + (unsigned long) tetrahedrons->alignbytes - (alignptr % (unsigned long) tetrahedrons->alignbytes)); for (j = 0; j < samplesperblock; j++) { if (i == tetblocks - 1) { // This is the last block. samplenum = randomnation((int) (tetrahedrons->maxitems - (i * ELEPERBLOCK))); } else { samplenum = randomnation(ELEPERBLOCK); } tetptr = (tetrahedron *) (firsttet + (samplenum * tetrahedrons->itemwords)); if (tetptr[4] != (tetrahedron) NULL) { dist = distance2(tetptr, searchpt); if (dist < searchdist) { searchtet->tet = tetptr; searchdist = dist; } } } sampleblock = (void **) *sampleblock; } } /////////////////////////////////////////////////////////////////////////////// // // // locate() Find a simplex containing a given point. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::locate(point searchpt, triface *searchtet) { // Randomly sample for a good starting tet. randomsample(searchpt, searchtet); // Call simple walk-through to locate the point. return preciselocate(searchpt, searchtet, tetrahedrons->items); } /////////////////////////////////////////////////////////////////////////////// // // // locate2() Find a simplex containing a given point. // // // // Another implementation of the Walk-through point location algorithm. // // See the comments of preciselocate(). // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::locate2(point searchpt, triface* searchtet, arraypool *histtetarray) { triface neightet, backtracetet, *parytet; point torg, tdest, tapex, toppo, ntoppo; enum {ORGMOVE, DESTMOVE, APEXMOVE} nextmove; REAL ori, oriorg, oridest, oriapex; REAL searchdist, dist; enum locateresult loc; int i; if (searchtet->tet == dummytet) { // A hull tet. Choose the neighbor of its base face. searchtet->loc = 0; symself(*searchtet); } // Stay in the 0th edge ring. searchtet->ver = 0; // Let searchtet be the face such that 'searchpt' lies above to it. for (searchtet->loc = 0; searchtet->loc < 4; searchtet->loc++) { torg = org(*searchtet); tdest = dest(*searchtet); tapex = apex(*searchtet); ori = orient3d(torg, tdest, tapex, searchpt); orient3dcount++; if (ori < 0.0) break; } if (!(searchtet->loc < 4)) { // Either 'searchtet' is a very flat tet, or the 'searchpt' lies in // infinity, or both of them. Return OUTSIDE. return OUTSIDE; } if (histtetarray != NULL) { // Remember all the tets we've visited. assert(histtetarray->objects == 0l); infect(*searchtet); histtetarray->newindex((void **) &parytet); *parytet = *searchtet; } loc = OUTSIDE; // Set a default return value. // Walk through tetrahedra to locate the point. while (true) { ptloc_count++; // Algorithimic count. toppo = oppo(*searchtet); // Check if the vertex is we seek. if (toppo == searchpt) { // Adjust the origin of searchtet to be searchpt. fnextself(*searchtet); esymself(*searchtet); enext2self(*searchtet); loc = ONVERTEX; // return ONVERTEX; break; } // We enter from serarchtet's base face. There are three other faces in // searchtet (all connecting to toppo), which one is the exit? oriorg = orient3d(tdest, tapex, toppo, searchpt); oridest = orient3d(tapex, torg, toppo, searchpt); oriapex = orient3d(torg, tdest, toppo, searchpt); orient3dcount+=3; // Now decide which face to move. It is possible there are more than one // faces are viable moves. Use the opposite points of thier neighbors // to discriminate, i.e., we choose the face whose opposite point has // the shortest distance to searchpt. if (oriorg < 0) { if (oridest < 0) { if (oriapex < 0) { // Any of the three faces is a viable move. nextmove = ORGMOVE; enextfnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); searchdist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { dist = searchdist; } if (dist < searchdist) { nextmove = DESTMOVE; searchdist = dist; } fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { dist = searchdist; } if (dist < searchdist) { nextmove = APEXMOVE; searchdist = dist; } } else { // Two faces, opposite to origin and destination, are viable. nextmove = ORGMOVE; enextfnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); searchdist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { dist = searchdist; } if (dist < searchdist) { nextmove = DESTMOVE; searchdist = dist; } } } else { if (oriapex < 0) { // Two faces, opposite to origin and apex, are viable. nextmove = ORGMOVE; enextfnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); searchdist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { dist = searchdist; } if (dist < searchdist) { nextmove = APEXMOVE; searchdist = dist; } } else { // Only the face opposite to origin is viable. nextmove = ORGMOVE; } } } else { if (oridest < 0) { if (oriapex < 0) { // Two faces, opposite to destination and apex, are viable. nextmove = DESTMOVE; enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); searchdist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { searchdist = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { ntoppo = oppo(neightet); dist = NORM2(searchpt[0] - ntoppo[0], searchpt[1] - ntoppo[1], searchpt[2] - ntoppo[2]); } else { dist = searchdist; } if (dist < searchdist) { nextmove = APEXMOVE; searchdist = dist; } } else { // Only the face opposite to destination is viable. nextmove = DESTMOVE; } } else { if (oriapex < 0) { // Only the face opposite to apex is viable. nextmove = APEXMOVE; } else { // The point we seek must be on the boundary of or inside this // tetrahedron. Check for boundary cases. if (oriorg == 0) { // Go to the face opposite to origin. enextfnextself(*searchtet); if (oridest == 0) { enextself(*searchtet); // edge apex->oppo if (oriapex == 0) { enextself(*searchtet); // oppo is duplicated with p. loc = ONVERTEX; // return ONVERTEX; break; } loc = ONEDGE; // return ONEDGE; break; } if (oriapex == 0) { enext2self(*searchtet); loc = ONEDGE; // return ONEDGE; break; } loc = ONFACE; // return ONFACE; break; } if (oridest == 0) { // Go to the face opposite to destination. enext2fnextself(*searchtet); if (oriapex == 0) { enextself(*searchtet); loc = ONEDGE; // return ONEDGE; break; } loc = ONFACE; // return ONFACE; break; } if (oriapex == 0) { // Go to the face opposite to apex fnextself(*searchtet); loc = ONFACE; // return ONFACE; break; } loc = INTETRAHEDRON; // return INTETRAHEDRON; break; } } } // Move to the selected face. if (nextmove == ORGMOVE) { enextfnextself(*searchtet); } else if (nextmove == DESTMOVE) { enext2fnextself(*searchtet); } else { fnextself(*searchtet); } // Move to the adjacent tetrahedron (maybe a hull tetrahedron). backtracetet = *searchtet; symself(*searchtet); if (searchtet->tet == dummytet) { *searchtet = backtracetet; loc = OUTSIDE; // return OUTSIDE; break; } if (histtetarray != NULL) { // Check if we have run into a loop. if (infected(*searchtet)) { // We have visited this tet. A potential loop is found. loc = OUTSIDE; break; } else { // Remember this tet. infect(*searchtet); histtetarray->newindex((void **) &parytet); *parytet = *searchtet; } } // Retreat the three vertices of the base face. searchtet->ver = 0; torg = org(*searchtet); tdest = dest(*searchtet); tapex = apex(*searchtet); } // while (true) if (histtetarray != NULL) { // Unmark the visited tets. for (i = 0; i < (int) histtetarray->objects; i++) { parytet = (triface *) fastlookup(histtetarray, i); uninfect(*parytet); } histtetarray->restart(); } return loc; } /////////////////////////////////////////////////////////////////////////////// // // // adjustlocate() Adjust the precise location of a vertex. // // // // 'precise' is the value returned from preciselocate(). It indicates the // // exact location of the point 'searchpt' with respect to the tetrahedron // // 'searchtet'. 'epspp' is a given relative tolerance. // // // // This routine re-evaluates the orientations of searchpt with respect to // // the four sides of searchtet. Detects the coplanarities by additinal tests // // which are based on the given tolerance. If 'precise' is ONFACE or ONEDGE, // // we can save one or two orientation tests. // // // // The return value indicates the location of the 'searchpt' (INTETRAHEDRON, // // or ONFACE, ...). 'searchtet' is adjusted to a tetrahedron corresponding // // to that value. See the introduction part of preciselocate(). // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::adjustlocate(point searchpt, triface* searchtet, enum locateresult precise, REAL epspp) { point torg, tdest, tapex, toppo; REAL s1, s2, s3, s4; // For the given 'searchtet', the orientations tests are: // s1: (tdest, torg, tapex, searchpt); // s2: (torg, tdest, toppo, searchpt); // s3: (tdest, tapex, toppo, searchpt); // s4: (tapex, torg, toppo, searchpt); adjustedgering(*searchtet, CCW); torg = org(*searchtet); tdest = dest(*searchtet); tapex = apex(*searchtet); toppo = oppo(*searchtet); switch (precise) { case ONVERTEX: // This case we don't need do any further test. return ONVERTEX; case ONEDGE: // (torg, tdest); s1 = 0.0; s2 = 0.0; break; case ONFACE: // (tdest, torg, tapex); s1 = 0.0; s2 = orient3d(torg, tdest, toppo, searchpt); break; default: // INTETRAHEDRON or OUTSIDE s1 = orient3d(tdest, torg, tapex, searchpt); s2 = orient3d(torg, tdest, toppo, searchpt); } if (s1 != 0.0) { if (iscoplanar(tdest, torg, tapex, searchpt, s1, epspp)) { s1 = 0.0; } } if (s1 < 0.0) { return OUTSIDE; } if (s2 != 0.0) { if (iscoplanar(torg, tdest, toppo, searchpt, s2, epspp)) { s2 = 0.0; } } if (s2 < 0.0) { fnextself(*searchtet); return OUTSIDE; } s3 = orient3d(tdest, tapex, toppo, searchpt); if (s3 != 0.0) { if (iscoplanar(tdest, tapex, toppo, searchpt, s3, epspp)) { s3 = 0.0; } } if (s3 < 0.0) { enextfnextself(*searchtet); return OUTSIDE; } s4 = orient3d(tapex, torg, toppo, searchpt); if (s4 != 0.0) { if (iscoplanar(tapex, torg, toppo, searchpt, s4, epspp)) { s4 = 0.0; } } if (s4 < 0.0) { enext2fnextself(*searchtet); return OUTSIDE; } // Determine degenerate cases. if (s1 == 0.0) { if (s2 == 0.0) { if (s3 == 0.0) { // On tdest. enextself(*searchtet); return ONVERTEX; } if (s4 == 0.0) { // On torg. return ONVERTEX; } // On edge (torg, tdest). return ONEDGE; } if (s3 == 0.0) { if (s4 == 0.0) { // On tapex. enext2self(*searchtet); return ONVERTEX; } // On edge (tdest, tapex). enextself(*searchtet); return ONEDGE; } if (s4 == 0.0) { // On edge (tapex, torg). enext2self(*searchtet); return ONEDGE; } // On face (torg, tdest, tapex). return ONFACE; } if (s2 == 0.0) { fnextself(*searchtet); if (s3 == 0.0) { if (s4 == 0.0) { // On toppo. enext2self(*searchtet); return ONVERTEX; } // On edge (tdest, toppo). enextself(*searchtet); return ONEDGE; } if (s4 == 0.0) { // On edge (toppo, torg). enext2self(*searchtet); return ONEDGE; } // On face (torg, tdest, toppo). return ONFACE; } if (s3 == 0.0) { enextfnextself(*searchtet); if (s4 == 0.0) { // On edge (tapex, toppo). enextself(*searchtet); return ONEDGE; } // On face (tdest, tapex, toppo). return ONFACE; } if (s4 == 0.0) { enext2fnextself(*searchtet); // On face (tapex, torg, toppo). return ONFACE; } // Inside tetrahedron. return INTETRAHEDRON; } /////////////////////////////////////////////////////////////////////////////// // // // hullwalk() Find a tetrahedron on the hull to continue search. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::hullwalk(point searchpt, triface *hulltet) { list* travtetlist; triface travtet, neightet; point pa, pb, pc, pp[3]; enum locateresult loc; REAL prjpt[3]; REAL ori; int i, j; travtetlist = new list(sizeof(triface), NULL, 256); travtet = *hulltet; infect(travtet); travtetlist->append(&travtet); loc = OUTSIDE; for (i = 0; i < travtetlist->len(); i++) { travtet = * (triface *)(* travtetlist)[i]; // Choose the CCW-edgering in face. travtet.ver = 0; // Look for a side where pt lies below it. for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) { pa = org(travtet); pb = dest(travtet); pc = apex(travtet); ori = orient3d(pa, pb, pc, searchpt); if (ori > 0.0) break; } // Is pt above all (or coplanar with some of) the four sides? if (travtet.loc == 4) { hulltet->tet = travtet.tet; loc = adjustlocate(searchpt, hulltet, INTETRAHEDRON, b->epsilon); assert(loc != OUTSIDE); } else { // ori > 0.0 // pt is below (behind) this side. We want to walk through it. sym(travtet, neightet); if (neightet.tet == dummytet) { // This is a hull side. Is p approximately on this side. loc = adjustlocate(searchpt, &travtet, OUTSIDE, b->epsilon); } if (loc == OUTSIDE) { // searchpt is outside the hull face. Project it on the face. travtet.ver = 1; pp[0] = org(travtet); pp[1] = dest(travtet); pp[2] = apex(travtet); projpt2face(searchpt, pp[0], pp[1], pp[2], prjpt); // check if project point inside the hull face. for (j = 0; j < 3; j++) { ori = orient3d(pp[j], pp[(j+1)%3], searchpt, prjpt); if (ori < 0.0) break; // Stop if it lies ouside. } if (ori >= 0.0) { // Yes, return this tet. *hulltet = travtet; } // Let's collect all the neighbors for next searching. for (travtet.loc = 0; travtet.loc < 4; travtet.loc++) { sym(travtet, neightet); if ((neightet.tet != dummytet) && !infected(neightet)) { // Neighbor exists and not visited. infect(neightet); travtetlist->append(&neightet); } } // for (travtet.loc = 0; } // if (loc == OUTSIDE) } // if (travtet.loc == 4) if (loc != OUTSIDE) break; } // for (i = 0; i < travtetlist->len(); i++) // Uninfect traversed tets. for (i = 0; i < travtetlist->len(); i++) { travtet = * (triface *)(* travtetlist)[i]; uninfect(travtet); } delete travtetlist; return loc; } /////////////////////////////////////////////////////////////////////////////// // // // locatesub() Find a point in the surface mesh of a facet. // // // // Searching begins from the input 'searchsh', it should be a handle on the // // convex hull of the facet triangulation. // // // // If 'stopatseg' is nonzero, the search will stop if it tries to walk // // through a subsegment, and will return OUTSIDE. // // // // On completion, 'searchsh' is a subface that contains 'searchpt'. // // - Returns ONVERTEX if the point lies on an existing vertex. 'searchsh' // // is a handle whose origin is the existing vertex. // // - Returns ONEDGE if the point lies on a mesh edge. 'searchsh' is a // // handle whose primary edge is the edge on which the point lies. // // - Returns ONFACE if the point lies strictly within a subface. // // 'searchsh' is a handle on which the point lies. // // - Returns OUTSIDE if the point lies outside the triangulation. // // // // WARNING: This routine is designed for convex triangulations, and will not // // not generally work after the holes and concavities have been carved. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::locatesub(point searchpt, face* searchsh, int stopatseg, REAL epspp) { face backtracksh, spinsh, checkedge; point forg, fdest, fapex; REAL orgori, destori; REAL ori, sign; int moveleft, i; if (searchsh->sh == dummysh) { searchsh->shver = 0; spivotself(*searchsh); #ifdef SELF_CHECK assert(searchsh->sh != dummysh); #endif } // Find the sign to simulate that abovepoint is 'above' the facet. adjustedgering(*searchsh, CCW); forg = sorg(*searchsh); fdest = sdest(*searchsh); fapex = sapex(*searchsh); ori = orient3d(forg, fdest, fapex, abovepoint); sign = ori > 0.0 ? -1 : 1; // Orient 'searchsh' so that 'searchpt' is below it (i.e., searchpt has // CCW orientation with respect to searchsh in plane). Such edge // should always exist. Save it as (forg, fdest). for (i = 0; i < 3; i++) { forg = sorg(*searchsh); fdest = sdest(*searchsh); ori = orient3d(forg, fdest, abovepoint, searchpt) * sign; if (ori > 0.0) break; senextself(*searchsh); } #ifdef SELF_CHECK assert(i < 3); #endif while (1) { fapex = sapex(*searchsh); // Check whether the apex is the point we seek. if (fapex[0] == searchpt[0] && fapex[1] == searchpt[1] && fapex[2] == searchpt[2]) { senext2self(*searchsh); return ONVERTEX; } // Does the point lie on the other side of the line defined by the // triangle edge opposite the triangle's destination? destori = orient3d(forg, fapex, abovepoint, searchpt) * sign; if (epspp > 0.0) { if (iscoplanar(forg, fapex, abovepoint, searchpt, destori, epspp)) { destori = 0.0; } } // Does the point lie on the other side of the line defined by the // triangle edge opposite the triangle's origin? orgori = orient3d(fapex, fdest, abovepoint, searchpt) * sign; if (epspp > 0.0) { if (iscoplanar(fapex, fdest, abovepoint, searchpt, orgori, epspp)) { orgori = 0.0; } } if (destori > 0.0) { moveleft = 1; } else { if (orgori > 0.0) { moveleft = 0; } else { // The point must be on the boundary of or inside this triangle. if (destori == 0.0) { senext2self(*searchsh); return ONEDGE; } if (orgori == 0.0) { senextself(*searchsh); return ONEDGE; } return ONFACE; } } // Move to another triangle. Leave a trace `backtracksh' in case // walking off a boundary of the triangulation. if (moveleft) { senext2(*searchsh, backtracksh); fdest = fapex; } else { senext(*searchsh, backtracksh); forg = fapex; } // Check if we meet a segment. sspivot(backtracksh, checkedge); if (checkedge.sh != dummysh) { if (stopatseg) { // The flag indicates we should not cross a segment. Stop. *searchsh = backtracksh; return OUTSIDE; } // Try to walk through a segment. We need to find a coplanar subface // sharing this segment to get into. spinsh = backtracksh; do { spivotself(spinsh); if (spinsh.sh == backtracksh.sh) { // Turn back, no coplanar subface is found. break; } // Are they belong to the same facet. if (shellmark(spinsh) == shellmark(backtracksh)) { // Find a coplanar subface. Walk into it. *searchsh = spinsh; break; } // Are they (nearly) coplanar? ori = orient3d(forg, fdest, sapex(backtracksh), sapex(spinsh)); if (iscoplanar(forg, fdest, sapex(backtracksh), sapex(spinsh), ori, b->epsilon)) { // Find a coplanar subface. Walk into it. *searchsh = spinsh; break; } } while (spinsh.sh != backtracksh.sh); } else { spivot(backtracksh, *searchsh); } // Check for walking right out of the triangulation. if ((searchsh->sh == dummysh) || (searchsh->sh == backtracksh.sh)) { // Go back to the last triangle. *searchsh = backtracksh; return OUTSIDE; } // To keep the same orientation wrt abovepoint. if (sorg(*searchsh) != forg) sesymself(*searchsh); #ifdef SELF_CHECK assert((sorg(*searchsh) == forg) && (sdest(*searchsh) == fdest)); #endif } } /////////////////////////////////////////////////////////////////////////////// // // // adjustlocatesub() Adjust the precise location of a vertex. // // // // 'precise' is the precise location (returned from locatesub()) of 'searcht'// // with respect to 'searchsh'. 'epspp' is the given relative tolerance. // // // // This routine re-evaluates the orientations of 'searchpt' with respect to // // the three edges of 'searchsh'. Detects the collinearities by additinal // // tests based on the given tolerance. If 'precise' is ONEDGE, one can save // // one orientation test for the current edge of 'searchsh'. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh:: adjustlocatesub(point searchpt, face* searchsh, enum locateresult precise, REAL epspp) { point pa, pb, pc; bool s1, s2, s3; pa = sorg(*searchsh); pb = sdest(*searchsh); pc = sapex(*searchsh); if (precise == ONEDGE) { s1 = true; } else { s1 = iscollinear(pa, pb, searchpt, epspp); } s2 = iscollinear(pb, pc, searchpt, epspp); s3 = iscollinear(pc, pa, searchpt, epspp); if (s1) { if (s2) { // on vertex pb. #ifdef SELF_CHECK assert(!s3); #endif senextself(*searchsh); return ONVERTEX; } else if (s3) { // on vertex pa. return ONVERTEX; } else { // on edge pa->pb. return ONEDGE; } } else if (s2) { if (s3) { // on vertex pc. senext2self(*searchsh); return ONVERTEX; } else { // on edge pb->pc. senextself(*searchsh); return ONEDGE; } } else if (s3) { // on edge pc->pa. senext2self(*searchsh); return ONEDGE; } else { return precise; } } /////////////////////////////////////////////////////////////////////////////// // // // locateseg() Find a point in subsegments. // // // // Searching begins from the input 'searchseg', it should be a subsegment of // // the whole segment. // // // // On completion, 'searchseg' is a subsegment that contains 'searchpt'. // // - Returns ONVERTEX if the point lies on an existing vertex. 'searchseg' // // is a handle whose origin is the existing vertex. // // - Returns ONEDGE if the point lies inside 'searchseg'. // // - Returns OUTSIDE if the point lies outside the segment. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh:: locateseg(point searchpt, face* searchseg) { face backtraceseg; point pa, pb; REAL dx, dy, dz; int moveleft; int i; moveleft = 0; while (1) { searchseg->shver = 0; pa = sorg(*searchseg); pb = sdest(*searchseg); // Find the biggest difference in x, y, and z coordinates of a and b. dx = fabs(pb[0] - pa[0]); dy = fabs(pb[1] - pa[1]); dz = fabs(pb[2] - pa[2]); if (dx > dy) { if (dx > dz) { i = 0; } else { i = 2; } } else { if (dy > dz) { i = 1; } else { i = 2; } } if (pa[i] < pb[i]) { if (searchpt[i] < pa[i]) { moveleft = 1; } else if (searchpt[i] > pa[i]) { if (searchpt[i] < pb[i]) { return ONEDGE; } else if (searchpt[i] > pb[i]) { moveleft = 0; } else { #ifdef SELF_CHECK assert(searchpt[i] == pb[i]); #endif sesymself(*searchseg); return ONVERTEX; } } else { #ifdef SELF_CHECK assert(searchpt[i] == pa[i]); #endif return ONVERTEX; } } else if (pa[i] > pb[i]) { if (searchpt[i] < pb[i]) { moveleft = 0; } else if (searchpt[i] > pb[i]) { if (searchpt[i] < pa[i]) { return ONEDGE; } else if (searchpt[i] > pa[i]) { moveleft = 1; } else { #ifdef SELF_CHECK assert(searchpt[i] == pa[i]); #endif return ONVERTEX; } } else { #ifdef SELF_CHECK assert(searchpt[i] == pb[i]); #endif sesymself(*searchseg); return ONVERTEX; } } backtraceseg = *searchseg; if (moveleft) { senext2self(*searchseg); } else { senextself(*searchseg); } spivotself(*searchseg); if (searchseg->sh == dummysh) { *searchseg = backtraceseg; break; } } return OUTSIDE; } /////////////////////////////////////////////////////////////////////////////// // // // adjustlocateseg() Adjust the precise location of a vertex on segment. // // // // 'searchpt' is either inside or ouside the segment 'searchseg'. It will be // // adjusted to on vertex if it is very close to an endpoint of 'searchseg'. // // 'epspp' is the given relative tolerance. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh:: adjustlocateseg(point searchpt, face* searchseg, enum locateresult precise, REAL epspp) { point pa, pb; REAL L, d, r; pa = sorg(*searchseg); pb = sdest(*searchseg); L = distance(pa, pb); // Is searchpt approximate to pa? d = distance(pa, searchpt); r = d / L; if (r <= epspp) { return ONVERTEX; } // Is searchpt approximate to pb? d = distance(pb, searchpt); r = d / L; if (r <= epspp) { sesymself(*searchseg); return ONVERTEX; } return precise; } //// //// //// //// //// geom_cxx ///////////////////////////////////////////////////////////////// //// flip_cxx ///////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // enqueueflipface(), enqueueflipedge() Queue a face (or an edge). // // // // The face (or edge) may be non-locally Delaunay. It is queued for process- // // ing in flip() (or flipsub()). The vertices of the face (edge) are stored // // seperatly to ensure the face (or edge) is still the same one when we save // // it since other flips will cause this face (or edge) be changed or dead. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::enqueueflipface(triface& checkface, queue* flipqueue) { badface *queface; triface symface; sym(checkface, symface); if (symface.tet != dummytet) { queface = (badface *) flipqueue->push((void *) NULL); queface->tt = checkface; queface->foppo = oppo(symface); } } void tetgenmesh::enqueueflipedge(face& checkedge, queue* flipqueue) { badface *queface; queface = (badface *) flipqueue->push((void *) NULL); queface->ss = checkedge; queface->forg = sorg(checkedge); queface->fdest = sdest(checkedge); } /////////////////////////////////////////////////////////////////////////////// // // // flip23() Perform a 2-to-3 flip. // // // // On input, 'flipface' represents the face will be flipped. Let it is abc, // // the two tetrahedra sharing abc are abcd, bace. abc is not a subface. // // // // A 2-to-3 flip is to change two tetrahedra abcd, bace to three tetrahedra // // edab, edbc, and edca. As a result, face abc has been removed and three // // new faces eda, edb and edc have been created. // // // // On completion, 'flipface' returns edab. If 'flipqueue' is not NULL, all // // possibly non-Delaunay faces are added into it. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::flip23(triface* flipface, queue* flipqueue) { triface abcd, bace; // Old configuration. triface oldabd, oldbcd, oldcad; triface abdcasing, bcdcasing, cadcasing; triface oldbae, oldcbe, oldace; triface baecasing, cbecasing, acecasing; triface worktet; face abdsh, bcdsh, cadsh; // The six subfaces on the CH. face baesh, cbesh, acesh; face abseg, bcseg, caseg; // The nine segs on the CH. face adseg, bdseg, cdseg; face aeseg, beseg, ceseg; triface edab, edbc, edca; // New configuration. point pa, pb, pc, pd, pe; REAL attrib, volume; int i; abcd = *flipface; adjustedgering(abcd, CCW); // abcd represents edge ab. pa = org(abcd); pb = dest(abcd); pc = apex(abcd); pd = oppo(abcd); // sym(abcd, bace); // findedge(&bace, dest(abcd), org(abcd)); // bace represents edge ba. sym(abcd, bace); bace.ver = 0; // CCW. for (i = 0; (i < 3) && (org(bace) != pb); i++) { enextself(bace); } pe = oppo(bace); if (b->verbose > 1) { printf(" Do T23 on face (%d, %d, %d) %d, %d.\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd), pointmark(pe)); } flip23s++; // Storing the old configuration outside the convex hull. fnext(abcd, oldabd); enextfnext(abcd, oldbcd); enext2fnext(abcd, oldcad); fnext(bace, oldbae); enext2fnext(bace, oldcbe); enextfnext(bace, oldace); sym(oldabd, abdcasing); sym(oldbcd, bcdcasing); sym(oldcad, cadcasing); sym(oldbae, baecasing); sym(oldcbe, cbecasing); sym(oldace, acecasing); if (checksubfaces) { tspivot(oldabd, abdsh); tspivot(oldbcd, bcdsh); tspivot(oldcad, cadsh); tspivot(oldbae, baesh); tspivot(oldcbe, cbesh); tspivot(oldace, acesh); } if (checksubsegs) { tsspivot1(abcd, abseg); enext(abcd, worktet); tsspivot1(worktet, bcseg); enext2(abcd, worktet); tsspivot1(worktet, caseg); enext2(oldabd, worktet); tsspivot1(worktet, adseg); enext2(oldbcd, worktet); tsspivot1(worktet, bdseg); enext2(oldcad, worktet); tsspivot1(worktet, cdseg); enext(oldbae, worktet); tsspivot1(worktet, aeseg); enext(oldcbe, worktet); tsspivot1(worktet, beseg); enext(oldace, worktet); tsspivot1(worktet, ceseg); } // Creating the new configuration inside the convex hull. edab.tet = abcd.tet; // Update abcd to be edab. setorg (edab, pe); setdest(edab, pd); setapex(edab, pa); setoppo(edab, pb); edbc.tet = bace.tet; // Update bace to be edbc. setorg (edbc, pe); setdest(edbc, pd); setapex(edbc, pb); setoppo(edbc, pc); maketetrahedron(&edca); // Create edca. setorg (edca, pe); setdest(edca, pd); setapex(edca, pc); setoppo(edca, pa); // Set the element attributes of the new tetrahedron 'edca'. for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(abcd.tet, i); setelemattribute(edca.tet, i, attrib); } // Set the volume constraint of the new tetrahedron 'edca' if the -ra // switches are not used together. In -ra case, the various volume // constraints can be spreaded very far. if (b->varvolume && !b->refine) { volume = volumebound(abcd.tet); setvolumebound(edca.tet, volume); } // Clear old bonds in edab(was abcd) and edbc(was bace). for (i = 0; i < 4; i ++) { edab.tet[i] = (tetrahedron) dummytet; } for (i = 0; i < 4; i ++) { edbc.tet[i] = (tetrahedron) dummytet; } // Bond the faces inside the convex hull. edab.loc = 0; edca.loc = 1; bond(edab, edca); edab.loc = 1; edbc.loc = 0; bond(edab, edbc); edbc.loc = 1; edca.loc = 0; bond(edbc, edca); // Bond the faces on the convex hull. edab.loc = 2; bond(edab, abdcasing); edab.loc = 3; bond(edab, baecasing); edbc.loc = 2; bond(edbc, bcdcasing); edbc.loc = 3; bond(edbc, cbecasing); edca.loc = 2; bond(edca, cadcasing); edca.loc = 3; bond(edca, acecasing); // There may exist subfaces that need to be bonded to new configuarton. if (checksubfaces) { // Clear old flags in edab(was abcd) and edbc(was bace). for (i = 0; i < 4; i ++) { edab.loc = i; tsdissolve(edab); edbc.loc = i; tsdissolve(edbc); } if (abdsh.sh != dummysh) { edab.loc = 2; tsbond(edab, abdsh); } if (baesh.sh != dummysh) { edab.loc = 3; tsbond(edab, baesh); } if (bcdsh.sh != dummysh) { edbc.loc = 2; tsbond(edbc, bcdsh); } if (cbesh.sh != dummysh) { edbc.loc = 3; tsbond(edbc, cbesh); } if (cadsh.sh != dummysh) { edca.loc = 2; tsbond(edca, cadsh); } if (acesh.sh != dummysh) { edca.loc = 3; tsbond(edca, acesh); } } if (checksubsegs) { for (i = 0; i < 6; i++) { edab.loc = edge2locver[i][0]; edab.ver = edge2locver[i][1]; tssdissolve1(edab); } for (i = 0; i < 6; i++) { edbc.loc = edge2locver[i][0]; edbc.ver = edge2locver[i][1]; tssdissolve1(edbc); } edab.loc = edab.ver = 0; edbc.loc = edab.ver = 0; edca.loc = edab.ver = 0; // Operate in tet edab (5 edges). enext(edab, worktet); tssbond1(worktet, adseg); enext2(edab, worktet); tssbond1(worktet, aeseg); fnext(edab, worktet); enextself(worktet); tssbond1(worktet, bdseg); enextself(worktet); tssbond1(worktet, beseg); enextfnext(edab, worktet); enextself(worktet); tssbond1(worktet, abseg); // Operate in tet edbc (5 edges) enext(edbc, worktet); tssbond1(worktet, bdseg); enext2(edbc, worktet); tssbond1(worktet, beseg); fnext(edbc, worktet); enextself(worktet); tssbond1(worktet, cdseg); enextself(worktet); tssbond1(worktet, ceseg); enextfnext(edbc, worktet); enextself(worktet); tssbond1(worktet, bcseg); // Operate in tet edca (5 edges) enext(edca, worktet); tssbond1(worktet, cdseg); enext2(edca, worktet); tssbond1(worktet, ceseg); fnext(edca, worktet); enextself(worktet); tssbond1(worktet, adseg); enextself(worktet); tssbond1(worktet, aeseg); enextfnext(edca, worktet); enextself(worktet); tssbond1(worktet, caseg); } edab.loc = 0; edbc.loc = 0; edca.loc = 0; if (b->verbose > 3) { printf(" Updating edab "); printtet(&edab); printf(" Updating edbc "); printtet(&edbc); printf(" Creating edca "); printtet(&edca); } // Update point-to-tet map. setpoint2tet(pa, encode(edab)); setpoint2tet(pb, encode(edab)); setpoint2tet(pc, encode(edbc)); setpoint2tet(pd, encode(edab)); setpoint2tet(pe, encode(edab)); if (flipqueue != (queue *) NULL) { enextfnext(edab, abdcasing); enqueueflipface(abdcasing, flipqueue); enext2fnext(edab, baecasing); enqueueflipface(baecasing, flipqueue); enextfnext(edbc, bcdcasing); enqueueflipface(bcdcasing, flipqueue); enext2fnext(edbc, cbecasing); enqueueflipface(cbecasing, flipqueue); enextfnext(edca, cadcasing); enqueueflipface(cadcasing, flipqueue); enext2fnext(edca, acecasing); enqueueflipface(acecasing, flipqueue); } // Save a live handle in 'recenttet'. recenttet = edbc; // Set the return handle be edab. *flipface = edab; } /////////////////////////////////////////////////////////////////////////////// // // // flip32() Perform a 3-to-2 flip. // // // // On input, 'flipface' represents the face will be flipped. Let it is eda, // // where edge ed is locally non-convex. Three tetrahedra sharing ed are edab,// // edbc, and edca. ed is not a subsegment. // // // // A 3-to-2 flip is to change the three tetrahedra edab, edbc, and edca into // // another two tetrahedra abcd and bace. As a result, the edge ed has been // // removed and the face abc has been created. // // // // On completion, 'flipface' returns abcd. If 'flipqueue' is not NULL, all // // possibly non-Delaunay faces are added into it. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::flip32(triface* flipface, queue* flipqueue) { triface edab, edbc, edca; // Old configuration. triface oldabd, oldbcd, oldcad; triface abdcasing, bcdcasing, cadcasing; triface oldbae, oldcbe, oldace; triface baecasing, cbecasing, acecasing; triface worktet; face abdsh, bcdsh, cadsh; face baesh, cbesh, acesh; face abseg, bcseg, caseg; // The nine segs on the CH. face adseg, bdseg, cdseg; face aeseg, beseg, ceseg; triface abcd, bace; // New configuration. point pa, pb, pc, pd, pe; int i; edab = *flipface; adjustedgering(edab, CCW); pa = apex(edab); pb = oppo(edab); pd = dest(edab); pe = org(edab); fnext(edab, edbc); symself(edbc); edbc.ver = 0; for (i = 0; (i < 3) && (org(edbc) != pe); i++) { enextself(edbc); } pc = oppo(edbc); fnext(edbc, edca); symself(edca); edca.ver = 0; for (i = 0; (i < 3) && (org(edca) != pe); i++) { enextself(edca); } if (b->verbose > 1) { printf(" Do T32 on edge (%d, %d) %d, %d, %d.\n", pointmark(pe), pointmark(pd), pointmark(pa), pointmark(pb), pointmark(pc)); } flip32s++; // Storing the old configuration outside the convex hull. enextfnext(edab, oldabd); enext2fnext(edab, oldbae); enextfnext(edbc, oldbcd); enext2fnext(edbc, oldcbe); enextfnext(edca, oldcad); enext2fnext(edca, oldace); sym(oldabd, abdcasing); sym(oldbcd, bcdcasing); sym(oldcad, cadcasing); sym(oldbae, baecasing); sym(oldcbe, cbecasing); sym(oldace, acecasing); if (checksubfaces) { tspivot(oldabd, abdsh); tspivot(oldbcd, bcdsh); tspivot(oldcad, cadsh); tspivot(oldbae, baesh); tspivot(oldcbe, cbesh); tspivot(oldace, acesh); } if (checksubsegs) { enext(edab, worktet); tsspivot1(worktet, adseg); enext2(edab, worktet); tsspivot1(worktet, aeseg); enext(edbc, worktet); tsspivot1(worktet, bdseg); enext2(edbc, worktet); tsspivot1(worktet, beseg); enext(edca, worktet); tsspivot1(worktet, cdseg); enext2(edca, worktet); tsspivot1(worktet, ceseg); enextfnext(edab, worktet); enextself(worktet); tsspivot1(worktet, abseg); enextfnext(edbc, worktet); enextself(worktet); tsspivot1(worktet, bcseg); enextfnext(edca, worktet); enextself(worktet); tsspivot1(worktet, caseg); } // Creating the new configuration inside the convex hull. abcd.tet = edab.tet; // Update edab to be abcd. setorg (abcd, pa); setdest(abcd, pb); setapex(abcd, pc); setoppo(abcd, pd); bace.tet = edbc.tet; // Update edbc to be bace. setorg (bace, pb); setdest(bace, pa); setapex(bace, pc); setoppo(bace, pe); // Dealloc a redundant tetrahedron (edca). tetrahedrondealloc(edca.tet); // Clear the old bonds in abcd (was edab) and bace (was edbc). for (i = 0; i < 4; i ++) { abcd.tet[i] = (tetrahedron) dummytet; } for (i = 0; i < 4; i ++) { bace.tet[i] = (tetrahedron) dummytet; } // Bond the inside face of the convex hull. abcd.loc = 0; bace.loc = 0; bond(abcd, bace); // Bond the outside faces of the convex hull. abcd.loc = 1; bond(abcd, abdcasing); abcd.loc = 2; bond(abcd, bcdcasing); abcd.loc = 3; bond(abcd, cadcasing); bace.loc = 1; bond(bace, baecasing); bace.loc = 3; bond(bace, cbecasing); bace.loc = 2; bond(bace, acecasing); if (checksubfaces) { // Clear old bonds in abcd(was edab) and bace(was edbc). for (i = 0; i < 4; i ++) { abcd.loc = i; tsdissolve(abcd); } for (i = 0; i < 4; i ++) { bace.loc = i; tsdissolve(bace); } if (abdsh.sh != dummysh) { abcd.loc = 1; tsbond(abcd, abdsh); } if (bcdsh.sh != dummysh) { abcd.loc = 2; tsbond(abcd, bcdsh); } if (cadsh.sh != dummysh) { abcd.loc = 3; tsbond(abcd, cadsh); } if (baesh.sh != dummysh) { bace.loc = 1; tsbond(bace, baesh); } if (cbesh.sh != dummysh) { bace.loc = 3; tsbond(bace, cbesh); } if (acesh.sh != dummysh) { bace.loc = 2; tsbond(bace, acesh); } } if (checksubsegs) { for (i = 0; i < 6; i++) { abcd.loc = edge2locver[i][0]; abcd.ver = edge2locver[i][1]; tssdissolve1(abcd); } for (i = 0; i < 6; i++) { bace.loc = edge2locver[i][0]; bace.ver = edge2locver[i][1]; tssdissolve1(bace); } abcd.loc = abcd.ver = 0; bace.loc = bace.ver = 0; tssbond1(abcd, abseg); // 1 enext(abcd, worktet); tssbond1(worktet, bcseg); // 2 enext2(abcd, worktet); tssbond1(worktet, caseg); // 3 fnext(abcd, worktet); enext2self(worktet); tssbond1(worktet, adseg); // 4 enextfnext(abcd, worktet); enext2self(worktet); tssbond1(worktet, bdseg); // 5 enext2fnext(abcd, worktet); enext2self(worktet); tssbond1(worktet, cdseg); // 6 tssbond1(bace, abseg); enext2(bace, worktet); tssbond1(worktet, bcseg); enext(bace, worktet); tssbond1(worktet, caseg); fnext(bace, worktet); enextself(worktet); tssbond1(worktet, aeseg); // 7 enext2fnext(bace, worktet); enextself(worktet); tssbond1(worktet, beseg); // 8 enextfnext(bace, worktet); enextself(worktet); tssbond1(worktet, ceseg); // 9 } abcd.loc = 0; bace.loc = 0; if (b->verbose > 3) { printf(" Updating abcd "); printtet(&abcd); printf(" Updating bace "); printtet(&bace); printf(" Deleting edca "); // printtet(&edca); } // Update point-to-tet map. setpoint2tet(pa, encode(abcd)); setpoint2tet(pb, encode(abcd)); setpoint2tet(pc, encode(abcd)); setpoint2tet(pd, encode(abcd)); setpoint2tet(pe, encode(bace)); if (flipqueue != (queue *) NULL) { fnext(abcd, abdcasing); enqueueflipface(abdcasing, flipqueue); fnext(bace, baecasing); enqueueflipface(baecasing, flipqueue); enextfnext(abcd, bcdcasing); enqueueflipface(bcdcasing, flipqueue); enextfnext(bace, cbecasing); enqueueflipface(cbecasing, flipqueue); enext2fnext(abcd, cadcasing); enqueueflipface(cadcasing, flipqueue); enext2fnext(bace, acecasing); enqueueflipface(acecasing, flipqueue); } // Save a live handle in 'recenttet'. recenttet = abcd; // Set the return handle be abcd. *flipface = abcd; } /////////////////////////////////////////////////////////////////////////////// // // // flip22() Perform a 2-to-2 (or 4-to-4) flip. // // // // On input, 'flipface' represents the face will be flipped. Let it is abe, // // ab is the flipable edge, the two tetrahedra sharing abe are abce and bade,// // hence a, b, c and d are coplanar. If abc, bad are interior faces, the two // // tetrahedra opposite to e are bacf and abdf. ab is not a subsegment. // // // // A 2-to-2 flip is to change two tetrahedra abce and bade into another two // // tetrahedra dcae and cdbe. If bacf and abdf exist, they're changed to cdaf // // and dcbf, thus a 4-to-4 flip. As a result, two or four tetrahedra have // // rotated counterclockwise (using right-hand rule with thumb points to e): // // abce->dcae, bade->cdbe, and bacf->cdaf, abdf->dcbf. // // // // If abc and bad are subfaces, a 2-to-2 flip is performed simultaneously by // // calling routine flip22sub(), hence abc->dca, bad->cdb. The edge rings of // // the flipped subfaces dca and cdb have the same orientation as abc and bad.// // Hence, they have the same orientation as other subfaces of the facet with // // respect to the lift point of this facet. // // // // On completion, 'flipface' holds edge dc of tetrahedron dcae. 'flipqueue' // // contains all possibly non-Delaunay faces if it is not NULL. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::flip22(triface* flipface, queue* flipqueue) { triface abce, bade; triface oldbce, oldcae, oldade, olddbe; triface bcecasing, caecasing, adecasing, dbecasing; face bcesh, caesh, adesh, dbesh; triface bacf, abdf; triface oldacf, oldcbf, oldbdf, olddaf; triface acfcasing, cbfcasing, bdfcasing, dafcasing; triface worktet; face acfsh, cbfsh, bdfsh, dafsh; face abc, bad; face adseg, dbseg, bcseg, caseg; // Coplanar segs. face aeseg, deseg, beseg, ceseg; // Above segs. face afseg, dfseg, bfseg, cfseg; // Below segs. point pa, pb, pc, pd, pe, pf; int mirrorflag, i; adjustedgering(*flipface, CCW); // 'flipface' is bae. fnext(*flipface, abce); esymself(abce); adjustedgering(*flipface, CW); // 'flipface' is abe. fnext(*flipface, bade); #ifdef SELF_CHECK assert(bade.tet != dummytet); #endif esymself(bade); pa = org(abce); pb = dest(abce); pc = apex(abce); pd = apex(bade); pe = oppo(bade); #ifdef SELF_CHECK assert(oppo(abce) == pe); #endif sym(abce, bacf); mirrorflag = bacf.tet != dummytet; if (mirrorflag) { // findedge(&bacf, pb, pa); bacf.ver = 0; for (i = 0; (i < 3) && (org(bacf) != pb); i++) { enextself(bacf); } sym(bade, abdf); #ifdef SELF_CHECK assert(abdf.tet != dummytet); #endif // findedge(&abdf, pa, pb); abdf.ver = 0; for (i = 0; (i < 3) && (org(abdf) != pa); i++) { enextself(abdf); } pf = oppo(bacf); #ifdef SELF_CHECK assert(oppo(abdf) == pf); #endif } if (b->verbose > 1) { printf(" Flip edge (%d, %d) to (%d, %d) %s.\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd), mirrorflag ? "T44" : "T22"); } mirrorflag ? flip44s++ : flip22s++; // Save the old configuration at the convex hull. enextfnext(abce, oldbce); enext2fnext(abce, oldcae); enextfnext(bade, oldade); enext2fnext(bade, olddbe); sym(oldbce, bcecasing); sym(oldcae, caecasing); sym(oldade, adecasing); sym(olddbe, dbecasing); if (checksubfaces) { tspivot(oldbce, bcesh); tspivot(oldcae, caesh); tspivot(oldade, adesh); tspivot(olddbe, dbesh); tspivot(abce, abc); tspivot(bade, bad); } if (checksubsegs) { // Coplanar segs: a->d->b->c. enext(bade, worktet); tsspivot1(worktet, adseg); enext2(bade, worktet); tsspivot1(worktet, dbseg); enext(abce, worktet); tsspivot1(worktet, bcseg); enext2(abce, worktet); tsspivot1(worktet, caseg); // Above segs: a->e, d->e, b->e, c->e. fnext(bade, worktet); enextself(worktet); tsspivot1(worktet, aeseg); enextfnext(bade, worktet); enextself(worktet); tsspivot1(worktet, deseg); enext2fnext(bade, worktet); enextself(worktet); tsspivot1(worktet, beseg); enextfnext(abce, worktet); enextself(worktet); tsspivot1(worktet, ceseg); } if (mirrorflag) { enextfnext(bacf, oldacf); enext2fnext(bacf, oldcbf); enextfnext(abdf, oldbdf); enext2fnext(abdf, olddaf); sym(oldacf, acfcasing); sym(oldcbf, cbfcasing); sym(oldbdf, bdfcasing); sym(olddaf, dafcasing); if (checksubfaces) { tspivot(oldacf, acfsh); tspivot(oldcbf, cbfsh); tspivot(oldbdf, bdfsh); tspivot(olddaf, dafsh); } if (checksubsegs) { // Below segs: a->f, d->f, b->f, c->f. fnext(abdf, worktet); enext2self(worktet); tsspivot1(worktet, afseg); enext2fnext(abdf, worktet); enext2self(worktet); tsspivot1(worktet, dfseg); enextfnext(abdf, worktet); enext2self(worktet); tsspivot1(worktet, bfseg); enextfnext(bacf, worktet); enextself(worktet); tsspivot1(worktet, cfseg); } } // Rotate abce, bade one-quarter turn counterclockwise. bond(oldbce, caecasing); bond(oldcae, adecasing); bond(oldade, dbecasing); bond(olddbe, bcecasing); if (checksubfaces) { // Check for subfaces and rebond them to the rotated tets. if (caesh.sh == dummysh) { tsdissolve(oldbce); } else { tsbond(oldbce, caesh); } if (adesh.sh == dummysh) { tsdissolve(oldcae); } else { tsbond(oldcae, adesh); } if (dbesh.sh == dummysh) { tsdissolve(oldade); } else { tsbond(oldade, dbesh); } if (bcesh.sh == dummysh) { tsdissolve(olddbe); } else { tsbond(olddbe, bcesh); } } if (checksubsegs) { // 5 edges in abce are changed. enext(abce, worktet); // fit b->c into c->a. if (caseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, caseg); } enext2(abce, worktet); // fit c->a into a->d. if (adseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, adseg); } fnext(abce, worktet); // fit b->e into c->e. enextself(worktet); if (ceseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, ceseg); } enextfnext(abce, worktet); // fit c->e into a->e. enextself(worktet); if (aeseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, aeseg); } enext2fnext(abce, worktet); // fit a->e into d->e. enextself(worktet); if (deseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, deseg); } // 5 edges in bade are changed. enext(bade, worktet); // fit a->d into d->b. if (dbseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, dbseg); } enext2(bade, worktet); // fit d->b into b->c. if (bcseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, bcseg); } fnext(bade, worktet); // fit a->e into d->e. enextself(worktet); if (deseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, deseg); } enextfnext(bade, worktet); // fit d->e into b->e. enextself(worktet); if (beseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, beseg); } enext2fnext(bade, worktet); // fit b->e into c->e. enextself(worktet); if (ceseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, ceseg); } } if (mirrorflag) { // Rotate bacf, abdf one-quarter turn counterclockwise. bond(oldcbf, acfcasing); bond(oldacf, dafcasing); bond(olddaf, bdfcasing); bond(oldbdf, cbfcasing); if (checksubfaces) { // Check for subfaces and rebond them to the rotated tets. if (acfsh.sh == dummysh) { tsdissolve(oldcbf); } else { tsbond(oldcbf, acfsh); } if (dafsh.sh == dummysh) { tsdissolve(oldacf); } else { tsbond(oldacf, dafsh); } if (bdfsh.sh == dummysh) { tsdissolve(olddaf); } else { tsbond(olddaf, bdfsh); } if (cbfsh.sh == dummysh) { tsdissolve(oldbdf); } else { tsbond(oldbdf, cbfsh); } } if (checksubsegs) { // 5 edges in bacf are changed. enext2(bacf, worktet); // fit b->c into c->a. if (caseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, caseg); } enext(bacf, worktet); // fit c->a into a->d. if (adseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, adseg); } fnext(bacf, worktet); // fit b->f into c->f. enext2self(worktet); if (cfseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, cfseg); } enext2fnext(bacf, worktet); // fit c->f into a->f. enext2self(worktet); if (afseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, afseg); } enextfnext(bacf, worktet); // fit a->f into d->f. enext2self(worktet); if (dfseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, dfseg); } // 5 edges in abdf are changed. enext2(abdf, worktet); // fit a->d into d->b. if (dbseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, dbseg); } enext(abdf, worktet); // fit d->b into b->c. if (bcseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, bcseg); } fnext(abdf, worktet); // fit a->f into d->f. enext2self(worktet); if (dfseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, dfseg); } enext2fnext(abdf, worktet); // fit d->f into b->f. enext2self(worktet); if (bfseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, bfseg); } enextfnext(abdf, worktet); // fit b->f into c->f. enext2self(worktet); if (cfseg.sh == dummysh) { tssdissolve1(worktet); } else { tssbond1(worktet, cfseg); } } } // New vertex assignments for the rotated tetrahedra. setorg(abce, pd); // Update abce to dcae setdest(abce, pc); setapex(abce, pa); setorg(bade, pc); // Update bade to cdbe setdest(bade, pd); setapex(bade, pb); if (mirrorflag) { setorg(bacf, pc); // Update bacf to cdaf setdest(bacf, pd); setapex(bacf, pa); setorg(abdf, pd); // Update abdf to dcbf setdest(abdf, pc); setapex(abdf, pb); } // Update point-to-tet map. setpoint2tet(pa, encode(abce)); setpoint2tet(pb, encode(bade)); setpoint2tet(pc, encode(abce)); setpoint2tet(pd, encode(bade)); setpoint2tet(pe, encode(abce)); if (mirrorflag) { setpoint2tet(pf, encode(bacf)); } // Are there subfaces need to be flipped? if (checksubfaces && abc.sh != dummysh) { #ifdef SELF_CHECK assert(bad.sh != dummysh); #endif // Adjust the edge be ab, so the rotation of subfaces is according with // the rotation of tetrahedra. findedge(&abc, pa, pb); // Flip an edge of two subfaces, ignore non-Delaunay edges. flip22sub(&abc, NULL); } if (b->verbose > 3) { printf(" Updating abce "); printtet(&abce); printf(" Updating bade "); printtet(&bade); if (mirrorflag) { printf(" Updating bacf "); printtet(&bacf); printf(" Updating abdf "); printtet(&abdf); } } if (flipqueue != (queue *) NULL) { enextfnext(abce, bcecasing); enqueueflipface(bcecasing, flipqueue); enext2fnext(abce, caecasing); enqueueflipface(caecasing, flipqueue); enextfnext(bade, adecasing); enqueueflipface(adecasing, flipqueue); enext2fnext(bade, dbecasing); enqueueflipface(dbecasing, flipqueue); if (mirrorflag) { enextfnext(bacf, acfcasing); enqueueflipface(acfcasing, flipqueue); enext2fnext(bacf, cbfcasing); enqueueflipface(cbfcasing, flipqueue); enextfnext(abdf, bdfcasing); enqueueflipface(bdfcasing, flipqueue); enext2fnext(abdf, dafcasing); enqueueflipface(dafcasing, flipqueue); } // The two new faces dcae (abce), cdbe (bade) may still not be locally // Delaunay, and may need be flipped (flip23). On the other hand, in // conforming Delaunay algorithm, two new subfaces dca (abc), and cdb // (bad) may be non-conforming Delaunay, they need be queued if they // are locally Delaunay but non-conforming Delaunay. enqueueflipface(abce, flipqueue); enqueueflipface(bade, flipqueue); } // Save a live handle in 'recenttet'. recenttet = abce; } /////////////////////////////////////////////////////////////////////////////// // // // flip22sub() Perform a 2-to-2 flip on a subface edge. // // // // The flip edge is given by subface 'flipedge'. Let it is abc, where ab is // // the flipping edge. The other subface is bad, where a, b, c, d form a // // convex quadrilateral. ab is not a subsegment. // // // // A 2-to-2 subface flip is to change two subfaces abc and bad to another // // two subfaces dca and cdb. Hence, edge ab has been removed and dc becomes // // an edge. If a point e is above abc, this flip is equal to rotate abc and // // bad counterclockwise using right-hand rule with thumb points to e. It is // // important to know that the edge rings of the flipped subfaces dca and cdb // // are keeping the same orientation as their original subfaces. So they have // // the same orientation with respect to the lift point of this facet. // // // // During rotating, the face rings of the four edges bc, ca, ad, and de need // // be re-connected. If the edge is not a subsegment, then its face ring has // // only two faces, a sbond() will bond them together. If it is a subsegment, // // one should use sbond1() twice to bond two different handles to the rotat- // // ing subface, one is predecssor (-casin), another is successor (-casout). // // // // If 'flipqueue' is not NULL, it returns four edges bc, ca, ad, de, which // // may be non-Delaunay. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::flip22sub(face* flipedge, queue* flipqueue) { face abc, bad; face oldbc, oldca, oldad, olddb; face bccasin, bccasout, cacasin, cacasout; face adcasin, adcasout, dbcasin, dbcasout; face bc, ca, ad, db; face spinsh; point pa, pb, pc, pd; abc = *flipedge; spivot(abc, bad); if (sorg(bad) != sdest(abc)) { sesymself(bad); } pa = sorg(abc); pb = sdest(abc); pc = sapex(abc); pd = sapex(bad); if (b->verbose > 1) { printf(" Flip subedge (%d, %d) to (%d, %d).\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd)); } // Unmark the flipped subfaces (used in mesh refinement). 2009-08-17. sunmarktest(abc); sunmarktest(bad); // Save the old configuration outside the quadrilateral. senext(abc, oldbc); senext2(abc, oldca); senext(bad, oldad); senext2(bad, olddb); // Get the outside connection. Becareful if there is a subsegment on the // quadrilateral, two casings (casin and casout) are needed to save for // keeping the face link. spivot(oldbc, bccasout); sspivot(oldbc, bc); if (bc.sh != dummysh) { // 'bc' is a subsegment. if (bccasout.sh != dummysh) { if (oldbc.sh != bccasout.sh) { // 'oldbc' is not self-bonded. spinsh = bccasout; do { bccasin = spinsh; spivotself(spinsh); } while (spinsh.sh != oldbc.sh); } else { bccasout.sh = dummysh; } } ssdissolve(oldbc); } spivot(oldca, cacasout); sspivot(oldca, ca); if (ca.sh != dummysh) { // 'ca' is a subsegment. if (cacasout.sh != dummysh) { if (oldca.sh != cacasout.sh) { // 'oldca' is not self-bonded. spinsh = cacasout; do { cacasin = spinsh; spivotself(spinsh); } while (spinsh.sh != oldca.sh); } else { cacasout.sh = dummysh; } } ssdissolve(oldca); } spivot(oldad, adcasout); sspivot(oldad, ad); if (ad.sh != dummysh) { // 'ad' is a subsegment. if (adcasout.sh != dummysh) { if (oldad.sh != adcasout.sh) { // 'adcasout' is not self-bonded. spinsh = adcasout; do { adcasin = spinsh; spivotself(spinsh); } while (spinsh.sh != oldad.sh); } else { adcasout.sh = dummysh; } } ssdissolve(oldad); } spivot(olddb, dbcasout); sspivot(olddb, db); if (db.sh != dummysh) { // 'db' is a subsegment. if (dbcasout.sh != dummysh) { if (olddb.sh != dbcasout.sh) { // 'dbcasout' is not self-bonded. spinsh = dbcasout; do { dbcasin = spinsh; spivotself(spinsh); } while (spinsh.sh != olddb.sh); } else { dbcasout.sh = dummysh; } } ssdissolve(olddb); } // Rotate abc and bad one-quarter turn counterclockwise. if (ca.sh != dummysh) { if (cacasout.sh != dummysh) { sbond1(cacasin, oldbc); sbond1(oldbc, cacasout); } else { // Bond 'oldbc' to itself. sdissolve(oldbc); // sbond(oldbc, oldbc); // Make sure that dummysh always correctly bonded. dummysh[0] = sencode(oldbc); } ssbond(oldbc, ca); } else { sbond(oldbc, cacasout); } if (ad.sh != dummysh) { if (adcasout.sh != dummysh) { sbond1(adcasin, oldca); sbond1(oldca, adcasout); } else { // Bond 'oldca' to itself. sdissolve(oldca); // sbond(oldca, oldca); // Make sure that dummysh always correctly bonded. dummysh[0] = sencode(oldca); } ssbond(oldca, ad); } else { sbond(oldca, adcasout); } if (db.sh != dummysh) { if (dbcasout.sh != dummysh) { sbond1(dbcasin, oldad); sbond1(oldad, dbcasout); } else { // Bond 'oldad' to itself. sdissolve(oldad); // sbond(oldad, oldad); // Make sure that dummysh always correctly bonded. dummysh[0] = sencode(oldad); } ssbond(oldad, db); } else { sbond(oldad, dbcasout); } if (bc.sh != dummysh) { if (bccasout.sh != dummysh) { sbond1(bccasin, olddb); sbond1(olddb, bccasout); } else { // Bond 'olddb' to itself. sdissolve(olddb); // sbond(olddb, olddb); // Make sure that dummysh always correctly bonded. dummysh[0] = sencode(olddb); } ssbond(olddb, bc); } else { sbond(olddb, bccasout); } // New vertex assignments for the rotated subfaces. setsorg(abc, pd); // Update abc to dca. setsdest(abc, pc); setsapex(abc, pa); setsorg(bad, pc); // Update bad to cdb. setsdest(bad, pd); setsapex(bad, pb); // Update the point-to-subface map. // Comemnt: After the flip, abc becomes dca, bad becodes cdb. setpoint2sh(pa, sencode(abc)); // dca setpoint2sh(pb, sencode(bad)); // cdb setpoint2sh(pc, sencode(bad)); setpoint2sh(pd, sencode(bad)); if (flipqueue != (queue *) NULL) { enqueueflipedge(bccasout, flipqueue); enqueueflipedge(cacasout, flipqueue); enqueueflipedge(adcasout, flipqueue); enqueueflipedge(dbcasout, flipqueue); } } /////////////////////////////////////////////////////////////////////////////// // // // lawson3d() Perform 3D Lawson flips on non-Delaunay faces/edges. // // // /////////////////////////////////////////////////////////////////////////////// long tetgenmesh::lawson3d(queue* flipqueue) { badface *qface; triface flipface, symface, flipedge; triface neighface, symneighface; face checksh, checkseg; face neighsh, symneighsh; point pa, pb, pc, pd, pe; point end1, end2; REAL sign, ori1, ori2, ori3; REAL ori4, len, vol; long flipcount; int copflag; int i; if (b->verbose > 1) { printf(" Lawson flip: %ld faces.\n", flipqueue->len()); } flipcount = flip23s + flip32s + flip22s + flip44s; // Loop until the queue is empty. while (!flipqueue->empty()) { qface = (badface *) flipqueue->pop(); flipface = qface->tt; if (isdead(&flipface)) continue; if (flipface.tet == dummytet) continue; // Do not flip it if it is a subface. tspivot(flipface, checksh); if (checksh.sh != dummysh) continue; sym(flipface, symface); // Only do check when the adjacent tet exists and it's not a "fake" tet. if ((symface.tet != dummytet) && (oppo(symface) == qface->foppo)) { flipface.ver = 0; // CCW. pa = org(flipface); pb = dest(flipface); pc = apex(flipface); pd = oppo(flipface); pe = oppo(symface); sign = insphere_s(pb, pa, pc, pd, pe); assert(sign != 0.0); if (sign > 0.0) { // flipface is not locally Delaunay. Try to flip it. ori1 = orient3d(pa, pb, pd, pe); ori2 = orient3d(pb, pc, pd, pe); ori3 = orient3d(pc, pa, pd, pe); flipedge = flipface; // Initialize flipedge. copflag = 0; // Find a suitable flip. if (ori1 > 0) { if (ori2 > 0) { if (ori3 > 0) { // (+++) // A 2-to-3 flip is found. // Do not flip it if it is a subface. // tspivot(flipface, checksh); // if (checksh.sh == dummysh) { // Do not flip it if it will create a tet spanning two // "coplanar" subfaces. We treat this case as either // a 2-to-2 or a 4-to-4 flip. for (i = 0; i < 3; i++) { tsspivot(&flipface, &checkseg); if (checkseg.sh == dummysh) { fnext(flipface, neighface); tspivot(neighface, neighsh); if (neighsh.sh != dummysh) { // Check if there exist another subface. symedge(flipface, symface); fnext(symface, symneighface); tspivot(symneighface, symneighsh); if (symneighsh.sh != dummysh) { // Do not flip this face. Try to do a 2-to-2 or a // 4-to-4 flip instead. flipedge = flipface; copflag = 1; break; } } } enextself(flipface); } if (i == 3) { // Do not flip if it will create a nearly degenerate tet // at a segment. Once we created such a tet, it may // prevent you to split the segment later. An example // is in dump-.lua for (i = 0; i < 3; i++) { tsspivot(&flipface, &checkseg); if (checkseg.sh != dummysh) { end1 = (point) checkseg.sh[3]; end2 = (point) checkseg.sh[4]; ori4 = orient3d(end1, end2, pd, pe); len = distance(end1, end2); vol = len * len * len; // Is it nearly degnerate? if ((fabs(ori4) / vol) < b->epsilon) { flipedge = flipface; copflag = 0; break; } } enextself(flipface); } if (i == 3) { flip23(&flipface, flipqueue); continue; } } // } } else { if (ori3 < 0) { // (++-) // Try to flip edge [c, a]. flipedge.ver = 4; copflag = 0; } else { // (++0) // A 2-to-2 or 4-to-4 flip at edge [c, a]. flipedge.ver = 4; copflag = 1; } } } else { if (ori2 < 0) { if (ori3 > 0) { // (+-+) // Try to flip edge [b, c]. flipedge.ver = 2; copflag = 0; } else { if (ori3 < 0) { // (+--) // Not possible when pe is inside the circumsphere of // the tet [pa.pb, pc, pd]. assert(0); } else { // (+-0) assert(0); // The same reason as above. } } } else { // ori2 == 0 if (ori3 > 0) { // (+0+) // A 2-to-2 or 4-to-4 flip at edge [b, c]. flipedge.ver = 2; copflag = 1; } else { if (ori3 < 0) { // (+0-) // Not possible when pe is inside the circumsphere of // the tet [pa.pb, pc, pd]. assert(0); } else { // (+00) assert(0); // The same reason as above. } } } } } else { if (ori1 < 0) { if (ori2 > 0) { if (ori3 > 0) { // (-++) // Try to flip edge [a, b]. flipedge.ver = 0; copflag = 0; } else { if (ori3 < 0) { // (-+-) // Not possible when pe is inside the circumsphere of // the tet [pa.pb, pc, pd]. assert(0); } else { // (-+0) assert(0); // The same reason as above. } } } else { if (ori2 < 0) { if (ori3 > 0) { // (--+) // Not possible when pe is inside the circumsphere of // the tet [pa.pb, pc, pd]. assert(0); } else { if (ori3 < 0) { // (---) assert(0); } else { // (--0) assert(0); } } } else { // ori2 == 0 if (ori3 > 0) { // (-0+) assert(0); } else { if (ori3 < 0) { // (-0-) assert(0); } else { // (-00) assert(0); } } } } } else { // ori1 == 0 if (ori2 > 0) { if (ori3 > 0) { // (0++) // A 2-to-2 or 4-to-4 flip at edge [a, b]. flipedge.ver = 0; copflag = 1; } else { if (ori3 < 0) { // (0+-) assert(0); } else { // (0+0) assert(0); } } } else { if (ori2 < 0) { if (ori3 > 0) { // (0-+) assert(0); } else { if (ori3 < 0) { // (0--) assert(0); } else { // (0-0) assert(0); } } } else { if (ori3 > 0) { // (00+) assert(0); } else { if (ori3 < 0) { // (00-) assert(0); } else { // (000) assert(0); } } } } } } // An edge (flipedge) is going to be flipped. // Do not flip it it is a subsegment. tsspivot(&flipedge, &checkseg); if (checkseg.sh == dummysh) { symedge(flipedge, symface); if (copflag == 0) { // Check if a 3-to-2 flip is possible. tfnext(flipedge, neighface); if (neighface.tet != dummytet) { // Check if neighface is a subface. tspivot(neighface, neighsh); if (neighsh.sh == dummysh) { tfnext(symface, symneighface); if (neighface.tet == symneighface.tet) { // symneighface should not be a subface. Check it. tspivot(symneighface, symneighsh); assert(symneighsh.sh == dummysh); // Found a 3-to-2 flip. flip32(&flipedge, flipqueue); } } else { // neighsh is a subface. Check a potential 4-to-4 flip. tfnext(symface, symneighface); tspivot(symneighface, symneighsh); if (symneighsh.sh != dummysh) { if (oppo(neighface) == oppo(symneighface)) { // Found a 4-to-4 flip. flip22(&flipedge, flipqueue); } } } } else { // neightface is a hull face. Since flipedge is not a segment // and this edge is locally non-convex. tfnext(symface, symneighface); // symneighface should also be a hull face. if (symneighface.tet == dummytet) { // Force a 2-to-2 flip (recovery of Delaunay). flip22(&flipedge, flipqueue); } } } else { // Check if a 2-to-2 or 4-to-4 flip is possible. tfnext(flipedge, neighface); tfnext(symface, symneighface); if (neighface.tet != dummytet) { if (symneighface.tet != dummytet) { if (oppo(neighface) == oppo(symneighface)) { // Found a 4-to-4 flip. flip22(&flipedge, flipqueue); } } } else { if (symneighface.tet == dummytet) { // Found a 2-to-2 flip. flip22(&flipedge, flipqueue); } } } } } // if (sign > 0) } } // while (!flipqueue->empty()) flipcount = flip23s + flip32s + flip22s + flip44s - flipcount; if (b->verbose > 1) { printf(" %ld flips.\n", flipcount); } return flipcount; } /////////////////////////////////////////////////////////////////////////////// // // // lawson() Perform lawson flips on non-Delaunay edges. // // // // Assumpation: Current triangulation T contains non-Delaunay edges (after // // inserting a point or performing a flip). Non-Delaunay edges are queued in // // 'facequeue'. Returns the total number of flips done during this call. // // // /////////////////////////////////////////////////////////////////////////////// long tetgenmesh::lawson(queue* flipqueue) { badface *qedge; face flipedge, symedge; face checkseg; point pa, pb, pc, pd; REAL vab[3], vac[3], vad[3]; REAL dot1, dot2, lac, lad; REAL sign, ori; int edgeflips, maxflips; int i; if (b->verbose > 1) { printf(" Lawson flip: %ld edges.\n", flipqueue->len()); } if (b->diagnose) { maxflips = (int) ((flipqueue->len() + 1l) * 3l); maxflips *= maxflips; } else { maxflips = -1; } edgeflips = 0; while (!flipqueue->empty() && maxflips != 0) { qedge = (badface *) flipqueue->pop(); flipedge = qedge->ss; if (flipedge.sh == dummysh) continue; if ((sorg(flipedge) != qedge->forg) || (sdest(flipedge) != qedge->fdest)) continue; sspivot(flipedge, checkseg); if (checkseg.sh != dummysh) continue; // Can't flip a subsegment. spivot(flipedge, symedge); if (symedge.sh == dummysh) continue; // Can't flip a hull edge. pa = sorg(flipedge); pb = sdest(flipedge); pc = sapex(flipedge); pd = sapex(symedge); // Choose the triangle abc or abd as the base depending on the angle1 // (Vac, Vab) and angle2 (Vad, Vab). for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i]; for (i = 0; i < 3; i++) vac[i] = pc[i] - pa[i]; for (i = 0; i < 3; i++) vad[i] = pd[i] - pa[i]; dot1 = dot(vac, vab); dot2 = dot(vad, vab); dot1 *= dot1; dot2 *= dot2; lac = dot(vac, vac); lad = dot(vad, vad); if (lad * dot1 <= lac * dot2) { // angle1 is closer to 90 than angle2, choose abc (flipedge). abovepoint = facetabovepointarray[shellmark(flipedge)]; if (abovepoint == (point) NULL) { getfacetabovepoint(&flipedge); } sign = insphere(pa, pb, pc, abovepoint, pd); ori = orient3d(pa, pb, pc, abovepoint); } else { // angle2 is closer to 90 than angle1, choose abd (symedge). abovepoint = facetabovepointarray[shellmark(symedge)]; if (abovepoint == (point) NULL) { getfacetabovepoint(&symedge); } sign = insphere(pa, pb, pd, abovepoint, pc); ori = orient3d(pa, pb, pd, abovepoint); } // Correct the sign. sign = ori > 0.0 ? sign : -sign; if (sign > 0.0) { // Flip the non-Delaunay edge. flip22sub(&flipedge, flipqueue); edgeflips++; if (maxflips > 0) maxflips--; } } if (!maxflips && !b->quiet) { printf("Warning: Maximal number of flips reached !\n"); } if (b->verbose > 1) { printf(" Total %d flips.\n", edgeflips); } return edgeflips; } /////////////////////////////////////////////////////////////////////////////// // // // removetetbypeeloff() Remove a boundary tet by peeling it off. // // // // 'striptet' (abcd) is on boundary and can be removed by stripping it off. // // Let abc and bad are the external boundary faces. // // // // To strip 'abcd' from the mesh is to detach its two interal faces (dca and // // cdb) from their adjoining tets together with a 2-to-2 flip to transform // // two subfaces (abc and bad) into another two (dca and cdb). // // // // 'adjtetlist[2]' returns the two new boundary faces (in tet) dca and cdb. // // // // In mesh optimization. It is possible that ab is a segment and abcd is a // // sliver on the hull. Strip abcd will also delete the segment ab. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removetetbypeeloff(triface *striptet, triface *adjtetlist) { triface abcd, badc; triface dcacasing, cdbcasing; face abc, bad; face abseg; REAL ang; abcd = *striptet; adjustedgering(abcd, CCW); // Get the casing tets at the internal sides. enextfnext(abcd, cdbcasing); enext2fnext(abcd, dcacasing); symself(cdbcasing); symself(dcacasing); // Do the neighboring tets exist? During optimization. It is possible // that the neighboring tets are already dead. if ((cdbcasing.tet == dummytet) || (dcacasing.tet == dummytet)) { // Do not strip this tet. return false; } // Are there subfaces? if (checksubfaces) { // Get the external subfaces abc, bad. fnext(abcd, badc); esymself(badc); tspivot(abcd, abc); tspivot(badc, bad); if (abc.sh != dummysh) { assert(bad.sh != dummysh); findedge(&abc, org(abcd), dest(abcd)); findedge(&bad, org(badc), dest(badc)); // Is ab a segment? sspivot(abc, abseg); if (abseg.sh != dummysh) { // Does a segment allow to be removed? if ((b->optlevel > 3) && (b->nobisect == 0)) { // Only remove this segment if the dihedal angle at ab is between // [b->maxdihedral-9, 180] (deg). This avoids mistakely fliping // ab when it has actually no big dihedral angle while cd has. ang = facedihedral(org(abcd), dest(abcd), apex(abcd), oppo(abcd)); ang = ang * 180.0 / PI; if ((ang + 9.0) > b->maxdihedral) { if (b->verbose > 1) { printf(" Remove a segment during peeling.\n"); } face prevseg, nextseg; // It is only shared by abc and bad (abcd is a tet). ssdissolve(abc); ssdissolve(bad); abseg.shver = 0; senext(abseg, nextseg); spivotself(nextseg); if (nextseg.sh != dummysh) { ssdissolve(nextseg); } senext2(abseg, prevseg); spivotself(prevseg); if (prevseg.sh != dummysh) { ssdissolve(prevseg); } shellfacedealloc(subsegs, abseg.sh); optcount[1]++; } else { return false; } } else { return false; } } // Do a 2-to-2 flip on abc and bad, transform abc->dca, bad->cdb. flip22sub(&abc, NULL); // The two internal faces become boundary faces. tsbond(cdbcasing, bad); tsbond(dcacasing, abc); } } // Detach abcd from the two internal faces. dissolve(cdbcasing); dissolve(dcacasing); // Delete abcd. tetrahedrondealloc(abcd.tet); adjtetlist[0] = cdbcasing; adjtetlist[1] = dcacasing; return true; } /////////////////////////////////////////////////////////////////////////////// // // // removeedgebyflip22() Remove an edge by a 2-to-2 (or 4-to-4) flip. // // // // 'abtetlist' contains n tets (n is 2 or 4) sharing edge ab, abtetlist[0] // // and abtetlist[1] are tets abec and abde, respectively (NOTE, both are in // // CW edge ring), where a, b, c, and d are coplanar. If n = 4, abtetlist[2] // // and abtetlist[3] are tets abfd and abcf, respectively. This routine uses // // flip22() to replace edge ab with cd, the surrounding tets are rotated. // // // // If 'key' != NULL. The old tets are replaced by the new tets only if the // // local mesh quality is improved. Current 'key' = cos(\theta), where \theta // // is the maximum dihedral angle in the old tets. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removeedgebyflip22(REAL *key, int n, triface *abtetlist, queue *flipque) { point pa, pb, pc, pd, pe, pf; REAL cosmaxd, d1, d2, d3; bool doflip; doflip = true; adjustedgering(abtetlist[0], CW); pa = org(abtetlist[0]); pb = dest(abtetlist[0]); pe = apex(abtetlist[0]); pc = oppo(abtetlist[0]); pd = apex(abtetlist[1]); if (n == 4) { pf = apex(abtetlist[2]); } if (key && (*key > -1.0)) { tetalldihedral(pc, pd, pe, pa, NULL, &d1, NULL); tetalldihedral(pd, pc, pe, pb, NULL, &d2, NULL); cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. if (n == 4) { tetalldihedral(pd, pc, pf, pa, NULL, &d1, NULL); tetalldihedral(pc, pd, pf, pb, NULL, &d2, NULL); d3 = d1 < d2 ? d1 : d2; // Choose the bigger angle. cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle. } doflip = (*key < cosmaxd); // Can local quality be improved? } if (doflip) { flip22(&abtetlist[0], NULL); // Return the improved quality value. if (key) *key = cosmaxd; } return doflip; } /////////////////////////////////////////////////////////////////////////////// // // // removefacebyflip23() Remove a face by a 2-to-3 flip. // // // // 'abctetlist' contains 2 tets sharing abc, which are [0]abcd and [1]bace. // // This routine forms three new tets that abc is not a face anymore. Save // // them in 'newtetlist': [0]edab, [1]edbc, and [2]edca. Note that the new // // tets may not valid if one of them get inverted. return false if so. // // // // If 'key' != NULL. The old tets are replaced by the new tets only if the // // local mesh quality is improved. Current 'key' = cos(\theta), where \theta // // is the maximum dihedral angle in the old tets. // // // // If the face is flipped, 'newtetlist' returns the three new tets. The two // // tets in 'abctetlist' are NOT deleted. The caller has the right to either // // delete them or reverse the operation. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removefacebyflip23(REAL *key, triface *abctetlist, triface *newtetlist, queue *flipque) { triface edab, edbc, edca; // new configuration. triface newfront, oldfront, adjfront; face checksh; point pa, pb, pc, pd, pe; REAL ori, cosmaxd, d1, d2, d3; REAL attrib, volume; bool doflip; int i; adjustedgering(abctetlist[0], CCW); pa = org(abctetlist[0]); pb = dest(abctetlist[0]); pc = apex(abctetlist[0]); pd = oppo(abctetlist[0]); pe = oppo(abctetlist[1]); // Check if the flip creates valid new tets. ori = orient3d(pe, pd, pa, pb); if (ori < 0.0) { ori = orient3d(pe, pd, pb, pc); if (ori < 0.0) { ori = orient3d(pe, pd, pc, pa); } } doflip = (ori < 0.0); // Can abc be flipped away? if (doflip && (key != (REAL *) NULL)) { if (*key > -1.0) { // Test if the new tets reduce the maximal dihedral angle. tetalldihedral(pe, pd, pa, pb, NULL, &d1, NULL); tetalldihedral(pe, pd, pb, pc, NULL, &d2, NULL); tetalldihedral(pe, pd, pc, pa, NULL, &d3, NULL); cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. cosmaxd = cosmaxd < d3 ? cosmaxd : d3; // Choose the bigger angle. doflip = (*key < cosmaxd); // Can local quality be improved? } } if (doflip) { // A valid (2-to-3) flip is found. flip23s++; // Create the new tets. maketetrahedron(&edab); setorg(edab, pe); setdest(edab, pd); setapex(edab, pa); setoppo(edab, pb); maketetrahedron(&edbc); setorg(edbc, pe); setdest(edbc, pd); setapex(edbc, pb); setoppo(edbc, pc); maketetrahedron(&edca); setorg(edca, pe); setdest(edca, pd); setapex(edca, pc); setoppo(edca, pa); // Transfer the element attributes. for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(abctetlist[0].tet, i); setelemattribute(edab.tet, i, attrib); setelemattribute(edbc.tet, i, attrib); setelemattribute(edca.tet, i, attrib); } // Transfer the volume constraints. if (b->varvolume && !b->refine) { volume = volumebound(abctetlist[0].tet); setvolumebound(edab.tet, volume); setvolumebound(edbc.tet, volume); setvolumebound(edca.tet, volume); } // Return two new tets. newtetlist[0] = edab; newtetlist[1] = edbc; newtetlist[2] = edca; // Glue the three new tets. for (i = 0; i < 3; i++) { fnext(newtetlist[i], newfront); bond(newfront, newtetlist[(i + 1) % 3]); } // Substitute the three new tets into the old cavity. for (i = 0; i < 3; i++) { fnext(abctetlist[0], oldfront); sym(oldfront, adjfront); // may be outside. enextfnext(newtetlist[i], newfront); bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } if (flipque != (queue *) NULL) { enqueueflipface(newfront, flipque); } enextself(abctetlist[0]); } findedge(&(abctetlist[1]), pb, pa); for (i = 0; i < 3; i++) { fnext(abctetlist[1], oldfront); sym(oldfront, adjfront); // may be outside. enext2fnext(newtetlist[i], newfront); bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } if (flipque != (queue *) NULL) { enqueueflipface(newfront, flipque); } enext2self(abctetlist[1]); } // Do not delete the old tets. // for (i = 0; i < 2; i++) { // tetrahedrondealloc(abctetlist[i].tet); // } // Return the improved quality value. if (key != (REAL *) NULL) *key = cosmaxd; return true; } return false; } /////////////////////////////////////////////////////////////////////////////// // // // removeedgebyflip32() Remove an edge by a 3-to-2 flip. // // // // 'abtetlist' contains 3 tets sharing ab. Imaging that ab is perpendicular // // to the screen, where a lies in front of and b lies behind it. The 3 tets // // of the list are: [0]abce, [1]abdc, and [2]abed, respectively. // // Comment: the edge ab is in CW edge ring of the three faces: abc, abd, and // // abe. (2009-06-29) // // // // This routine forms two new tets that ab is not an edge of them. Save them // // in 'newtetlist', [0]dcea, [1]cdeb. Note that the new tets may not valid // // if one of them get inverted. return false if so. // // // // If 'key' != NULL. The old tets are replaced by the new tets only if the // // local mesh quality is improved. Current 'key' = cos(\theta), where \theta // // is the maximum dihedral angle in the old tets. // // // // If the edge is flipped, 'newtetlist' returns the two new tets. The three // // tets in 'abtetlist' are NOT deleted. The caller has the right to either // // delete them or reverse the operation. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removeedgebyflip32(REAL *key, triface *abtetlist, triface *newtetlist, queue *flipque) { triface dcea, cdeb; // new configuration. triface newfront, oldfront, adjfront; face checksh, checkseg; point pa, pb, pc, pd, pe; REAL ori, cosmaxd, d1, d2; REAL attrib, volume; bool doflip; int i; pa = org(abtetlist[0]); pb = dest(abtetlist[0]); pc = apex(abtetlist[0]); pd = apex(abtetlist[1]); pe = apex(abtetlist[2]); ori = orient3d(pd, pc, pe, pa); if (ori < 0.0) { ori = orient3d(pc, pd, pe, pb); } doflip = (ori < 0.0); // Can ab be flipped away? // Does the caller ensure a valid configuration? if (doflip && (key != (REAL *) NULL)) { if (*key > -1.0) { // Test if the new tets reduce the maximal dihedral angle. tetalldihedral(pd, pc, pe, pa, NULL, &d1, NULL); tetalldihedral(pc, pd, pe, pb, NULL, &d2, NULL); cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. doflip = (*key < cosmaxd); // Can local quality be improved? // Return the key *key = cosmaxd; } } // Comment: This edge must not be fixed. It has been checked before. if (doflip && (elemfliplist != NULL)) { // Regist this flip. if (!registerelemflip(T32, pa, pb, dummypoint, pc, pd, pe)) { // Detected a potential flip loop. Don't do it. return false; } } if (doflip) { // Create the new tets. maketetrahedron(&dcea); setorg(dcea, pd); setdest(dcea, pc); setapex(dcea, pe); setoppo(dcea, pa); maketetrahedron(&cdeb); setorg(cdeb, pc); setdest(cdeb, pd); setapex(cdeb, pe); setoppo(cdeb, pb); // Transfer the element attributes. for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(abtetlist[0].tet, i); setelemattribute(dcea.tet, i, attrib); setelemattribute(cdeb.tet, i, attrib); } // Transfer the volume constraints. if (b->varvolume && !b->refine) { volume = volumebound(abtetlist[0].tet); setvolumebound(dcea.tet, volume); setvolumebound(cdeb.tet, volume); } // Return two new tets. newtetlist[0] = dcea; newtetlist[1] = cdeb; // Glue the two new tets. bond(dcea, cdeb); // Substitute the two new tets into the old three-tets cavity. for (i = 0; i < 3; i++) { fnext(dcea, newfront); // face dca, cea, eda. esym(abtetlist[(i + 1) % 3], oldfront); enextfnextself(oldfront); // Get the adjacent tet at the face (may be a dummytet). sym(oldfront, adjfront); bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } if (flipque != (queue *) NULL) { enqueueflipface(newfront, flipque); } enext2self(dcea); } for (i = 0; i < 3; i++) { fnext(cdeb, newfront); // face cdb, deb, ecb. esym(abtetlist[(i + 1) % 3], oldfront); enext2fnextself(oldfront); // Get the adjacent tet at the face (may be a dummytet). sym(oldfront, adjfront); bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } if (flipque != (queue *) NULL) { enqueueflipface(newfront, flipque); } enextself(cdeb); } // Do not delete the old tets. // for (i = 0; i < 3; i++) { // tetrahedrondealloc(abtetlist[i].tet); // } return true; } // if (doflip) return false; } /////////////////////////////////////////////////////////////////////////////// // // // removeedgebytranNM() Remove an edge by transforming n-to-m tets. // // // // This routine attempts to remove a given edge (ab) by transforming the set // // T of tets surrounding ab into another set T' of tets. T and T' have the // // same outer faces and ab is not an edge of T' anymore. Let |T|=n, and |T'| // // =m, it is actually a n-to-m flip for n > 3. The relation between n and m // // depends on the method, ours is found below. // // // // 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular // // to the screen, where a lies in front of and b lies behind it. Let the // // projections of the n apexes onto screen in clockwise order are: p_0, ... // // p_n-1, respectively. The tets in the list are: [0]abp_0p_n-1,[1]abp_1p_0, // // ..., [n-1]abp_n-1p_n-2, respectively. // // // // The principle of the approach is: Recursively reduce the link of ab by // // using flip23 until only three faces remain, hence a flip32 can be applied // // to remove ab. For a given face a.b.p_0, check a flip23 can be applied on // // it, i.e, edge p_1.p_n-1 crosses it. NOTE*** We do the flip even p_1.p_n-1 // // intersects with a.b (they are coplanar). If so, a degenerate tet (a.b.p_1.// // p_n-1) is temporarily created, but it will be eventually removed by the // // final flip32. This relaxation splits a flip44 into flip23 + flip32. *NOTE // // Now suppose a.b.p_0 gets flipped, p_0 is not on the link of ab anymore. // // The link is then reduced (by 1). 2 of the 3 new tets, p_n-1.p_1.p_0.a and // // p_1.p_n-1.p_0.b, will be part of the new configuration. The left new tet,// // a.b.p_1.p_n-1, goes into the new link of ab. A recurrence can be applied. // // // // If 'e1' and 'e2' are not NULLs, they specify an wanted edge to appear in // // the new tet configuration. In such case, only do flip23 if edge e1<->e2 // // can be recovered. It is used in removeedgebycombNM(). // // // // If ab gets removed. 'newtetlist' contains m new tets. By using the above // // approach, the pairs (n, m) can be easily enumerated. For example, (3, 2),// // (4, 4), (5, 6), (6, 8), (7, 10), (8, 12), (9, 14), (10, 16), and so on. // // It is easy to deduce, that m = (n - 2) * 2, when n >= 3. The n tets in // // 'abtetlist' are NOT deleted in this routine. The caller has the right to // // either delete them or reverse this operation. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removeedgebytranNM(REAL *key, int n, triface *abtetlist, triface *newtetlist, point e1, point e2, queue *flipque) { triface tmpabtetlist[21]; // Temporary max 20 tets configuration. triface newfront, oldfront, adjfront; face checksh; point pa, pb, p[21]; REAL ori, cosmaxd, d1, d2; REAL tmpkey; REAL attrib, volume; bool doflip, copflag, success; int i, j, k; // Maximum 20 tets. assert(n < 20); // n <= b->maxflipedgelinksize // Two points a and b are fixed. pa = org(abtetlist[0]); pb = dest(abtetlist[0]); // The points p_0, p_1, ..., p_n-1 are permuted in each new configuration. // These permutations can be easily done in the following loop. // Loop through all the possible new tets configurations. Stop on finding // a valid new tet configuration which also immproves the quality value. for (i = 0; i < n; i++) { // Get other n points for the current configuration. for (j = 0; j < n; j++) { p[j] = apex(abtetlist[(i + j) % n]); } // Is there a wanted edge? if ((e1 != (point) NULL) && (e2 != (point) NULL)) { // Yes. Skip this face if p[1]<->p[n-1] is not the edge. if (!(((p[1] == e1) && (p[n - 1] == e2)) || ((p[1] == e2) && (p[n - 1] == e1)))) continue; } // Test if face a.b.p_0 can be flipped (by flip23), ie, to check if the // edge p_n-1.p_1 crosses face a.b.p_0 properly. // Note. It is possible that face a.b.p_0 has type flip44, ie, a,b,p_1, // and p_n-1 are coplanar. A trick is to split the flip44 into two // steps: frist a flip23, then a flip32. The first step creates a // degenerate tet (vol=0) which will be removed by the second flip. ori = orient3d(pa, pb, p[1], p[n - 1]); copflag = (ori == 0.0); // Are they coplanar? if (ori >= 0.0) { // Accept the coplanar case which supports flip44. ori = orient3d(pb, p[0], p[1], p[n - 1]); if (ori > 0.0) { ori = orient3d(p[0], pa, p[1], p[n - 1]); } } // Is face abc flipable? if (ori > 0.0) { // A valid (2-to-3) flip (or 4-to-4 flip) is found. copflag ? flip44s++ : flip23s++; doflip = true; if (key != (REAL *) NULL) { if (*key > -1.0) { // Test if the new tets reduce the maximal dihedral angle. Only 2 // tets, p_n-1.p_1.p_0.a and p_1.p_n-1.p_0.b, need to be tested // The left one a.b.p_n-1.p_1 goes into the new link of ab. tetalldihedral(p[n - 1], p[1], p[0], pa, NULL, &d1, NULL); tetalldihedral(p[1], p[n - 1], p[0], pb, NULL, &d2, NULL); cosmaxd = d1 < d2 ? d1 : d2; // Choose the bigger angle. doflip = *key < cosmaxd; // Can the local quality be improved? } } if (doflip && (elemfliplist != NULL)) { // Comment: The flipping face must be not fixed. This case has been // tested during collecting the face ring of this edge. // Do not flip this face if it has been registered before. if (!registerelemflip(T23, pa, pb, p[0], p[1], p[n-1], dummypoint)) { doflip = false; // Do not flip this face. } } if (doflip) { tmpkey = key != NULL ? *key : -1.0; // Create the two new tets. maketetrahedron(&(newtetlist[0])); setorg(newtetlist[0], p[n - 1]); setdest(newtetlist[0], p[1]); setapex(newtetlist[0], p[0]); setoppo(newtetlist[0], pa); maketetrahedron(&(newtetlist[1])); setorg(newtetlist[1], p[1]); setdest(newtetlist[1], p[n - 1]); setapex(newtetlist[1], p[0]); setoppo(newtetlist[1], pb); // Create the n - 1 temporary new tets (the new Star(ab)). maketetrahedron(&(tmpabtetlist[0])); setorg(tmpabtetlist[0], pa); setdest(tmpabtetlist[0], pb); setapex(tmpabtetlist[0], p[n - 1]); setoppo(tmpabtetlist[0], p[1]); for (j = 1; j < n - 1; j++) { maketetrahedron(&(tmpabtetlist[j])); setorg(tmpabtetlist[j], pa); setdest(tmpabtetlist[j], pb); setapex(tmpabtetlist[j], p[j]); setoppo(tmpabtetlist[j], p[j + 1]); } // Transfer the element attributes. for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(abtetlist[0].tet, j); setelemattribute(newtetlist[0].tet, j, attrib); setelemattribute(newtetlist[1].tet, j, attrib); for (k = 0; k < n - 1; k++) { setelemattribute(tmpabtetlist[k].tet, j, attrib); } } // Transfer the volume constraints. if (b->varvolume && !b->refine) { volume = volumebound(abtetlist[0].tet); setvolumebound(newtetlist[0].tet, volume); setvolumebound(newtetlist[1].tet, volume); for (k = 0; k < n - 1; k++) { setvolumebound(tmpabtetlist[k].tet, volume); } } // Glue the new tets at their internal faces: 2 + (n - 1). bond(newtetlist[0], newtetlist[1]); // p_n-1.p_1.p_0. fnext(newtetlist[0], newfront); enext2fnext(tmpabtetlist[0], adjfront); bond(newfront, adjfront); // p_n-1.p_1.a. fnext(newtetlist[1], newfront); enextfnext(tmpabtetlist[0], adjfront); bond(newfront, adjfront); // p_n-1.p_1.b. // Glue n - 1 internal faces around ab. for (j = 0; j < n - 1; j++) { fnext(tmpabtetlist[j], newfront); bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1 } // Substitute the old tets with the new tets by connecting the new // tets to the adjacent tets in the mesh. There are n * 2 (outer) // faces of the new tets need to be operated. // Note, after the substitution, the old tets still have pointers to // their adjacent tets in the mesh. These pointers can be re-used // to inverse the substitution. for (j = 0; j < n; j++) { // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0). oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enextfnextself(oldfront); // Get an adjacent tet at face: [0]a.p_0.p_n-1 or [j]a.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy. // Get the corresponding face from the new tets. if (j == 0) { enext2fnext(newtetlist[0], newfront); // a.p_0.n_n-1 } else if (j == 1) { enextfnext(newtetlist[0], newfront); // a.p_1.p_0 } else { // j >= 2. enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1 } bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } if (flipque != (queue *) NULL) { // Only queue the faces of the two new tets. if (j < 2) enqueueflipface(newfront, flipque); } } for (j = 0; j < n; j++) { // Get an old tet: [0]a.b.p_0.p_n-1 or [j]a.b.p_j.p_j-1, (j > 0). oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enext2fnextself(oldfront); // Get an adjacent tet at face: [0]b.p_0.p_n-1 or [j]b.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy. // Get the corresponding face from the new tets. if (j == 0) { enextfnext(newtetlist[1], newfront); // b.p_0.n_n-1 } else if (j == 1) { enext2fnext(newtetlist[1], newfront); // b.p_1.p_0 } else { // j >= 2. enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1 } bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } if (flipque != (queue *) NULL) { // Only queue the faces of the two new tets. if (j < 2) enqueueflipface(newfront, flipque); } } // Adjust the faces in the temporary new tets at ab for recursively // processing on the n-1 tets.(See the description at beginning) for (j = 0; j < n - 1; j++) { fnextself(tmpabtetlist[j]); } if (n > 4) { success = removeedgebytranNM(&tmpkey, n-1, tmpabtetlist, &(newtetlist[2]), NULL, NULL, flipque); } else { // assert(n == 4); success = removeedgebyflip32(&tmpkey, tmpabtetlist, &(newtetlist[2]), flipque); } // No matter it was success or not, delete the temporary tets. for (j = 0; j < n - 1; j++) { tetrahedrondealloc(tmpabtetlist[j].tet); } if (success) { // The new configuration is good. // Do not delete the old tets. // for (j = 0; j < n; j++) { // tetrahedrondealloc(abtetlist[j].tet); // } // Save the minimal improved quality value. if (key != (REAL *) NULL) { *key = (tmpkey < cosmaxd ? tmpkey : cosmaxd); } return true; } else { // The new configuration is bad, substitue back the old tets. if (elemfliplist != NULL) { // Remove the last registered 2-to-3 flip. elemfliplist->objects--; } for (j = 0; j < n; j++) { oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy. bond(oldfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(oldfront, checksh); } } } for (j = 0; j < n; j++) { oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy bond(oldfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(oldfront, checksh); } } } // Delete the new tets. tetrahedrondealloc(newtetlist[0].tet); tetrahedrondealloc(newtetlist[1].tet); // If tmpkey has been modified, then the failure was not due to // unflipable configuration, but the non-improvement. if (key && (tmpkey < *key)) { *key = tmpkey; return false; } } // if (success) } // if (doflip) } // if (ori > 0.0) } // for (i = 0; i < n; i++) return false; } /////////////////////////////////////////////////////////////////////////////// // // // removeedgebycombNM() Remove an edge by combining two flipNMs. // // // // Given a set T of tets surrounding edge ab. The premise is that ab can not // // be removed by a flipNM. This routine attempts to remove ab by two flipNMs,// // i.e., first find and flip an edge af (or bf) by flipNM, then flip ab by // // flipNM. If it succeeds, two sets T(ab) and T(af) of tets are replaced by // // a new set T' and both ab and af are not edges in T' anymore. // // // // 'abtetlist' contains n tets sharing ab. Imaging that ab is perpendicular // // to the screen, such that a lies in front of and b lies behind it. Let the // // projections of the n apexes on the screen in clockwise order are: p_0,...,// // p_n-1, respectively. So the list of tets are: [0]abp_0p_n-1, [1]abp_1p_0, // // ..., [n-1]abp_n-1p_n-2, respectively. // // // // The principle of the approach is: for a face a.b.p_0, check if edge b.p_0 // // is of type N32 (or N44). If it is, then try to do a flipNM on it. If the // // flip is successful, then try to do another flipNM on a.b. If one of the // // two flipNMs fails, restore the old tets as they have never been flipped. // // Then try the next face a.b.p_1. The process can be looped for all faces // // having ab. Stop if ab is removed or all faces have been visited. Note in // // the above description only b.p_0 is considered, a.p_0 is done by swapping // // the position of a and b. // // // // Similar operations have been described in [Joe,1995]. My approach checks // // more cases for finding flips than Joe's. For instance, the cases (1)-(7) // // of Joe only consider abf for finding a flip (T23/T32). My approach looks // // all faces at ab for finding flips. Moreover, the flipNM can flip an edge // // whose star may have more than 3 tets while Joe's only works on 3-tet case.// // // // If ab is removed, 'newtetlist' contains the new tets. Two sets 'abtetlist'// // (n tets) and 'bftetlist' (n1 tets) have been replaced. The number of new // // tets can be calculated by follows: the 1st flip transforms n1 tets into // // (n1 - 2) * 2 new tets, however,one of the new tets goes into the new link // // of ab, i.e., the reduced tet number in Star(ab) is n - 1; the 2nd flip // // transforms n - 1 tets into (n - 3) * 2 new tets. Hence the number of new // // tets are: m = ((n1 - 2) * 2 - 1) + (n - 3) * 2. The old tets are NOT del-// // eted. The caller has the right to delete them or reverse the operation. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removeedgebycombNM(REAL *key, int n, triface *abtetlist, int *n1, triface *bftetlist, triface *newtetlist, queue *flipque) { triface tmpabtetlist[21]; triface newfront, oldfront, adjfront; face checksh; point pa, pb, p[21]; REAL ori, tmpkey, tmpkey2; REAL attrib, volume; bool doflip, success; int twice, count; int i, j, k, m; // point *ppt; // Used together with fixededgelist. long bakflipcount; // Used for elemfliplist. // Maximal 20 tets in Star(ab). assert(n < 20); // n <= b->maxflipedgelinksize // Do the following procedure twice, one for flipping edge b.p_0 and the // other for p_0.a which is symmetric to the first. twice = 0; do { // Two points a and b are fixed. pa = org(abtetlist[0]); pb = dest(abtetlist[0]); // The points p_0, ..., p_n-1 are permuted in the following loop. for (i = 0; i < n; i++) { // Get the n points for the current configuration. for (j = 0; j < n; j++) { p[j] = apex(abtetlist[(i + j) % n]); } // Check if b.p_0 is of type N32 or N44. ori = orient3d(pb, p[0], p[1], p[n - 1]); if ((ori > 0) && (key != (REAL *) NULL)) { // b.p_0 is not N32. However, it is possible that the tet b.p_0.p_1. // p_n-1 has worse quality value than the key. In such case, also // try to flip b.p_0. tetalldihedral(pb, p[0], p[n - 1], p[1], NULL, &tmpkey, NULL); if (tmpkey < *key) ori = 0.0; } if ((fixededgelist != NULL) && (ori <= 0.0)) { // b.p_0 is either N32 or N44. Do not flip a fixed edge. if (check4fixededge(pb, p[0])) { ori = 1.0; // Do not flip this edge. Skip it. } } if (ori <= 0.0) { // b.p_0 is either N32 or N44. Try the 1st flipNM. bftetlist[0] = abtetlist[i]; enextself(bftetlist[0]);// go to edge b.p_0. adjustedgering(bftetlist[0], CW); // edge p_0.b. assert(apex(bftetlist[0]) == pa); // Form Star(b.p_0). doflip = true; *n1 = 0; do { // Is the list full? if (*n1 == 20) break; if (checksubfaces) { // Stop if a subface appears. tspivot(bftetlist[*n1], checksh); if (checksh.sh != dummysh) { doflip = false; break; } } // Get the next tet at p_0.b. if (!fnext(bftetlist[*n1], bftetlist[(*n1) + 1])) { // Meet a boundary face. Do not flip. doflip = false; break; } (*n1)++; } while (apex(bftetlist[*n1]) != pa); // 2 < n1 <= b->maxflipedgelinksize. if (doflip) { success = false; tmpkey = -1.0; // = acos(pi). if (key != (REAL *) NULL) tmpkey = *key; m = 0; if (*n1 == 3) { // Three tets case. Try flip32. success = removeedgebyflip32(&tmpkey,bftetlist,newtetlist,flipque); m = 2; } else if ((*n1 > 3) && (*n1 <= b->maxflipedgelinksize)) { // Four or more tets case. Try flipNM. success = removeedgebytranNM(&tmpkey, *n1, bftetlist, newtetlist, p[1], p[n - 1], flipque); // If success, the number of new tets. m = ((*n1) - 2) * 2; } else { if (b->verbose > 1) { printf(" !! Unhandled case: n1 = %d.\n", *n1); } } if (success) { // b.p_0 is flipped. The link of ab is reduced (by 1), i.e., p_0 // is not on the link of ab. Two old tets a.b.p_0.p_n-1 and // a.b.p_1.p_0 have been removed from the Star(ab) and one new // tet t = a.b.p_1.p_n-1 belongs to Star(ab). // Find t in the 'newtetlist' and remove it from the list. setpointmark(pa, -pointmark(pa) - 1); setpointmark(pb, -pointmark(pb) - 1); assert(m > 0); for (j = 0; j < m; j++) { tmpabtetlist[0] = newtetlist[j]; // Does it has ab? count = 0; for (k = 0; k < 4; k++) { if (pointmark((point)(tmpabtetlist[0].tet[4+k])) < 0) count++; } if (count == 2) { // It is. Adjust t to be the edge ab. for (tmpabtetlist[0].loc = 0; tmpabtetlist[0].loc < 4; tmpabtetlist[0].loc++) { if ((oppo(tmpabtetlist[0]) != pa) && (oppo(tmpabtetlist[0]) != pb)) break; } // The face of t must contain ab. assert(tmpabtetlist[0].loc < 4); findedge(&(tmpabtetlist[0]), pa, pb); break; } } assert(j < m); // The tet must exist. // Remove t from list. Fill t's position by the last tet. newtetlist[j] = newtetlist[m - 1]; setpointmark(pa, -(pointmark(pa) + 1)); setpointmark(pb, -(pointmark(pb) + 1)); // Create the temporary Star(ab) for the next flipNM. adjustedgering(tmpabtetlist[0], CCW); if (org(tmpabtetlist[0]) != pa) { fnextself(tmpabtetlist[0]); esymself(tmpabtetlist[0]); } #ifdef SELF_CHECK // Make sure current edge is a->b. assert(org(tmpabtetlist[0]) == pa); assert(dest(tmpabtetlist[0]) == pb); assert(apex(tmpabtetlist[0]) == p[n - 1]); assert(oppo(tmpabtetlist[0]) == p[1]); #endif // SELF_CHECK // There are n - 2 left temporary tets. for (j = 1; j < n - 1; j++) { maketetrahedron(&(tmpabtetlist[j])); setorg(tmpabtetlist[j], pa); setdest(tmpabtetlist[j], pb); setapex(tmpabtetlist[j], p[j]); setoppo(tmpabtetlist[j], p[j + 1]); } // Transfer the element attributes. for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(abtetlist[0].tet, j); for (k = 0; k < n - 1; k++) { setelemattribute(tmpabtetlist[k].tet, j, attrib); } } // Transfer the volume constraints. if (b->varvolume && !b->refine) { volume = volumebound(abtetlist[0].tet); for (k = 0; k < n - 1; k++) { setvolumebound(tmpabtetlist[k].tet, volume); } } // Glue n - 1 internal faces of Star(ab). for (j = 0; j < n - 1; j++) { fnext(tmpabtetlist[j], newfront); bond(newfront, tmpabtetlist[(j + 1) % (n - 1)]); // a.b.p_j+1 } // Substitute the old tets with the new tets by connecting the // new tets to the adjacent tets in the mesh. There are (n-2) // * 2 (outer) faces of the new tets need to be operated. // Note that the old tets still have the pointers to their // adjacent tets in the mesh. These pointers can be re-used // to inverse the substitution. for (j = 2; j < n; j++) { // Get an old tet: [j]a.b.p_j.p_j-1, (j > 1). oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enextfnextself(oldfront); // Get an adjacent tet at face: [j]a.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy. // Get the corresponding face from the new tets. // j >= 2. enext2fnext(tmpabtetlist[j - 1], newfront); // a.p_j.p_j-1 bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } } for (j = 2; j < n; j++) { // Get an old tet: [j]a.b.p_j.p_j-1, (j > 2). oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enext2fnextself(oldfront); // Get an adjacent tet at face: [j]b.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy. // Get the corresponding face from the new tets. // j >= 2. enextfnext(tmpabtetlist[j - 1], newfront); // b.p_j.p_j-1 bond(newfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(newfront, checksh); } } } // Adjust the faces in the temporary new tets at ab for // recursively processing on the n-1 tets. for (j = 0; j < n - 1; j++) { fnextself(tmpabtetlist[j]); } tmpkey2 = -1; if (key) tmpkey2 = *key; if (elemfliplist != NULL) { // Remember the current registered flips. bakflipcount = elemfliplist->objects; } if ((n - 1) == 3) { success = removeedgebyflip32(&tmpkey2, tmpabtetlist, &(newtetlist[m - 1]), flipque); } else { // assert((n - 1) >= 4); success = removeedgebytranNM(&tmpkey2, n - 1, tmpabtetlist, &(newtetlist[m - 1]), NULL, NULL, flipque); } // No matter it was success or not, delete the temporary tets. for (j = 0; j < n - 1; j++) { tetrahedrondealloc(tmpabtetlist[j].tet); } if (success) { // The new configuration is good. // Do not delete the old tets. // for (j = 0; j < n; j++) { // tetrahedrondealloc(abtetlist[j].tet); // } // Return the bigger dihedral in the two sets of new tets. if (key != (REAL *) NULL) { *key = tmpkey2 < tmpkey ? tmpkey2 : tmpkey; } return true; } else { // The new configuration is bad, substitue back the old tets. if (elemfliplist != NULL) { // Restore the registered flips. elemfliplist->objects = bakflipcount; } for (j = 0; j < n; j++) { oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enextfnextself(oldfront); // [0]a.p_0.p_n-1, [j]a.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy. bond(oldfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(oldfront, checksh); } } } for (j = 0; j < n; j++) { oldfront = abtetlist[(i + j) % n]; esymself(oldfront); enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy bond(oldfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(oldfront, checksh); } } } // Substitute back the old tets of the first flip. for (j = 0; j < *n1; j++) { oldfront = bftetlist[j]; esymself(oldfront); enextfnextself(oldfront); sym(oldfront, adjfront); // adjfront may be dummy. bond(oldfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(oldfront, checksh); } } } for (j = 0; j < *n1; j++) { oldfront = bftetlist[j]; esymself(oldfront); enext2fnextself(oldfront); // [0]b.p_0.p_n-1, [j]b.p_j.p_j-1. sym(oldfront, adjfront); // adjfront may be dummy bond(oldfront, adjfront); if (checksubfaces) { tspivot(oldfront, checksh); if (checksh.sh != dummysh) { tsbond(oldfront, checksh); } } } // Delete the new tets of the first flip. Note that one new // tet has already been removed from the list. for (j = 0; j < m - 1; j++) { tetrahedrondealloc(newtetlist[j].tet); } } // if (success) } // if (success) } // if (doflip) } // if (ori <= 0.0) } // for (i = 0; i < n; i++) // Inverse a and b and the tets configuration. for (i = 0; i < n; i++) newtetlist[i] = abtetlist[i]; for (i = 0; i < n; i++) { oldfront = newtetlist[n - i - 1]; esymself(oldfront); fnextself(oldfront); abtetlist[i] = oldfront; } twice++; } while (twice < 2); return false; } /////////////////////////////////////////////////////////////////////////////// // // // splittetrahedron() Insert a point into a tetrahedron, split it into // // four tetrahedra. // // // // The tetrahedron is given by 'splittet'. Let it is abcd. The inserting // // point 'newpoint' v should lie strictly inside abcd. // // // // Splitting a tetrahedron is to shrink abcd to abcv, and create three new // // tetrahedra badv, cbdv, and acdv. // // // // On completion, 'splittet' returns abcv. If 'flipqueue' is not NULL, it // // contains all possibly non-locally Delaunay faces. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::splittetrahedron(point newpoint, triface* splittet, queue* flipqueue) { triface oldabd, oldbcd, oldcad; // Old configuration. triface abdcasing, bcdcasing, cadcasing; face abdsh, bcdsh, cadsh; triface abcv, badv, cbdv, acdv; // New configuration. triface worktet; face abseg, bcseg, caseg; face adseg, bdseg, cdseg; point pa, pb, pc, pd; REAL attrib, volume; int i; abcv = *splittet; abcv.ver = 0; // Set the changed vertices and new tetrahedron. pa = org(abcv); pb = dest(abcv); pc = apex(abcv); pd = oppo(abcv); if (b->verbose > 1) { printf(" Inserting point %d in tetrahedron (%d, %d, %d, %d).\n", pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd)); } fnext(abcv, oldabd); enextfnext(abcv, oldbcd); enext2fnext(abcv, oldcad); sym(oldabd, abdcasing); sym(oldbcd, bcdcasing); sym(oldcad, cadcasing); maketetrahedron(&badv); maketetrahedron(&cbdv); maketetrahedron(&acdv); // Set 'badv' vertices. setorg (badv, pb); setdest(badv, pa); setapex(badv, pd); setoppo(badv, newpoint); // Set 'cbdv' vertices. setorg (cbdv, pc); setdest(cbdv, pb); setapex(cbdv, pd); setoppo(cbdv, newpoint); // Set 'acdv' vertices. setorg (acdv, pa); setdest(acdv, pc); setapex(acdv, pd); setoppo(acdv, newpoint); // Set 'abcv' vertices setoppo(abcv, newpoint); // Set the element attributes of the new tetrahedra. for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(abcv.tet, i); setelemattribute(badv.tet, i, attrib); setelemattribute(cbdv.tet, i, attrib); setelemattribute(acdv.tet, i, attrib); } // Set the volume constraint of the new tetrahedra. if (b->varvolume) { volume = volumebound(abcv.tet); setvolumebound(badv.tet, volume); setvolumebound(cbdv.tet, volume); setvolumebound(acdv.tet, volume); } // Bond the new triangles to the surrounding tetrahedron. bond(badv, abdcasing); bond(cbdv, bcdcasing); bond(acdv, cadcasing); // There may exist subfaces need to be bonded to the new tetrahedra. if (checksubfaces) { tspivot(oldabd, abdsh); if (abdsh.sh != dummysh) { tsdissolve(oldabd); tsbond(badv, abdsh); } tspivot(oldbcd, bcdsh); if (bcdsh.sh != dummysh) { tsdissolve(oldbcd); tsbond(cbdv, bcdsh); } tspivot(oldcad, cadsh); if (cadsh.sh != dummysh) { tsdissolve(oldcad); tsbond(acdv, cadsh); } } else if (checksubsegs) { tsspivot1(abcv, abseg); if (abseg.sh != dummysh) { tssbond1(badv, abseg); } enext(abcv, worktet); tsspivot1(worktet, bcseg); if (bcseg.sh != dummysh) { tssbond1(cbdv, bcseg); } enext2(abcv, worktet); tsspivot1(worktet, caseg); if (caseg.sh != dummysh) { tssbond1(acdv, caseg); } fnext(abcv, worktet); enext2self(worktet); tsspivot1(worktet, adseg); if (adseg.sh != dummysh) { tssdissolve1(worktet); enext(badv, worktet); tssbond1(worktet, adseg); enext2(acdv, worktet); tssbond1(worktet, adseg); } enextfnext(abcv, worktet); enext2self(worktet); tsspivot1(worktet, bdseg); if (bdseg.sh != dummysh) { tssdissolve1(worktet); enext(cbdv, worktet); tssbond1(worktet, bdseg); enext2(badv, worktet); tssbond1(worktet, bdseg); } enext2fnext(abcv, worktet); enext2self(worktet); tsspivot1(worktet, cdseg); if (cdseg.sh != dummysh) { tssdissolve1(worktet); enext(acdv, worktet); tssbond1(worktet, cdseg); enext2(cbdv, worktet); tssbond1(worktet, cdseg); } } badv.loc = 3; cbdv.loc = 2; bond(badv, cbdv); cbdv.loc = 3; acdv.loc = 2; bond(cbdv, acdv); acdv.loc = 3; badv.loc = 2; bond(acdv, badv); badv.loc = 1; bond(badv, oldabd); cbdv.loc = 1; bond(cbdv, oldbcd); acdv.loc = 1; bond(acdv, oldcad); badv.loc = 0; cbdv.loc = 0; acdv.loc = 0; if (b->verbose > 3) { printf(" Updating abcv "); printtet(&abcv); printf(" Creating badv "); printtet(&badv); printf(" Creating cbdv "); printtet(&cbdv); printf(" Creating acdv "); printtet(&acdv); } if (flipqueue != (queue *) NULL) { enqueueflipface(abcv, flipqueue); enqueueflipface(badv, flipqueue); enqueueflipface(cbdv, flipqueue); enqueueflipface(acdv, flipqueue); } // Save a handle for quick point location. recenttet = abcv; // Set the return handle be abcv. *splittet = abcv; } /////////////////////////////////////////////////////////////////////////////// // // // splittetface() Insert a point on a face of a mesh. // // // // 'splittet' is the splitting face. Let it is abcd, where abc is the face // // will be split. If abc is not a hull face, abce is the tetrahedron at the // // opposite of d. // // // // To split face abc by a point v is to shrink the tetrahedra abcd to abvd, // // create two new tetrahedra bcvd, cavd. If abc is not a hull face, shrink // // the tetrahedra bace to bave, create two new tetrahedra cbve, acve. // // // // If abc is a subface, it is split into three subfaces simultaneously by // // calling routine splitsubface(), hence, abv, bcv, cav. The edge rings of // // the split subfaces have the same orientation as abc's. // // // // On completion, 'splittet' returns abvd. If 'flipqueue' is not NULL, it // // contains all possibly non-locally Delaunay faces. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::splittetface(point newpoint, triface* splittet, queue* flipqueue) { triface abcd, bace; // Old configuration. triface oldbcd, oldcad, oldace, oldcbe; triface bcdcasing, cadcasing, acecasing, cbecasing; face abcsh, bcdsh, cadsh, acesh, cbesh; triface abvd, bcvd, cavd, bave, cbve, acve; // New configuration. triface worktet; face bcseg, caseg; face adseg, bdseg, cdseg; face aeseg, beseg, ceseg; point pa, pb, pc, pd, pe; REAL attrib, volume; bool mirrorflag; int i; abcd = *splittet; // abcd.ver = 0; // Adjust to be CCW edge ring. adjustedgering(abcd, CCW); pa = org(abcd); pb = dest(abcd); pc = apex(abcd); pd = oppo(abcd); pe = (point) NULL; // avoid a compile warning. // Is there a second tetrahderon? mirrorflag = issymexist(&abcd); if (mirrorflag) { // This is an interior face. sym(abcd, bace); findedge(&bace, dest(abcd), org(abcd)); pe = oppo(bace); } if (checksubfaces) { // Is there a subface need to be split together? tspivot(abcd, abcsh); if (abcsh.sh != dummysh) { // Exists! Keep the edge ab of both handles be the same. findedge(&abcsh, org(abcd), dest(abcd)); } } if (b->verbose > 1) { printf(" Inserting point %d on face (%d, %d, %d).\n", pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc)); } // Save the old configuration at faces bcd and cad. enextfnext(abcd, oldbcd); enext2fnext(abcd, oldcad); sym(oldbcd, bcdcasing); sym(oldcad, cadcasing); // Create two new tetrahedra. maketetrahedron(&bcvd); maketetrahedron(&cavd); if (mirrorflag) { // Save the old configuration at faces bce and cae. enextfnext(bace, oldace); enext2fnext(bace, oldcbe); sym(oldace, acecasing); sym(oldcbe, cbecasing); // Create two new tetrahedra. maketetrahedron(&acve); maketetrahedron(&cbve); } else { // Splitting a boundary face increases the number of boundary faces. hullsize += 2; } // Set vertices to the changed tetrahedron and new tetrahedra. abvd = abcd; // Update 'abcd' to 'abvd'. setapex(abvd, newpoint); setorg (bcvd, pb); // Set 'bcvd'. setdest(bcvd, pc); setapex(bcvd, newpoint); setoppo(bcvd, pd); setorg (cavd, pc); // Set 'cavd'. setdest(cavd, pa); setapex(cavd, newpoint); setoppo(cavd, pd); // Set the element attributes of the new tetrahedra. for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(abvd.tet, i); setelemattribute(bcvd.tet, i, attrib); setelemattribute(cavd.tet, i, attrib); } if (b->varvolume) { // Set the area constraint of the new tetrahedra. volume = volumebound(abvd.tet); setvolumebound(bcvd.tet, volume); setvolumebound(cavd.tet, volume); } if (mirrorflag) { bave = bace; // Update 'bace' to 'bave'. setapex(bave, newpoint); setorg (acve, pa); // Set 'acve'. setdest(acve, pc); setapex(acve, newpoint); setoppo(acve, pe); setorg (cbve, pc); // Set 'cbve'. setdest(cbve, pb); setapex(cbve, newpoint); setoppo(cbve, pe); // Set the element attributes of the new tetrahedra. for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(bave.tet, i); setelemattribute(acve.tet, i, attrib); setelemattribute(cbve.tet, i, attrib); } if (b->varvolume) { // Set the area constraint of the new tetrahedra. volume = volumebound(bave.tet); setvolumebound(acve.tet, volume); setvolumebound(cbve.tet, volume); } } // Bond the new tetrahedra to the surrounding tetrahedra. bcvd.loc = 1; bond(bcvd, bcdcasing); cavd.loc = 1; bond(cavd, cadcasing); bcvd.loc = 3; bond(bcvd, oldbcd); cavd.loc = 2; bond(cavd, oldcad); bcvd.loc = 2; cavd.loc = 3; bond(bcvd, cavd); if (mirrorflag) { acve.loc = 1; bond(acve, acecasing); cbve.loc = 1; bond(cbve, cbecasing); acve.loc = 3; bond(acve, oldace); cbve.loc = 2; bond(cbve, oldcbe); acve.loc = 2; cbve.loc = 3; bond(acve, cbve); // Bond two new coplanar facets. bcvd.loc = 0; cbve.loc = 0; bond(bcvd, cbve); cavd.loc = 0; acve.loc = 0; bond(cavd, acve); } // There may exist subface needed to be bonded to the new tetrahedra. if (checksubfaces) { tspivot(oldbcd, bcdsh); if (bcdsh.sh != dummysh) { tsdissolve(oldbcd); bcvd.loc = 1; tsbond(bcvd, bcdsh); } tspivot(oldcad, cadsh); if (cadsh.sh != dummysh) { tsdissolve(oldcad); cavd.loc = 1; tsbond(cavd, cadsh); } if (mirrorflag) { tspivot(oldace, acesh); if (acesh.sh != dummysh) { tsdissolve(oldace); acve.loc = 1; tsbond(acve, acesh); } tspivot(oldcbe, cbesh); if (cbesh.sh != dummysh) { tsdissolve(oldcbe); cbve.loc = 1; tsbond(cbve, cbesh); } } // Is there a subface needs to be split together? if (abcsh.sh != dummysh) { // Split this subface 'abc' into three i.e, abv, bcv, cav. splitsubface(newpoint, &abcsh, (queue *) NULL); } } else if (checksubsegs) { // abvd.loc = abvd.ver = 0; bcvd.loc = bcvd.ver = 0; cavd.loc = cavd.ver = 0; if (mirrorflag) { // bave.loc = bave.ver = 0; cbve.loc = cbve.ver = 0; acve.loc = acve.ver = 0; } enext(abvd, worktet); tsspivot1(worktet, bcseg); if (bcseg.sh != dummysh) { tssdissolve1(worktet); tssbond1(bcvd, bcseg); if (mirrorflag) { enext2(bave, worktet); tssdissolve1(worktet); tssbond1(cbve, bcseg); } } enext2(abvd, worktet); tsspivot1(worktet, caseg); if (caseg.sh != dummysh) { tssdissolve1(worktet); tssbond1(cavd, caseg); if (mirrorflag) { enext(bave, worktet); tssdissolve1(worktet); tssbond1(acve, caseg); } } fnext(abvd, worktet); enext2self(worktet); tsspivot1(worktet, adseg); if (adseg.sh != dummysh) { fnext(cavd, worktet); enextself(worktet); tssbond1(worktet, adseg); } fnext(abvd, worktet); enextself(worktet); tsspivot1(worktet, bdseg); if (bdseg.sh != dummysh) { fnext(bcvd, worktet); enext2self(worktet); tssbond1(worktet, bdseg); } enextfnext(abvd, worktet); enextself(worktet); tsspivot1(worktet, cdseg); if (cdseg.sh != dummysh) { tssdissolve1(worktet); fnext(bcvd, worktet); enextself(worktet); tssbond1(worktet, cdseg); fnext(cavd, worktet); enext2self(worktet); tssbond1(worktet, cdseg); } if (mirrorflag) { fnext(bave, worktet); enextself(worktet); tsspivot1(worktet, aeseg); if (aeseg.sh != dummysh) { fnext(acve, worktet); enext2self(worktet); tssbond1(worktet, aeseg); } fnext(bave, worktet); enext2self(worktet); tsspivot1(worktet, beseg); if (beseg.sh != dummysh) { fnext(cbve, worktet); enextself(worktet); tssbond1(worktet, beseg); } enextfnext(bave, worktet); enextself(worktet); tsspivot1(worktet, ceseg); if (ceseg.sh != dummysh) { tssdissolve1(worktet); fnext(cbve, worktet); enext2self(worktet); tssbond1(worktet, ceseg); fnext(acve, worktet); enextself(worktet); tssbond1(worktet, ceseg); } } } // Save a handle for quick point location. recenttet = abvd; // Set the return handle be abvd. *splittet = abvd; bcvd.loc = 0; cavd.loc = 0; if (mirrorflag) { cbve.loc = 0; acve.loc = 0; } if (b->verbose > 3) { printf(" Updating abvd "); printtet(&abvd); printf(" Creating bcvd "); printtet(&bcvd); printf(" Creating cavd "); printtet(&cavd); if (mirrorflag) { printf(" Updating bave "); printtet(&bave); printf(" Creating cbve "); printtet(&cbve); printf(" Creating acve "); printtet(&acve); } } if (flipqueue != (queue *) NULL) { fnextself(abvd); enqueueflipface(abvd, flipqueue); fnextself(bcvd); enqueueflipface(bcvd, flipqueue); fnextself(cavd); enqueueflipface(cavd, flipqueue); if (mirrorflag) { fnextself(bave); enqueueflipface(bave, flipqueue); fnextself(cbve); enqueueflipface(cbve, flipqueue); fnextself(acve); enqueueflipface(acve, flipqueue); } } } /////////////////////////////////////////////////////////////////////////////// // // // splitsubface() Insert a point on a subface, split it into three. // // // // The subface is 'splitface'. Let it is abc. The inserting point 'newpoint'// // v should lie inside abc. If the neighbor tetrahedra of abc exist, i.e., // // abcd and bace, they should have been split by routine splittetface() // // before calling this routine, so the connection between the new tetrahedra // // and new subfaces can be correctly set. // // // // To split subface abc by point v is to shrink abc to abv, create two new // // subfaces bcv and cav. Set the connection between updated and new created // // subfaces. If there is a subsegment at edge bc or ca, connection of new // // subface (bcv or cav) to its casing subfaces is a face link, 'casingin' is // // the predecessor and 'casingout' is the successor. It is important to keep // // the orientations of the edge rings of the updated and created subfaces be // // the same as abc's. So they have the same orientation as other subfaces of // // this facet with respect to the lift point of this facet. // // // // On completion, 'splitface' returns abv. If 'flipqueue' is not NULL, it // // returns all possibly non-Delaunay edges. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::splitsubface(point newpoint, face* splitface, queue* flipqueue) { triface abvd, bcvd, cavd, bave, cbve, acve; face abc, oldbc, oldca, bc, ca, spinsh; face bccasin, bccasout, cacasin, cacasout; face abv, bcv, cav; point pa, pb, pc; abc = *splitface; // The newly created subfaces will have the same edge ring as abc. adjustedgering(abc, CCW); pa = sorg(abc); pb = sdest(abc); pc = sapex(abc); if (b->verbose > 1) { printf(" Inserting point %d on subface (%d, %d, %d).\n", pointmark(newpoint), pointmark(pa), pointmark(pb), pointmark(pc)); } // Save the old configuration at edge bc and ca. Subsegments may appear // at both sides, save the face links and dissolve them. senext(abc, oldbc); senext2(abc, oldca); spivot(oldbc, bccasout); sspivot(oldbc, bc); if (bc.sh != dummysh) { if (bccasout.sh != dummysh) { // 'oldbc' is not self-bonded. spinsh = bccasout; do { bccasin = spinsh; spivotself(spinsh); } while (spinsh.sh != oldbc.sh); } ssdissolve(oldbc); } spivot(oldca, cacasout); sspivot(oldca, ca); if (ca.sh != dummysh) { if (cacasout.sh != dummysh) { // 'oldca' is not self-bonded. spinsh = cacasout; do { cacasin = spinsh; spivotself(spinsh); } while (spinsh.sh != oldca.sh); } ssdissolve(oldca); } // Create two new subfaces. makeshellface(subfaces, &bcv); makeshellface(subfaces, &cav); // Set the vertices of changed and new subfaces. abv = abc; // Update 'abc' to 'abv'. setsapex(abv, newpoint); setsorg(bcv, pb); // Set 'bcv'. setsdest(bcv, pc); setsapex(bcv, newpoint); setsorg(cav, pc); // Set 'cav'. setsdest(cav, pa); setsapex(cav, newpoint); if (b->quality && varconstraint) { // Copy yhr area bound into the new subfaces. setareabound(bcv, areabound(abv)); setareabound(cav, areabound(abv)); } // Copy the boundary mark into the new subfaces. setshellmark(bcv, shellmark(abv)); setshellmark(cav, shellmark(abv)); // Copy the subface type into the new subfaces. setshelltype(bcv, shelltype(abv)); setshelltype(cav, shelltype(abv)); if (checkpbcs) { // Copy the pbcgroup into the new subfaces. setshellpbcgroup(bcv, shellpbcgroup(abv)); setshellpbcgroup(cav, shellpbcgroup(abv)); } // Bond the new subfaces to the surrounding subfaces. if (bc.sh != dummysh) { if (bccasout.sh != dummysh) { sbond1(bccasin, bcv); sbond1(bcv, bccasout); } else { // Bond 'bcv' to itsself. sdissolve(bcv); // sbond(bcv, bcv); } ssbond(bcv, bc); } else { sbond(bcv, bccasout); } if (ca.sh != dummysh) { if (cacasout.sh != dummysh) { sbond1(cacasin, cav); sbond1(cav, cacasout); } else { // Bond 'cav' to itself. sdissolve(cav); // sbond(cav, cav); } ssbond(cav, ca); } else { sbond(cav, cacasout); } senext2self(bcv); sbond(bcv, oldbc); senextself(cav); sbond(cav, oldca); senext2self(bcv); senextself(cav); sbond(bcv, cav); // Bond the new subfaces to the new tetrahedra if they exist. stpivot(abv, abvd); if (abvd.tet != dummytet) { // Get two new tetrahedra and their syms. findedge(&abvd, sorg(abv), sdest(abv)); enextfnext(abvd, bcvd); #ifdef SELF_CHECK assert(bcvd.tet != dummytet); #endif fnextself(bcvd); enext2fnext(abvd, cavd); #ifdef SELF_CHECK assert(cavd.tet != dummytet); #endif fnextself(cavd); // Bond two new subfaces to the two new tetrahedra. tsbond(bcvd, bcv); tsbond(cavd, cav); } // Set the connection at the other sides if the tetrahedra exist. sesymself(abv); // bav stpivot(abv, bave); if (bave.tet != dummytet) { sesymself(bcv); // cbv sesymself(cav); // acv // Get two new tetrahedra and their syms. findedge(&bave, sorg(abv), sdest(abv)); enextfnext(bave, acve); #ifdef SELF_CHECK assert(acve.tet != dummytet); #endif fnextself(acve); enext2fnext(bave, cbve); #ifdef SELF_CHECK assert(cbve.tet != dummytet); #endif fnextself(cbve); // Bond two new subfaces to the two new tetrahedra. tsbond(acve, cav); tsbond(cbve, bcv); } bcv.shver = 0; cav.shver = 0; if (b->verbose > 3) { printf(" Updating abv "); printsh(&abv); printf(" Creating bcv "); printsh(&bcv); printf(" Creating cav "); printsh(&cav); } if (flipqueue != (queue *) NULL) { enqueueflipedge(abv, flipqueue); enqueueflipedge(bcv, flipqueue); enqueueflipedge(cav, flipqueue); } // Set the return handle be abv. *splitface = abv; } /////////////////////////////////////////////////////////////////////////////// // // // splittetedge() Insert a point on an edge of the mesh. // // // // The edge is given by 'splittet'. Assume its four corners are a, b, n1 and // // n2, where ab is the edge will be split. Around ab may exist any number of // // tetrahedra. For convenience, they're ordered in a sequence following the // // right-hand rule with your thumb points from a to b. Let the vertex set of // // these tetrahedra be {a, b, n1, n2, ..., n(i)}. NOTE the tetrahedra around // // ab may not connect to each other (can only happen when ab is a subsegment,// // hence some faces abn(i) are subfaces). If ab is a subsegment, abn1 must // // be a subface. // // // // To split edge ab by a point v is to split all tetrahedra containing ab by // // v. More specifically, for each such tetrahedron, an1n2b, it is shrunk to // // an1n2v, and a new tetrahedra bn2n1v is created. If ab is a subsegment, or // // some faces of the splitting tetrahedra are subfaces, they must be split // // either by calling routine 'splitsubedge()'. // // // // On completion, 'splittet' returns avn1n2. If 'flipqueue' is not NULL, it // // returns all faces which may become non-Delaunay after this operation. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::splittetedge(point newpoint, triface* splittet, queue* flipqueue) { triface *bots, *newtops; triface oldtop, topcasing; triface spintet, tmpbond0, tmpbond1; face abseg, splitsh, topsh, spinsh; triface worktet; face n1n2seg, n2vseg, n1vseg; point pa, pb, n1, n2; REAL attrib, volume; int wrapcount, hitbdry; int i, j; if (checksubfaces) { // Is there a subsegment need to be split together? tsspivot(splittet, &abseg); if (abseg.sh != dummysh) { abseg.shver = 0; // Orient the edge direction of 'splittet' be abseg. if (org(*splittet) != sorg(abseg)) { esymself(*splittet); } } } spintet = *splittet; pa = org(spintet); pb = dest(spintet); if (b->verbose > 1) { printf(" Inserting point %d on edge (%d, %d).\n", pointmark(newpoint), pointmark(pa), pointmark(pb)); } // Collect the tetrahedra containing the splitting edge (ab). n1 = apex(spintet); hitbdry = 0; wrapcount = 1; if (checksubfaces && abseg.sh != dummysh) { // It may happen that some tetrahedra containing ab (a subsegment) are // completely disconnected with others. If it happens, use the face // link of ab to cross the boundary. while (true) { if (!fnextself(spintet)) { // Meet a boundary, walk through it. hitbdry ++; tspivot(spintet, spinsh); #ifdef SELF_CHECK assert(spinsh.sh != dummysh); #endif findedge(&spinsh, pa, pb); sfnextself(spinsh); stpivot(spinsh, spintet); #ifdef SELF_CHECK assert(spintet.tet != dummytet); #endif findedge(&spintet, pa, pb); // Remember this position (hull face) in 'splittet'. *splittet = spintet; // Split two hull faces increase the hull size; hullsize += 2; } if (apex(spintet) == n1) break; wrapcount ++; } if (hitbdry > 0) { wrapcount -= hitbdry; } } else { // All the tetrahedra containing ab are connected together. If there // are subfaces, 'splitsh' keeps one of them. splitsh.sh = dummysh; while (hitbdry < 2) { if (checksubfaces && splitsh.sh == dummysh) { tspivot(spintet, splitsh); } if (fnextself(spintet)) { if (apex(spintet) == n1) break; wrapcount++; } else { hitbdry ++; if (hitbdry < 2) { esym(*splittet, spintet); } } } if (hitbdry > 0) { // ab is on the hull. wrapcount -= 1; // 'spintet' now is a hull face, inverse its edge direction. esym(spintet, *splittet); // Split two hull faces increases the number of hull faces. hullsize += 2; } } // Make arrays of updating (bot, oldtop) and new (newtop) tetrahedra. bots = new triface[wrapcount]; newtops = new triface[wrapcount]; // Spin around ab, gather tetrahedra and set up new tetrahedra. spintet = *splittet; for (i = 0; i < wrapcount; i++) { // Get 'bots[i] = an1n2b'. enext2fnext(spintet, bots[i]); esymself(bots[i]); // Create 'newtops[i]'. maketetrahedron(&(newtops[i])); // Go to the next. fnextself(spintet); if (checksubfaces && abseg.sh != dummysh) { if (!issymexist(&spintet)) { // We meet a hull face, walk through it. tspivot(spintet, spinsh); #ifdef SELF_CHECK assert(spinsh.sh != dummysh); #endif findedge(&spinsh, pa, pb); sfnextself(spinsh); stpivot(spinsh, spintet); #ifdef SELF_CHECK assert(spintet.tet != dummytet); #endif findedge(&spintet, pa, pb); } } } // Set the vertices of updated and new tetrahedra. for (i = 0; i < wrapcount; i++) { // Update 'bots[i] = an1n2v'. setoppo(bots[i], newpoint); // Set 'newtops[i] = bn2n1v'. n1 = dest(bots[i]); n2 = apex(bots[i]); // Set 'newtops[i]'. setorg(newtops[i], pb); setdest(newtops[i], n2); setapex(newtops[i], n1); setoppo(newtops[i], newpoint); // Set the element attributes of a new tetrahedron. for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(bots[i].tet, j); setelemattribute(newtops[i].tet, j, attrib); } if (b->varvolume) { // Set the area constraint of a new tetrahedron. volume = volumebound(bots[i].tet); setvolumebound(newtops[i].tet, volume); } //#ifdef SELF_CHECK // Make sure no inversed tetrahedron has been created. volume = orient3d(pa, n1, n2, newpoint); if (volume >= 0.0) { //printf("Internal error in splittetedge(): volume = %.12g.\n", volume); break; } volume = orient3d(pb, n2, n1, newpoint); if (volume >= 0.0) { //printf("Internal error in splittetedge(): volume = %.12g.\n", volume); break; } //#endif } if (i < wrapcount) { // Do not insert this point. It will result inverted or degenerated tet. // Restore have updated tets in "bots". for (; i >= 0; i--) { setoppo(bots[i], pb); } // Deallocate tets in "newtops". for (i = 0; i < wrapcount; i++) { tetrahedrondealloc(newtops[i].tet); } delete [] newtops; delete [] bots; return false; } // Bond newtops to topcasings and bots. for (i = 0; i < wrapcount; i++) { // Get 'oldtop = n1n2va' from 'bots[i]'. enextfnext(bots[i], oldtop); sym(oldtop, topcasing); bond(newtops[i], topcasing); if (checksubfaces) { tspivot(oldtop, topsh); if (topsh.sh != dummysh) { tsdissolve(oldtop); tsbond(newtops[i], topsh); } } enextfnext(newtops[i], tmpbond0); bond(oldtop, tmpbond0); } // Bond between newtops. fnext(newtops[0], tmpbond0); enext2fnext(bots[0], spintet); for (i = 1; i < wrapcount; i ++) { if (issymexist(&spintet)) { enext2fnext(newtops[i], tmpbond1); bond(tmpbond0, tmpbond1); } fnext(newtops[i], tmpbond0); enext2fnext(bots[i], spintet); } // Bond the last to the first if no boundary. if (issymexist(&spintet)) { enext2fnext(newtops[0], tmpbond1); bond(tmpbond0, tmpbond1); } if (checksubsegs) { for (i = 0; i < wrapcount; i++) { enextfnext(bots[i], worktet); // edge n1->n2. tsspivot1(worktet, n1n2seg); if (n1n2seg.sh != dummysh) { enext(newtops[i], tmpbond0); tssbond1(tmpbond0, n1n2seg); } enextself(worktet); // edge n2->v ==> n2->b tsspivot1(worktet, n2vseg); if (n2vseg.sh != dummysh) { tssdissolve1(worktet); tssbond1(newtops[i], n2vseg); } enextself(worktet); // edge v->n1 ==> b->n1 tsspivot1(worktet, n1vseg); if (n1vseg.sh != dummysh) { tssdissolve1(worktet); enext2(newtops[i], tmpbond0); tssbond1(tmpbond0, n1vseg); } } } // Is there exist subfaces and subsegment need to be split? if (checksubfaces) { if (abseg.sh != dummysh) { // A subsegment needs be split. spivot(abseg, splitsh); #ifdef SELF_CHECK assert(splitsh.sh != dummysh); #endif } if (splitsh.sh != dummysh) { // Split subfaces (and subsegment). findedge(&splitsh, pa, pb); splitsubedge(newpoint, &splitsh, (queue *) NULL); } } if (b->verbose > 3) { for (i = 0; i < wrapcount; i++) { printf(" Updating bots[%i] ", i); printtet(&(bots[i])); printf(" Creating newtops[%i] ", i); printtet(&(newtops[i])); } } if (flipqueue != (queue *) NULL) { for (i = 0; i < wrapcount; i++) { enqueueflipface(bots[i], flipqueue); enqueueflipface(newtops[i], flipqueue); } } // Set the return handle be avn1n2. It is got by transforming from // 'bots[0]' (which is an1n2v). fnext(bots[0], spintet); // spintet is an1vn2. esymself(spintet); // spintet is n1avn2. enextself(spintet); // spintet is avn1n2. *splittet = spintet; delete [] bots; delete [] newtops; return true; } /////////////////////////////////////////////////////////////////////////////// // // // splitsubedge() Insert a point on an edge of the surface mesh. // // // // The splitting edge is given by 'splitsh'. Assume its three corners are a, // // b, c, where ab is the edge will be split. ab may be a subsegment. // // // // To split edge ab is to split all subfaces conatining ab. If ab is not a // // subsegment, there are only two subfaces need be split, otherwise, there // // may have any number of subfaces need be split. Each splitting subface abc // // is shrunk to avc, a new subface vbc is created. It is important to keep // // the orientations of edge rings of avc and vbc be the same as abc's. If ab // // is a subsegment, it is shrunk to av and a new subsegment vb is created. // // // // If there are tetrahedra adjoining to the splitting subfaces, they should // // be split before calling this routine, so the connection between the new // // tetrahedra and the new subfaces can be correctly set. // // // // On completion, 'splitsh' returns avc. If 'flipqueue' is not NULL, it // // returns all edges which may be non-Delaunay. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::splitsubedge(point newpoint, face* splitsh, queue* flipqueue) { triface abcd, bace, vbcd, bvce; face startabc, spinabc, spinsh; face oldbc, bccasin, bccasout; face ab, bc; face avc, vbc, vbc1; face av, vb; point pa, pb; startabc = *splitsh; // Is there a subsegment? sspivot(startabc, ab); if (ab.sh != dummysh) { ab.shver = 0; if (sorg(startabc) != sorg(ab)) { sesymself(startabc); } } pa = sorg(startabc); pb = sdest(startabc); if (b->verbose > 1) { printf(" Inserting point %d on subedge (%d, %d) %s.\n", pointmark(newpoint), pointmark(pa), pointmark(pb), (ab.sh != dummysh ? "(seg)" : " ")); } // Spin arround ab, split every subface containing ab. spinabc = startabc; do { // Adjust spinabc be edge ab. if (sorg(spinabc) != pa) { sesymself(spinabc); } // Unmark the face for splitting (used for refinement) 2009-08-17. sunmarktest(spinabc); // Save old configuration at edge bc, if bc has a subsegment, save the // face link of it and dissolve it from bc. senext(spinabc, oldbc); spivot(oldbc, bccasout); sspivot(oldbc, bc); if (bc.sh != dummysh) { if (bccasout.sh != dummysh) { // 'spinabc' is not self-bonded. spinsh = bccasout; do { bccasin = spinsh; spivotself(spinsh); } while (spinsh.sh != oldbc.sh); } else { bccasout.sh = dummysh; } ssdissolve(oldbc); } // Create a new subface. makeshellface(subfaces, &vbc); // Split abc. avc = spinabc; // Update 'abc' to 'avc'. setsdest(avc, newpoint); // Make 'vbc' be in the same edge ring as 'avc'. vbc.shver = avc.shver; setsorg(vbc, newpoint); // Set 'vbc'. setsdest(vbc, pb); setsapex(vbc, sapex(avc)); if (b->quality && varconstraint) { // Copy the area bound into the new subface. setareabound(vbc, areabound(avc)); } // Copy the shell marker and shell type into the new subface. setshellmark(vbc, shellmark(avc)); setshelltype(vbc, shelltype(avc)); if (checkpbcs) { // Copy the pbcgroup into the new subface. setshellpbcgroup(vbc, shellpbcgroup(avc)); } // Set the connection between updated and new subfaces. senext2self(vbc); sbond(vbc, oldbc); // Set the connection between new subface and casings. senext2self(vbc); if (bc.sh != dummysh) { if (bccasout.sh != dummysh) { // Insert 'vbc' into face link. sbond1(bccasin, vbc); sbond1(vbc, bccasout); } else { // Bond 'vbc' to itself. sdissolve(vbc); // sbond(vbc, vbc); } ssbond(vbc, bc); } else { sbond(vbc, bccasout); } // Go to next subface at edge ab. spivotself(spinabc); if (spinabc.sh == dummysh) { break; // 'ab' is a hull edge. } } while (spinabc.sh != startabc.sh); // Get the new subface vbc above the updated subface avc (= startabc). senext(startabc, oldbc); spivot(oldbc, vbc); if (sorg(vbc) == newpoint) { sesymself(vbc); } #ifdef SELF_CHECK assert(sorg(vbc) == sdest(oldbc) && sdest(vbc) == sorg(oldbc)); #endif senextself(vbc); // Set the face link for the new created subfaces around edge vb. spinabc = startabc; do { // Go to the next subface at edge av. spivotself(spinabc); if (spinabc.sh == dummysh) { break; // 'ab' is a hull edge. } if (sorg(spinabc) != pa) { sesymself(spinabc); } // Get the new subface vbc1 above the updated subface avc (= spinabc). senext(spinabc, oldbc); spivot(oldbc, vbc1); if (sorg(vbc1) == newpoint) { sesymself(vbc1); } #ifdef SELF_CHECK assert(sorg(vbc1) == sdest(oldbc) && sdest(vbc1) == sorg(oldbc)); #endif senextself(vbc1); // Set the connection: vbc->vbc1. sbond1(vbc, vbc1); // For the next connection. vbc = vbc1; } while (spinabc.sh != startabc.sh); // Split ab if it is a subsegment. if (ab.sh != dummysh) { // Unmark the segment for mesh optimization. 2009-08-17. sunmarktest(ab); // Update subsegment ab to av. av = ab; setsdest(av, newpoint); // Create a new subsegment vb. makeshellface(subsegs, &vb); setsorg(vb, newpoint); setsdest(vb, pb); // vb gets the same mark and segment type as av. setshellmark(vb, shellmark(av)); setshelltype(vb, shelltype(av)); if (b->quality && varconstraint) { // Copy the area bound into the new subsegment. setareabound(vb, areabound(av)); } // Save the old connection at ab (re-use the handles oldbc, bccasout). senext(av, oldbc); spivot(oldbc, bccasout); // Bond av and vb (bonded at their "fake" edges). senext2(vb, bccasin); sbond(bccasin, oldbc); if (bccasout.sh != dummysh) { // There is a subsegment connecting with ab at b. It will connect // to vb at b after splitting. bccasout.shver = 0; if (sorg(bccasout) != pb) sesymself(bccasout); #ifdef SELF_CHECK assert(sorg(bccasout) == pb); #endif senext2self(bccasout); senext(vb, bccasin); sbond(bccasin, bccasout); } // Bond all new subfaces (vbc) to vb. spinabc = startabc; do { // Adjust spinabc be edge av. if (sorg(spinabc) != pa) { sesymself(spinabc); } // Get new subface vbc above the updated subface avc (= spinabc). senext(spinabc, oldbc); spivot(oldbc, vbc); if (sorg(vbc) == newpoint) { sesymself(vbc); } senextself(vbc); // Bond the new subface and the new subsegment. ssbond(vbc, vb); // Go to the next. spivotself(spinabc); if (spinabc.sh == dummysh) { break; // There's only one facet at the segment.rr } } while (spinabc.sh != startabc.sh); } // Bond the new subfaces to new tetrahedra if they exist. New tetrahedra // should have been created before calling this routine. spinabc = startabc; do { // Adjust spinabc be edge av. if (sorg(spinabc) != pa) { sesymself(spinabc); } // Get new subface vbc above the updated subface avc (= spinabc). senext(spinabc, oldbc); spivot(oldbc, vbc); if (sorg(vbc) == newpoint) { sesymself(vbc); } senextself(vbc); // Get the adjacent tetrahedra at 'spinabc'. stpivot(spinabc, abcd); if (abcd.tet != dummytet) { findedge(&abcd, sorg(spinabc), sdest(spinabc)); enextfnext(abcd, vbcd); fnextself(vbcd); #ifdef SELF_CHECK assert(vbcd.tet != dummytet); #endif tsbond(vbcd, vbc); sym(vbcd, bvce); sesymself(vbc); tsbond(bvce, vbc); } else { // One side is empty, check the other side. sesymself(spinabc); stpivot(spinabc, bace); if (bace.tet != dummytet) { findedge(&bace, sorg(spinabc), sdest(spinabc)); enext2fnext(bace, bvce); fnextself(bvce); #ifdef SELF_CHECK assert(bvce.tet != dummytet); #endif sesymself(vbc); tsbond(bvce, vbc); } } // Go to the next. spivotself(spinabc); if (spinabc.sh == dummysh) { break; // 'ab' is a hull edge. } } while (spinabc.sh != startabc.sh); if (b->verbose > 3) { spinabc = startabc; do { // Adjust spinabc be edge av. if (sorg(spinabc) != pa) { sesymself(spinabc); } printf(" Updating abc:\n"); printsh(&spinabc); // Get new subface vbc above the updated subface avc (= spinabc). senext(spinabc, oldbc); spivot(oldbc, vbc); if (sorg(vbc) == newpoint) { sesymself(vbc); } senextself(vbc); printf(" Creating vbc:\n"); printsh(&vbc); // Go to the next. spivotself(spinabc); if (spinabc.sh == dummysh) { break; // 'ab' is a hull edge. } } while (spinabc.sh != startabc.sh); } if (flipqueue != (queue *) NULL) { spinabc = startabc; do { // Adjust spinabc be edge av. if (sorg(spinabc) != pa) { sesymself(spinabc); } senext2(spinabc, oldbc); // Re-use oldbc. enqueueflipedge(oldbc, flipqueue); // Get new subface vbc above the updated subface avc (= spinabc). senext(spinabc, oldbc); spivot(oldbc, vbc); if (sorg(vbc) == newpoint) { sesymself(vbc); } senextself(vbc); senext(vbc, oldbc); // Re-use oldbc. enqueueflipedge(oldbc, flipqueue); // Go to the next. spivotself(spinabc); if (spinabc.sh == dummysh) { break; // 'ab' is a hull edge. } } while (spinabc.sh != startabc.sh); } } /////////////////////////////////////////////////////////////////////////////// // // // formstarpolyhedron() Get the star ployhedron of a point 'pt'. // // // // The polyhedron P is formed by faces of tets having 'pt' as a vertex. If // // 'complete' is TRUE, P is the complete star of 'pt'. Otherwise, P is boun- // // ded by subfaces, i.e. P is only part of the star of 'pt'. // // // // 'tetlist' T returns the tets, it has one of such tets on input. Moreover, // // if t is in T, then oppo(t) = p. Topologically, T is the star of p; and // // the faces of T is the link of p. 'verlist' V returns the vertices of T. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formstarpolyhedron(point pt, list* tetlist, list* verlist, bool complete) { triface starttet, neightet; face checksh; point ver[3]; int idx, i, j; // Get a tet t containing p. starttet = * (triface *)(* tetlist)[0]; // Let oppo(t) = p. for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { if (oppo(starttet) == pt) break; } assert(starttet.loc < 4); // Add t into T. * (triface *)(* tetlist)[0] = starttet; infect(starttet); if (verlist != (list *) NULL) { // Add three verts of t into V. ver[0] = org(starttet); ver[1] = dest(starttet); ver[2] = apex(starttet); for (i = 0; i < 3; i++) { // Mark the vert by inversing the index of the vert. idx = pointmark(ver[i]); setpointmark(ver[i], -idx - 1); // -1 to distinguish the zero. verlist->append(&(ver[i])); } } // Find other tets by a broadth-first search. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; starttet.ver = 0; for (j = 0; j < 3; j++) { fnext(starttet, neightet); tspivot(neightet, checksh); // Should we cross a subface. if ((checksh.sh == dummysh) || complete) { // Get the neighbor n. symself(neightet); if ((neightet.tet != dummytet) && !infected(neightet)) { // Let oppo(n) = p. for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { if (oppo(neightet) == pt) break; } assert(neightet.loc < 4); // Add n into T. infect(neightet); tetlist->append(&neightet); if (verlist != (list *) NULL) { // Add the apex vertex in n into V. ver[0] = org(starttet); ver[1] = dest(starttet); findedge(&neightet, ver[0], ver[1]); ver[2] = apex(neightet); idx = pointmark(ver[2]); if (idx >= 0) { setpointmark(ver[2], -idx - 1); verlist->append(&(ver[2])); } } } } enextself(starttet); } } // Uninfect tets. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; uninfect(starttet); } if (verlist != (list *) NULL) { // Uninfect vertices. for (i = 0; i < verlist->len(); i++) { ver[0] = * (point *)(* verlist)[i]; idx = pointmark(ver[0]); setpointmark(ver[0], -(idx + 1)); } } } /////////////////////////////////////////////////////////////////////////////// // // // Terminology: BC(p) and CBC(p), B(p) and C(p). // // // // Given an arbitrary point p, the Bowyer-Watson cavity BC(p) is formed by // // tets whose circumspheres containing p. The outer faces of BC(p) form a // // polyhedron B(p). // // // // If p is on a facet F, the constrained Bowyer-Watson cavity CBC(p) on F is // // formed by subfaces of F whose circumspheres containing p. The outer edges // // of CBC(p) form a polygon C(p). B(p) is separated into two parts by C(p), // // denoted as B_1(p) and B_2(p), one of them may be empty (F is on the hull).// // // // If p is on a segment S which is shared by n facets. There exist n C(p)s, // // each one is a non-closed polygon (without S). B(p) is split into n parts, // // each of them is denoted as B_i(p), some B_i(p) may be empty. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // formbowatcavitysub() Form CBC(p) and C(p) on a facet F. // // // // Parameters: bp = p, bpseg = S, sublist = CBC(p), subceillist = C(p). // // // // CBC(p) contains at least one subface on input; S may be NULL which means // // that p is inside a facet. On output, all subfaces of CBC(p) are infected, // // and the edge rings are oriented to the same halfspace. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formbowatcavitysub(point bp, face* bpseg, list* sublist, list* subceillist) { triface adjtet; face startsh, neighsh; face checkseg; point pa, pb, pc, pd; REAL sign; int i, j; // Form CBC(p) and C(p) by a broadth-first searching. for (i = 0; i < sublist->len(); i++) { startsh = * (face *)(* sublist)[i]; // startsh = f. // Look for three neighbors of f. for (j = 0; j < 3; j++) { sspivot(startsh, checkseg); if (checkseg.sh == dummysh) { // Get its neighbor n. spivot(startsh, neighsh); // Is n already in CBC(p)? if (!sinfected(neighsh)) { stpivot(neighsh, adjtet); if (adjtet.tet == dummytet) { sesymself(neighsh); stpivot(neighsh, adjtet); } // For positive orientation that insphere() test requires. adjustedgering(adjtet, CW); pa = org(adjtet); pb = dest(adjtet); pc = apex(adjtet); pd = oppo(adjtet); sign = insphere(pa, pb, pc, pd, bp); if (sign >= 0.0) { // Orient edge ring of n according to that of f. if (sorg(neighsh) != sdest(startsh)) sesymself(neighsh); // Collect it into CBC(p). sinfect(neighsh); sublist->append(&neighsh); } else { subceillist->append(&startsh); // Found an edge of C(p). } } } else { // Do not cross a segment. if (bpseg != (face *) NULL) { if (checkseg.sh != bpseg->sh) { subceillist->append(&startsh); // Found an edge of C(p). } } else { subceillist->append(&startsh); // Found an edge of C(p). } } senextself(startsh); } } if (b->verbose > 2) { printf(" Collect CBC(%d): %d subfaces, %d edges.\n", pointmark(bp), sublist->len(), subceillist->len()); } } /////////////////////////////////////////////////////////////////////////////// // // // formbowatcavityquad() Form BC_i(p) and B_i(p) in a quadrant. // // // // Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). // // // // BC_i(p) contains at least one tet on input. On finish, all tets collected // // in BC_i(p) are infected. B_i(p) may not closed when p is on segment or in // // facet. C(p) must be formed before this routine. Check the infect flag of // // a subface to identify the unclosed side of B_i(p). These sides will be // // closed by new subfaces of C(p)s. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formbowatcavityquad(point bp, list* tetlist, list* ceillist) { triface starttet, neightet; face checksh; point pa, pb, pc, pd; REAL sign; int i; // Form BC_i(p) and B_i(p) by a broadth-first searching. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { // Try to collect the neighbor of the face (f). tspivot(starttet, checksh); if (checksh.sh == dummysh) { // Get its neighbor n. sym(starttet, neightet); // Is n already in BC_i(p)? if (!infected(neightet)) { // For positive orientation that insphere() test requires. adjustedgering(neightet, CW); pa = org(neightet); pb = dest(neightet); pc = apex(neightet); pd = oppo(neightet); sign = insphere(pa, pb, pc, pd, bp); if (sign >= 0.0) { // Collect it into BC_i(p). infect(neightet); tetlist->append(&neightet); } else { ceillist->append(&starttet); // Found a face of B_i(p). } } } else { // Do not cross a boundary face. if (!sinfected(checksh)) { ceillist->append(&starttet); // Found a face of B_i(p). } } } } if (b->verbose > 2) { printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp), tetlist->len(), ceillist->len()); } } /////////////////////////////////////////////////////////////////////////////// // // // formbowatcavitysegquad() Form BC_i(p) and B_i(p) in a segment quadrant.// // // // Parameters: bp = p, tetlist = BC_i(p), ceillist = B_i(p). // // // // BC_i(p) contains at least one tet on input. On finish, all tets collected // // in BC_i(p) are infected. B_i(p) is not closed. C(p) must be formed before // // this routine. Check the infect flag of a subface to identify the unclosed // // sides of B_i(p). These sides will be closed by new subfaces of C(p)s. // // // // During the repair of encroaching subsegments, there may exist locally non-// // Delaunay faces. These faces are collected in BC_i(p) either. B_i(p) has // // to be formed later than BC_i(p). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formbowatcavitysegquad(point bp, list* tetlist,list* ceillist) { triface starttet, neightet, cavtet; face checksh; point pa, pb, pc, pd, pe; REAL sign; int i; // Form BC_i(p) by a broadth-first searching. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; for (starttet.loc = 0; starttet.loc < 4; starttet.loc++) { // Try to collect the neighbor of the face f. tspivot(starttet, checksh); if (checksh.sh == dummysh) { // Get its neighbor n. sym(starttet, neightet); // Is n already in BC_i(p)? if (!infected(neightet)) { // For positive orientation that insphere() test requires. adjustedgering(neightet, CW); pa = org(neightet); pb = dest(neightet); pc = apex(neightet); pd = oppo(neightet); sign = insphere(pa, pb, pc, pd, bp); if (sign >= 0.0) { // Collect it into BC_i(p). infect(neightet); tetlist->append(&neightet); } else { // Check if the face is locally non-Delaunay. pe = oppo(starttet); sign = insphere(pa, pb, pc, pd, pe); if (sign >= 0.0) { // Collect it into BC_i(p). infect(neightet); tetlist->append(&neightet); } } } } } } // Generate B_i(p). for (i = 0; i < tetlist->len(); i++) { cavtet = * (triface *)(* tetlist)[i]; for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) { tspivot(cavtet, checksh); if (checksh.sh == dummysh) { sym(cavtet, neightet); if (!infected(neightet)) { ceillist->append(&cavtet); // Found a face of B(p). } } else { // Do not cross a boundary face. if (!sinfected(checksh)) { ceillist->append(&cavtet); // Found a face of B(p). } } } } if (b->verbose > 2) { printf(" Collect BC_i(%d): %d tets, %d faces.\n", pointmark(bp), tetlist->len(), ceillist->len()); } } /////////////////////////////////////////////////////////////////////////////// // // // formbowatcavity() Form BC(p), B(p), CBC(p)s, and C(p)s. // // // // If 'bpseg'(S) != NULL, p is on segment S, else, p is on facet containing // // 'bpsh' (F). 'n' returns the number of quadrants in BC(p). 'nmax' is the // // maximum pre-allocated array length for the lists. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formbowatcavity(point bp, face* bpseg, face* bpsh, int* n, int* nmax, list** sublists, list** subceillists, list** tetlists, list** ceillists) { list *sublist; triface adjtet; face startsh, spinsh; point pa, pb; int i, j; *n = 0; if (bpseg != (face *) NULL) { // p is on segment S. bpseg->shver = 0; pa = sorg(*bpseg); pb = sdest(*bpseg); // Count the number of facets sharing at S. spivot(*bpseg, startsh); spinsh = startsh; do { (*n)++; // spinshlist->append(&spinsh); spivotself(spinsh); } while (spinsh.sh != startsh.sh); // *n is the number of quadrants around S. if (*n > *nmax) { // Reallocate arrays. Should not happen very often. delete [] tetlists; delete [] ceillists; delete [] sublists; delete [] subceillists; tetlists = new list*[*n]; ceillists = new list*[*n]; sublists = new list*[*n]; subceillists = new list*[*n]; *nmax = *n; } // Form CBC(p)s and C(p)s. spinsh = startsh; for (i = 0; i < *n; i++) { sublists[i] = new list(sizeof(face), NULL, 256); subceillists[i] = new list(sizeof(face), NULL, 256); // Set a subface f to start search. startsh = spinsh; // Let f face to the quadrant of interest (used in forming BC(p)). findedge(&startsh, pa, pb); sinfect(startsh); sublists[i]->append(&startsh); formbowatcavitysub(bp, bpseg, sublists[i], subceillists[i]); // Go to the next facet. spivotself(spinsh); } } else if (sublists != (list **) NULL) { // p is on a facet. *n = 2; // Form CBC(p) and C(p). sublists[0] = new list(sizeof(face), NULL, 256); subceillists[0] = new list(sizeof(face), NULL, 256); sinfect(*bpsh); sublists[0]->append(bpsh); formbowatcavitysub(bp, NULL, sublists[0], subceillists[0]); } else { // p is inside a tet. *n = 1; } // Form BC_i(p) and B_i(p). for (i = 0; i < *n; i++) { tetlists[i] = new list(sizeof(triface), NULL, 256); ceillists[i] = new list(sizeof(triface), NULL, 256); if (sublists != (list **) NULL) { // There are C(p)s. sublist = ((bpseg == (face *) NULL) ? sublists[0] : sublists[i]); // Add all adjacent tets of C_i(p) into BC_i(p). for (j = 0; j < sublist->len(); j++) { startsh = * (face *)(* sublist)[j]; // Adjust the side facing to the right quadrant for C(p). if ((bpseg == (face *) NULL) && (i == 1)) sesymself(startsh); stpivot(startsh, adjtet); if (adjtet.tet != dummytet) { if (!infected(adjtet)) { infect(adjtet); tetlists[i]->append(&adjtet); } } } if (bpseg != (face *) NULL) { // The quadrant is bounded by another facet. sublist = ((i < *n - 1) ? sublists[i + 1] : sublists[0]); for (j = 0; j < sublist->len(); j++) { startsh = * (face *)(* sublist)[j]; // Adjust the side facing to the right quadrant for C(p). sesymself(startsh); stpivot(startsh, adjtet); if (adjtet.tet != dummytet) { if (!infected(adjtet)) { infect(adjtet); tetlists[i]->append(&adjtet); } } } } } // It is possible that BC_i(p) is empty. if (tetlists[i]->len() == 0) continue; // Collect the rest of tets of BC_i(p) and form B_i(p). // if (b->conformdel) { // formbowatcavitysegquad(bp, tetlists[i], ceillists[i]); // } else { formbowatcavityquad(bp, tetlists[i], ceillists[i]); // } } } /////////////////////////////////////////////////////////////////////////////// // // // releasebowatcavity() Undo and free the memory allocated in routine // // formbowatcavity(). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::releasebowatcavity(face* bpseg, int n, list** sublists, list** subceillist, list** tetlists, list** ceillists) { triface oldtet; face oldsh; int i, j; if (sublists != (list **) NULL) { // Release CBC(p)s. for (i = 0; i < n; i++) { // Uninfect subfaces of CBC(p). for (j = 0; j < sublists[i]->len(); j++) { oldsh = * (face *)(* (sublists[i]))[j]; #ifdef SELF_CHECK assert(sinfected(oldsh)); #endif suninfect(oldsh); } delete sublists[i]; delete subceillist[i]; sublists[i] = (list *) NULL; subceillist[i] = (list *) NULL; if (bpseg == (face *) NULL) break; } } // Release BC(p). for (i = 0; i < n; i++) { // Uninfect tets of BC_i(p). for (j = 0; j < tetlists[i]->len(); j++) { oldtet = * (triface *)(* (tetlists[i]))[j]; #ifdef SELF_CHECK assert(infected(oldtet)); #endif uninfect(oldtet); } delete tetlists[i]; delete ceillists[i]; tetlists[i] = (list *) NULL; ceillists[i] = (list *) NULL; } } /////////////////////////////////////////////////////////////////////////////// // // // validatebowatcavityquad() Valid B_i(p). // // // // B_i(p) is valid if all faces of B_i(p) are visible by p, else B_i(p) is // // invalid. Each tet of BC_i(p) which has such a face is marked (uninfect). // // They will be removed in updatebowatcavityquad(). // // // // Return TRUE if B(p) is valid, else, return FALSE. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::validatebowatcavityquad(point bp,list* ceillist,REAL maxcosd) { triface ceiltet; point pa, pb, pc; REAL ori, cosd; int remcount, i; // Check the validate of B(p), cut tets having invisible faces. remcount = 0; for (i = 0; i < ceillist->len(); i++) { ceiltet = * (triface *)(* ceillist)[i]; if (infected(ceiltet)) { adjustedgering(ceiltet, CCW); pa = org(ceiltet); pb = dest(ceiltet); pc = apex(ceiltet); ori = orient3d(pa, pb, pc, bp); if (ori >= 0.0) { // Found an invisible face. uninfect(ceiltet); remcount++; continue; } // If a non-trival 'maxcosd' is given. if (maxcosd > -1.0) { // Get the maximal dihedral angle of tet abcp. tetalldihedral(pa, pb, pc, bp, NULL, &cosd, NULL); // Do not form the tet if the maximal dihedral angle is not reduced. if (cosd < maxcosd) { uninfect(ceiltet); remcount++; } } } } return remcount == 0; } /////////////////////////////////////////////////////////////////////////////// // // // updatebowatcavityquad() Update BC_i(p) and reform B_i(p). // // // // B_i(p) is invalid and some tets in BC_i(p) have been marked to be removed // // in validatebowatcavityquad(). This routine actually remove the cut tets // // of BC_i(p) and re-form the B_i(p). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::updatebowatcavityquad(list* tetlist, list* ceillist) { triface cavtet, neightet; face checksh; int remcount, i; remcount = 0; for (i = 0; i < tetlist->len(); i++) { cavtet = * (triface *)(* tetlist)[i]; if (!infected(cavtet)) { tetlist->del(i, 1); remcount++; i--; } } // Are there tets have been cut in BC_i(p)? if (remcount > 0) { // Re-form B_i(p). ceillist->clear(); for (i = 0; i < tetlist->len(); i++) { cavtet = * (triface *)(* tetlist)[i]; for (cavtet.loc = 0; cavtet.loc < 4; cavtet.loc++) { tspivot(cavtet, checksh); if (checksh.sh == dummysh) { sym(cavtet, neightet); if (!infected(neightet)) { ceillist->append(&cavtet); // Found a face of B_i(p). } } else { // Do not cross a boundary face. if (!sinfected(checksh)) { ceillist->append(&cavtet); // Found a face of B_i(p). } } } } if (b->verbose > 2) { printf(" Update BC_i(p): %d tets, %d faces.\n", tetlist->len(), ceillist->len()); } } } /////////////////////////////////////////////////////////////////////////////// // // // updatebowatcavitysub() Check and update CBC(p) and C(p). // // // // A CBC(p) is valid if all its subfaces are inside or on the hull of BC(p). // // A subface s of CBC(p) is invalid if it is in one of the two cases: // // (1) s is completely outside BC(p); // // (2) s has two adjacent tets but only one of them is in BC(p); // // s is removed from CBC(p) if it is invalid. If there is an adjacent tet of // // s which is in BC(p), it gets removed from BC(p) too. If CBC(p) is updated,// // C(p) is re-formed. // // // // A C(p) is valid if all its edges are on the hull of BC(p). An edge e of // // C(p) may be inside BC(p) if e is a segment and belongs to only one facet. // // To correct C(p), a tet of BC(p) which shields e gets removed. // // // // If BC(p) is formed with locally non-Delaunay check (b->conformdel > 0). // // A boundary-consistent check is needed for non-segment edges of C(p). Let // // e be such an edge, the subface f contains e and outside C(p) may belong // // to B(p) due to the non-coplanarity of the facet definition. The tet of // // BC(p) containing f gets removed to avoid creating a degenerate new tet. // // // // 'cutcount' accumulates the total number of cuttets(not only by this call).// // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::updatebowatcavitysub(list* sublist, list* subceillist, int* cutcount) { triface adjtet, rotface; face checksh, neighsh; face checkseg; point pa, pb, pc; REAL ori1, ori2; int remcount; int i, j; remcount = 0; // Check the validity of CBC(p). for (i = 0; i < sublist->len(); i++) { checksh = * (face *)(* sublist)[i]; // Check two adjacent tets of s. for (j = 0; j < 2; j++) { stpivot(checksh, adjtet); if (adjtet.tet != dummytet) { if (!infected(adjtet)) { // Could be either case (1) or (2). suninfect(checksh); // s survives. // If the sym. adjtet exists, it should remove from BC(p) too. sesymself(checksh); stpivot(checksh, adjtet); if (adjtet.tet != dummytet) { if (infected(adjtet)) { // Found an adj. tet in BC(p), remove it. uninfect(adjtet); (*cutcount)++; } } // Remove s from C(p). sublist->del(i, 1); i--; remcount++; break; } } sesymself(checksh); } } if (remcount > 0) { // Some subfaces have been removed from the cavity. if (checkpbcs) { // Check if the facet has a PBC defined. checksh = * (face *)(* sublist)[0]; if (shellpbcgroup(checksh) >= 0) { // Yes, A PBC facet. Remove all subfaces -- Do not insert the point. for (i = 0; i < sublist->len(); i++) { checksh = * (face *)(* sublist)[i]; suninfect(checksh); // Remove both side tets from the cavity. for (j = 0; j < 2; j++) { stpivot(checksh, adjtet); if (adjtet.tet != dummytet) { if (infected(adjtet)) { uninfect(adjtet); (*cutcount)++; } } sesymself(checksh); } } remcount += sublist->len(); sublist->clear(); } } if (b->verbose > 2) { printf(" Removed %d subfaces from CBC(p).\n", remcount); } // Re-generate C(p). subceillist->clear(); for (i = 0; i < sublist->len(); i++) { checksh = * (face *)(* sublist)[i]; for (j = 0; j < 3; j++) { spivot(checksh, neighsh); if (!sinfected(neighsh)) { subceillist->append(&checksh); } senextself(checksh); } } if (b->verbose > 2) { printf(" Update CBC(p): %d subs, %d edges.\n", sublist->len(), subceillist->len()); } } // Check the validity of C(p). for (i = 0; i < subceillist->len(); i++) { checksh = * (face *)(* subceillist)[i]; sspivot(checksh, checkseg); if (checkseg.sh != dummysh) { // A segment. Check if it is inside BC(p). stpivot(checksh, adjtet); if (adjtet.tet == dummytet) { sesym(checksh, neighsh); stpivot(neighsh, adjtet); } findedge(&adjtet, sorg(checkseg), sdest(checkseg)); adjustedgering(adjtet, CCW); fnext(adjtet, rotface); // It's the same tet. // Rotate rotface (f), stop on either of the following cases: // (a) meet a subface, or // (b) enter an uninfected tet, or // (c) rewind back to adjtet. do { if (!infected(rotface)) break; // case (b) tspivot(rotface, neighsh); if (neighsh.sh != dummysh) break; // case (a) // Go to the next tet of the facing ring. fnextself(rotface); } while (apex(rotface) != apex(adjtet)); // Is it case (c)? if (apex(rotface) == apex(adjtet)) { // The segment is enclosed by BC(p), invalid cavity. pa = org(adjtet); pb = dest(adjtet); pc = apex(adjtet); // Find the shield tet and cut it. Notice that the shield tet may // not be unique when there are four coplanar points, ie., // ori1 * ori2 == 0.0. In such case, choose either of them. fnext(adjtet, rotface); do { fnextself(rotface); assert(infected(rotface)); ori1 = orient3d(pa, pb, pc, apex(rotface)); ori2 = orient3d(pa, pb, pc, oppo(rotface)); } while (ori1 * ori2 > 0.0); // Cut this tet from BC(p). uninfect(rotface); (*cutcount)++; } } else { /*// An edge. Check if boundary-consistency should be enforced. if (b->conformdel > 0) { // Get the adj-sub n at e, it must be outside C(p). spivot(checksh, neighsh); assert(!sinfected(neighsh)); // Check if n is on B(p). for (j = 0; j < 2; j++) { stpivot(neighsh, adjtet); if (adjtet.tet != dummytet) { if (infected(adjtet)) { uninfect(adjtet); (*cutcount)++; } } sesymself(neighsh); } } */ } } } /////////////////////////////////////////////////////////////////////////////// // // // trimbowatcavity() Validate B(p), CBC(p)s and C(p)s, update BC(p). // // // // A B(p) is valid if all its faces are visible by p. If a face f of B(p) is // // found invisible by p, the tet of BC(p) containing f gets removed and B(p) // // is refromed. The new B(p) may still contain invisible faces by p. Iterat- // // ively do the above procedure until B(p) is satisfied. // // // // A CBC(p) is valid if each subface of CBC(p) is either on the hull of BC(p)// // or completely inside BC(p). If a subface s of CBC(p) is not valid, it is // // removed from CBC(p) and C(p) is reformed. If there exists a tet t of BC(p)// // containg s, t is removed from BC(p). The process for validating BC(p) and // // B(p) is re-excuted. // // // // A C(p) is valid if each edge of C(p) is on the hull of BC(p). If an edge // // e of C(p) is invalid (e should be a subsegment which only belong to one // // facet), a tet of BC(p) which contains e and has two other faces shielding // // e is removed. The process for validating BC(p) and B(p) is re-excuted. // // // // If either BC(p) or CBC(p) becomes empty. No valid BC(p) is found, return // // FALSE. else, return TRUE. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::trimbowatcavity(point bp, face* bpseg, int n, list** sublists, list** subceillists, list** tetlists, list** ceillists, REAL maxcosd) { bool valflag; int oldnum, cutnum, cutcount; int i; cutnum = 0; // Count the total number of cut-off tets of BC(p). valflag = true; do { // Validate BC(p), B(p). for (i = 0; i < n && valflag; i++) { oldnum = tetlists[i]->len(); // Iteratively validate BC_i(p) and B_i(p). while (!validatebowatcavityquad(bp, ceillists[i], maxcosd)) { // Update BC_i(p) and B_i(p). updatebowatcavityquad(tetlists[i], ceillists[i]); valflag = tetlists[i]->len() > 0; } cutnum += (oldnum - tetlists[i]->len()); } if (valflag && (sublists != (list **) NULL)) { // Validate CBC(p), C(p). cutcount = 0; for (i = 0; i < n; i++) { updatebowatcavitysub(sublists[i], subceillists[i], &cutcount); // Only do once if p is on a facet. if (bpseg == (face *) NULL) break; } // Are there cut tets? if (cutcount > 0) { // Squeeze all cut tets in BC(p), keep valflag once it gets FLASE. for (i = 0; i < n; i++) { if (tetlists[i]->len() > 0) { updatebowatcavityquad(tetlists[i], ceillists[i]); if (valflag) { valflag = tetlists[i]->len() > 0; } } } cutnum += cutcount; // Go back to valid the updated BC(p). continue; } } break; // Leave the while-loop. } while (true); // Check if any CBC(p) becomes non-empty. if (valflag && (sublists != (list **) NULL)) { for (i = 0; i < n && valflag; i++) { valflag = (sublists[i]->len() > 0); if (bpseg == (face *) NULL) break; } } if (valflag && (cutnum > 0)) { // Accumulate counters. if (bpseg != (face *) NULL) { updsegcount++; } else if (sublists != (list **) NULL) { updsubcount++; } else { updvolcount++; } } if (!valflag) { // Accumulate counters. if (bpseg != (face *) NULL) { failsegcount++; } else if (sublists != (list **) NULL) { failsubcount++; } else { failvolcount++; } } return valflag; } /////////////////////////////////////////////////////////////////////////////// // // // bowatinsertsite() Insert a point using the Bowyer-Watson method. // // // // Parameters: 'bp' = p, 'splitseg' = S, 'n' = the number of quadrants, // // 'sublists', an array of CBC_i(p)s, 'subceillists', an array of C_i(p)s, // // 'tetlists', an array of BC_i(p)s, 'ceillists', an array of B_i(p)s. // // // // If p is inside the mesh domain, then S = NULL, n = 1, CBC(p) and C(p) are // // NULLs. 'tetlists[0]' = BC(p), 'ceillists[0]' = B(p). // // If p is on a facet F, then S = NULL, n = 2, and 'subceillists[0]' = C(p), // // 'subceillists[1]' is not needed (set it to NULL). B_1(p) and B_2(p) are // // in 'ceillists[0]' and 'ceillists[1]'. // // If p is on a segment S, then F(S) is a list of subfaces around S, and n = // // len(F(S)), there are n C_i(p)s and B_i(p)s supplied in 'subceillists[i]'// // and 'ceillists[i]'. // // // // If 'verlist' != NULL, it returns a list of vertices which connect to p. // // This vertices are used for interpolating size of p. // // // // If 'flipque' != NULL, it returns a list of internal faces of new tets in // // BC(p), faces on C(p)s are excluded. These faces may be locally non- // // Delaunay and will be flipped if they are flippable. Such non-Delaunay // // faces may exist when p is inserted to split an encroaching segment. // // // // 'chkencseg', 'chkencsub', and 'chkbadtet' are flags that indicate whether // // or not there should be checks for the creation of encroached subsegments, // // subfaces, or bad quality tets. If 'chkencseg' = TRUE, the encroached sub- // // segments are added to the list of subsegments to be split. // // // // On return, 'ceillists' returns Star(p). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::bowatinsertsite(point bp,face* splitseg,int n,list** sublists, list** subceillists, list** tetlists, list** ceillists, list* verlist, queue* flipque, bool chkencseg, bool chkencsub, bool chkbadtet) { list *ceillist, *subceillist; triface oldtet, newtet, newface, rotface, neightet; face oldsh, newsh, newedge, checksh; face spinsh, casingin, casingout; face *apsegshs, *pbsegshs; face apseg, pbseg, checkseg; point pa, pb, pc; REAL attrib, volume; int idx, i, j, k; if (b->verbose > 1) { printf(" Insert point %d (%.12g, %.12g, %.12g)", pointmark(bp), bp[0], bp[1], bp[2]); } if (splitseg != (face *) NULL) { if (b->verbose > 1) { printf(" on segment.\n"); } bowatsegcount++; } else { if (subceillists != (list **) NULL) { if (b->verbose > 1) { printf(" on facet.\n"); } bowatsubcount++; } else { if (b->verbose > 1) { printf(" in volume.\n"); } bowatvolcount++; } } // Create new tets to fill B(p). for (k = 0; k < n; k++) { // Create new tets from each B_i(p). ceillist = ceillists[k]; for (i = 0; i < ceillist->len(); i++) { oldtet = * (triface *)(* ceillist)[i]; adjustedgering(oldtet, CCW); pa = org(oldtet); pb = dest(oldtet); pc = apex(oldtet); maketetrahedron(&newtet); setorg(newtet, pa); setdest(newtet, pb); setapex(newtet, pc); setoppo(newtet, bp); for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(oldtet.tet, j); setelemattribute(newtet.tet, j, attrib); } if (b->varvolume) { volume = volumebound(oldtet.tet); if (volume > 0.0) { if (!b->fixedvolume && b->refine) { // '-r -a' switches and a .vol file case. Enlarge the maximum // volume constraint for the new tets. Hence the new points // only spread near the original constrained tet. volume *= 1.2; } } setvolumebound(newtet.tet, volume); } sym(oldtet, neightet); tspivot(oldtet, checksh); if (neightet.tet != dummytet) { bond(newtet, neightet); } if (checksh.sh != dummysh) { tsbond(newtet, checksh); } if (verlist != (list *) NULL) { // Collect vertices connecting to p. idx = pointmark(pa); if (idx >= 0) { setpointmark(pa, -idx - 1); verlist->append(&pa); } idx = pointmark(pb); if (idx >= 0) { setpointmark(pb, -idx - 1); verlist->append(&pb); } idx = pointmark(pc); if (idx >= 0) { setpointmark(pc, -idx - 1); verlist->append(&pc); } } // Replace the tet by the newtet for checking the quality. * (triface *)(* ceillist)[i] = newtet; } } if (verlist != (list *) NULL) { // Uninfect collected vertices. for (i = 0; i < verlist->len(); i++) { pa = * (point *)(* verlist)[i]; idx = pointmark(pa); setpointmark(pa, -(idx + 1)); } } // Connect new tets of B(p). Not all faces of new tets can be connected, // e.g., if there are empty B_i(p)s. for (k = 0; k < n; k++) { ceillist = ceillists[k]; for (i = 0; i < ceillist->len(); i++) { newtet = * (triface *)(* ceillist)[i]; newtet.ver = 0; for (j = 0; j < 3; j++) { fnext(newtet, newface); sym(newface, neightet); if (neightet.tet == dummytet) { // Find the neighbor face by rotating the faces at edge ab. esym(newtet, rotface); pa = org(rotface); pb = dest(rotface); while (fnextself(rotface)); // Do we meet a boundary face? tspivot(rotface, checksh); if (checksh.sh != dummysh) { // Walk through the boundary and continue to rotate faces. do { findedge(&checksh, pa, pb); sfnextself(checksh); assert((sorg(checksh) == pa) && (sdest(checksh) == pb)); stpivot(checksh, rotface); if (infected(rotface)) { // Meet an old tet of B_i(p). This side is on the hull and // will be connected to a new subface created in C(p). break; } findedge(&rotface, pa, pb); while (fnextself(rotface)); tspivot(rotface, checksh); } while (checksh.sh != dummysh); } // The rotface has edge ab, but it may not have newpt. if (apex(rotface) == apex(newface)) { // Bond the two tets together. bond(newface, rotface); // Queue (uniquely) this face if 'flipque' is given. if (flipque != (queue *) NULL) { enqueueflipface(newface, flipque); } } } enextself(newtet); } } } if (subceillists != (list **) NULL) { // There are C(p)s. if (splitseg != (face *) NULL) { // S (ab) is split by p. splitseg->shver = 0; pa = sorg(*splitseg); pb = sdest(*splitseg); // Allcate two arrays for saving the subface rings of the two new // segments a->p and p->b. apsegshs = new face[n]; pbsegshs = new face[n]; } // For each C_k(p), do the following: // (1) Create new subfaces to fill C_k(p), insert them into B(p); // (2) Connect new subfaces to each other; for (k = 0; k < n; k++) { subceillist = subceillists[k]; // Check if 'hullsize' should be updated. oldsh = * (face *)(* subceillist)[0]; stpivot(oldsh, neightet); if (neightet.tet != dummytet) { sesymself(oldsh); stpivot(oldsh, neightet); } if (neightet.tet == dummytet) { // The hull size changes. hullsize += (subceillist->len() - sublists[k]->len()); } // (1) Create new subfaces to fill C_k(p), insert them into B(p). for (i = 0; i < subceillist->len(); i++) { oldsh = * (face *)(* subceillist)[i]; makeshellface(subfaces, &newsh); setsorg(newsh, sorg(oldsh)); setsdest(newsh, sdest(oldsh)); setsapex(newsh, bp); if (b->quality && varconstraint) { setareabound(newsh, areabound(oldsh)); } setshellmark(newsh, shellmark(oldsh)); setshelltype(newsh, shelltype(oldsh)); if (checkpbcs) { setshellpbcgroup(newsh, shellpbcgroup(oldsh)); } // Replace oldsh by newsh at the edge. spivot(oldsh, casingout); sspivot(oldsh, checkseg); if (checkseg.sh != dummysh) { // A segment. Insert s into the face ring, ie, s_in -> s -> s_out. if (casingout.sh != dummysh) { // if (oldsh.sh != casingout.sh) { // s is not bonded to itself. spinsh = casingout; do { casingin = spinsh; spivotself(spinsh); } while (sapex(spinsh) != sapex(oldsh)); assert(casingin.sh != oldsh.sh); // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out). sbond1(casingin, newsh); sbond1(newsh, casingout); } else { // Bond newsh -> newsh. sdissolve(newsh); // sbond(newsh, newsh); } // Bond the segment. ssbond(newsh, checkseg); } else { // Bond s <-> s_out (and dissolve s_out -> s_old). sbond(newsh, casingout); } // Insert newsh into B(p). Use the coonections of oldsh. stpivot(oldsh, neightet); if (neightet.tet == dummytet) { sesymself(oldsh); sesymself(newsh); // Keep the same orientation as oldsh. stpivot(oldsh, neightet); } assert(infected(neightet)); // Set on the rotating edge. findedge(&neightet, sorg(oldsh), sdest(oldsh)); // Choose the rotating direction (to the inside of B(p)). adjustedgering(neightet, CCW); rotface = neightet; // Rotate face. Stop at a non-infected tet t (not in B(p)) or a // hull face f (on B(p)). Get the neighbor n of t or f. n is // a new tet that has just been created to fill B(p). do { fnextself(rotface); sym(rotface, neightet); if (neightet.tet == dummytet) { tspivot(rotface, checksh); assert(checksh.sh != dummysh); stpivot(checksh, newtet); break; } else if (!infected(neightet)) { sym(neightet, newtet); break; } } while (true); assert(newtet.tet != rotface.tet); // Set the rotating edge of n. findedge(&newtet, sorg(oldsh), sdest(oldsh)); // Choose the rotating direction (to the inside of B(p)). adjustedgering(newtet, CCW); fnext(newtet, newface); assert(apex(newface) == bp); // newsh has already been oriented toward n. tsbond(newface, newsh); sym(newface, neightet); // 'neightet' maybe outside. sesymself(newsh); tsbond(neightet, newsh); // Bond them anyway. // Replace oldsh by newsh in list. * (face *)(* subceillist)[i] = newsh; } // (2) Connect new subfaces to each other. for (i = 0; i < subceillist->len(); i++) { // Get a face cdp. newsh = * (face *)(* subceillist)[i]; // Get a new tet containing cdp. stpivot(newsh, newtet); if (newtet.tet == dummytet) { sesymself(newsh); stpivot(newsh, newtet); } for (j = 0; j < 2; j++) { if (j == 0) { senext(newsh, newedge); // edge dp. } else { senext2(newsh, newedge); // edge pc. sesymself(newedge); // edge cp. } if (splitseg != (face *) NULL) { // Don not operate on newedge if it is ap or pb. if (sorg(newedge) == pa) { apsegshs[k] = newedge; continue; } else if (sorg(newedge) == pb) { pbsegshs[k] = newedge; continue; } } // There should no segment inside the cavity. Check it. sspivot(newedge, checkseg); assert(checkseg.sh == dummysh); spivot(newedge, casingout); if (casingout.sh == dummysh) { rotface = newtet; findedge(&rotface, sorg(newedge), sdest(newedge)); // Rotate newtet until meeting a new subface which contains // newedge. It must exist since newedge is not a seg. adjustedgering(rotface, CCW); do { fnextself(rotface); tspivot(rotface, checksh); if (checksh.sh != dummysh) break; } while (true); findedge(&checksh, sorg(newedge), sdest(newedge)); sbond(newedge, checksh); } } } // Only do once if p is on a facet. if (splitseg == (face *) NULL) break; } // for (k = 0; k < n; k++) if (splitseg != (face *) NULL) { // Update a->b to be a->p. apseg = *splitseg; setsdest(apseg, bp); // Create a new subsegment p->b. makeshellface(subsegs, &pbseg); setsorg(pbseg, bp); setsdest(pbseg, pb); // p->b gets the same mark and segment type as a->p. setshellmark(pbseg, shellmark(apseg)); setshelltype(pbseg, shelltype(apseg)); if (b->quality && varconstraint) { // Copy the area bound into the new subsegment. setareabound(pbseg, areabound(apseg)); } senext(apseg, checkseg); // Get the old connection at b of a->b. spivot(checkseg, casingout); // Bond a->p and p->b together. senext2(pbseg, casingin); sbond(casingin, checkseg); if (casingout.sh != dummysh) { // There is a subsegment connect at b of p->b. casingout.shver = 0; #ifdef SELF_CHECK assert(sorg(casingout) == pb); #endif senext2self(casingout); senext(pbseg, casingin); sbond(casingin, casingout); } // Bond all new subfaces to a->p and p->b. for (i = 0; i < n; i++) { spinsh = apsegshs[i]; findedge(&spinsh, pa, bp); ssbond(spinsh, apseg); spinsh = pbsegshs[i]; findedge(&spinsh, bp, pb); ssbond(spinsh, pbseg); } // Bond all subfaces share at a->p together. for (i = 0; i < n; i++) { spinsh = apsegshs[i]; if (i < (n - 1)) { casingout = apsegshs[i + 1]; } else { casingout = apsegshs[0]; } sbond1(spinsh, casingout); } // Bond all subfaces share at p->b together. for (i = 0; i < n; i++) { spinsh = pbsegshs[i]; if (i < (n - 1)) { casingout = pbsegshs[i + 1]; } else { casingout = pbsegshs[0]; } sbond1(spinsh, casingout); } delete [] apsegshs; delete [] pbsegshs; // Check for newly encroached subsegments if the flag is set. if (chkencseg) { // Check if a->p and p->b are encroached by other vertices. checkseg4encroach(&apseg, NULL, NULL, true); checkseg4encroach(&pbseg, NULL, NULL, true); // Check if the adjacent segments are encroached by p. tallencsegs(bp, n, ceillists); } } // if (splitseg != (face *) NULL) // Delete subfaces of old CBC_i(p)s. for (k = 0; k < n; k++) { for (i = 0; i < sublists[k]->len(); i++) { oldsh = * (face *)(* (sublists[k]))[i]; shellfacedealloc(subfaces, oldsh.sh); } // Clear the list so that the subs will not get unmarked later in // routine releasebowatcavity() which only frees the memory. sublists[k]->clear(); // Only do once if p is on a facet. if (splitseg == (face *) NULL) break; } // Check for newly encroached subfaces if the flag is set. if (chkencsub) { // Check if new subfaces of C_i(p) are encroached by other vertices. for (k = 0; k < n; k++) { subceillist = subceillists[k]; for (i = 0; i < subceillist->len(); i++) { newsh = * (face *)(* subceillist)[i]; checksub4encroach(&newsh, NULL, true); } // Only do once if p is on a facet. if (splitseg == (face *) NULL) break; } // Check if the adjacent subfaces are encroached by p. tallencsubs(bp, n, ceillists); } } // if (subceillists != (list **) NULL) // Delete tets of old BC_i(p)s. for (k = 0; k < n; k++) { for (i = 0; i < tetlists[k]->len(); i++) { oldtet = * (triface *)(* (tetlists[k]))[i]; tetrahedrondealloc(oldtet.tet); } // Clear the list so that the tets will not get unmarked later in // routine releasebowatcavity() which only frees the memory. tetlists[k]->clear(); } // check for bad quality tets if the flags is set. if (chkbadtet) { for (k = 0; k < n; k++) { ceillist = ceillists[k]; for (i = 0; i < ceillist->len(); i++) { newtet = * (triface *)(* ceillist)[i]; checktet4badqual(&newtet, true); } } } if (flipque != (queue *) NULL) { // Newly created internal faces of BC(p) (excluding faces on C(p)s) are // in 'flipque'. Some of these faces may be locally non-Delaunay due // to the existence of non-constrained tets. check and fix them. lawson3d(flipque); } } //// //// //// //// //// flip_cxx ///////////////////////////////////////////////////////////////// //// delaunay_cxx ///////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // insertvertexbw() Insert a vertex using the Boywer-Watson algorithm. // // // // The point p will be first located in T. 'searchtet' is a suggested start- // // tetrahedron, it can be NULL. Note that p may lies outside T. In such case,// // the convex hull of T will be updated to include p as a vertex. // // // // If 'bwflag' is TRUE, the Bowyer-Watson algorithm is used to recover the // // Delaunayness of T. Otherwise, do nothing with regard to the Delaunayness // // T (T may be non-Delaunay after this function). // // // // If 'visflag' is TRUE, force to check the visibility of the boundary faces // // of cavity. This is needed when T is not Delaunay. // // // // If 'noencflag' is TRUE, only insert the new point p if it does not cause // // any existing (sub)segment be non-Delaunay. This option only is checked // // when the global variable 'checksubsegs' is set. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::insertvertexbw(point insertpt, triface *searchtet, bool bwflag, bool visflag, bool noencsegflag, bool noencsubflag) { triface neightet, spintet, newtet, neineitet; triface *cavetet, *parytet, *parytet1; face checksh, *pssub; face checkseg, *paryseg; point pa, pb, pc, *ppt; enum locateresult loc; REAL attrib, volume; REAL sign, ori; long tetcount; bool enqflag; int hitbdry; int i, j; arraypool *swaplist; // for updating cavity. long updatecount; if (b->verbose > 1) { printf(" Insert point %d\n", pointmark(insertpt)); } tetcount = ptloc_count; updatecount = 0; /*if (searchtet->tet == NULL) { randomsample(insertpt, searchtet); } loc = locate2(insertpt, searchtet); */ if (searchtet->tet == NULL) { loc = locate(insertpt, searchtet); } else { loc = locate2(insertpt, searchtet, NULL); } if (b->verbose > 1) { printf(" Walk distance (# tets): %ld\n", ptloc_count - tetcount); } if (ptloc_max_count < (ptloc_count - tetcount)) { ptloc_max_count = (ptloc_count - tetcount); } if (b->verbose > 1) { printf(" Located (%d) tet (%d, %d, %d, %d).\n", (int) loc, pointmark(org(*searchtet)), pointmark(dest(*searchtet)), pointmark(apex(*searchtet)), pointmark(oppo(*searchtet))); } if (loc == ONVERTEX) { // The point already exists. Mark it and do nothing on it. if (b->object != tetgenbehavior::STL) { if (!b->quiet) { printf("Warning: Point #%d is duplicated with Point #%d. Ignored!\n", pointmark(insertpt), pointmark(org(*searchtet))); } } setpoint2ppt(insertpt, org(*searchtet)); setpointtype(insertpt, DUPLICATEDVERTEX); dupverts++; return loc; } tetcount = 0l; // The number of deallocated tets. // Create the initial boundary of the cavity. if (loc == INTETRAHEDRON) { // Add four boundary faces of this tet into list. neightet.tet = searchtet->tet; for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { cavetetlist->newindex((void **) &parytet); *parytet = neightet; } infect(*searchtet); caveoldtetlist->newindex((void **) &parytet); *parytet = *searchtet; tetcount++; flip14count++; } else if (loc == ONFACE) { // Add at most six boundary faces into list. neightet.tet = searchtet->tet; for (i = 0; i < 3; i++) { neightet.loc = locpivot[searchtet->loc][i]; cavetetlist->newindex((void **) &parytet); *parytet = neightet; } infect(*searchtet); caveoldtetlist->newindex((void **) &parytet); *parytet = *searchtet; tetcount++; decode(searchtet->tet[searchtet->loc], spintet); if (spintet.tet != dummytet) { neightet.tet = spintet.tet; for (i = 0; i < 3; i++) { neightet.loc = locpivot[spintet.loc][i]; cavetetlist->newindex((void **) &parytet); *parytet = neightet; } infect(spintet); caveoldtetlist->newindex((void **) &parytet); *parytet = spintet; tetcount++; } else { // Split a hull face into three hull faces. hullsize += 2; } flip26count++; } else if (loc == ONEDGE) { // Add all adjacent boundary tets into list. spintet = *searchtet; pc = apex(spintet); hitbdry = 0; do { tetcount++; neightet.tet = spintet.tet; neightet.loc = locverpivot[spintet.loc][spintet.ver][0]; cavetetlist->newindex((void **) &parytet); *parytet = neightet; neightet.loc = locverpivot[spintet.loc][spintet.ver][1]; cavetetlist->newindex((void **) &parytet); *parytet = neightet; infect(spintet); caveoldtetlist->newindex((void **) &parytet); *parytet = spintet; // Go to the next tet (may be dummytet). tfnext(spintet, neightet); if (neightet.tet == dummytet) { hitbdry++; if (hitbdry == 2) break; esym(*searchtet, spintet); // Go to another direction. tfnext(spintet, neightet); if (neightet.tet == dummytet) break; } spintet = neightet; } while (apex(spintet) != pc); // Update hull size if it is a hull edge. if (hitbdry > 0) { // Split a hull edge deletes two hull faces, adds four new hull faces. hullsize += 2; } flipn2ncount++; } else if (loc == OUTSIDE) { // p lies outside the convex hull. Enlarge the convex hull by including p. if (b->verbose > 1) { printf(" Insert a hull vertex.\n"); } // 'searchtet' refers to a hull face which is visible by p. adjustedgering(*searchtet, CW); // Create the first tet t (from f and p). maketetrahedron(&newtet); setorg (newtet, org(*searchtet)); setdest(newtet, dest(*searchtet)); setapex(newtet, apex(*searchtet)); setoppo(newtet, insertpt); for (i = 0; i < in->numberoftetrahedronattributes; i++) { attrib = elemattribute(searchtet->tet, i); setelemattribute(newtet.tet, i, attrib); } if (b->varvolume) { volume = volumebound(searchtet->tet); setvolumebound(newtet.tet, volume); } // Connect t to T. bond(newtet, *searchtet); // Removed a hull face, added three "new hull faces". hullsize += 2; // Add a cavity boundary face. cavetetlist->newindex((void **) &parytet); *parytet = newtet; // Add a cavity tet. infect(newtet); caveoldtetlist->newindex((void **) &parytet); *parytet = newtet; tetcount++; // Add three "new hull faces" into list (re-use cavebdrylist). newtet.ver = 0; for (i = 0; i < 3; i++) { fnext(newtet, neightet); cavebdrylist->newindex((void **) &parytet); *parytet = neightet; enextself(newtet); } // Find all actual new hull faces. for (i = 0; i < (int) cavebdrylist->objects; i++) { // Get a queued "new hull face". parytet = (triface *) fastlookup(cavebdrylist, i); // Every "new hull face" must have p as its apex. assert(apex(*parytet) == insertpt); assert((parytet->ver & 1) == 1); // It's CW edge ring. // Check if it is still a hull face. sym(*parytet, neightet); if (neightet.tet == dummytet) { // Yes, get its adjacent hull face (at its edge). esym(*parytet, neightet); while (1) { fnextself(neightet); // Does its adjacent tet exist? sym(neightet, neineitet); if (neineitet.tet == dummytet) break; symedgeself(neightet); } // neightet is an adjacent hull face. pc = apex(neightet); if (pc != insertpt) { // Check if p is visible by the hull face ('neightet'). pa = org(neightet); pb = dest(neightet); ori = orient3d(pa, pb, pc, insertpt); orient3dcount++; if (ori < 0) { // Create a new tet adjacent to neightet. maketetrahedron(&newtet); setorg (newtet, pa); setdest(newtet, pb); setapex(newtet, pc); setoppo(newtet, insertpt); for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(neightet.tet, j); setelemattribute(newtet.tet, j, attrib); } if (b->varvolume) { volume = volumebound(neightet.tet); setvolumebound(newtet.tet, volume); } bond(newtet, neightet); fnext(newtet, neineitet); bond(neineitet, *parytet); // Comment: We removed two hull faces, and added two "new hull // faces", hence hullsize remains unchanged. // Add a cavity boundary face. cavetetlist->newindex((void **) &parytet1); *parytet1 = newtet; // Add a cavity tet. infect(newtet); caveoldtetlist->newindex((void **) &parytet1); *parytet1 = newtet; tetcount++; // Add two "new hull faces" into list. enextself(newtet); for (j = 0; j < 2; j++) { fnext(newtet, neineitet); cavebdrylist->newindex((void **) &parytet1); *parytet1 = neineitet; enextself(newtet); } } } else { // Two hull faces matched. Bond the two adjacent tets. bond(*parytet, neightet); hullsize -= 2; } } // if (neightet.tet == dummytet) } // i cavebdrylist->restart(); inserthullcount++; } if (!bwflag) return loc; // Form the Boywer-Watson cavity. for (i = 0; i < (int) cavetetlist->objects; i++) { // Get a cavity boundary face. parytet = (triface *) fastlookup(cavetetlist, i); assert(parytet->tet != dummytet); assert(infected(*parytet)); // The tet is inside the cavity. enqflag = false; // Get the adjacent tet. sym(*parytet, neightet); if (neightet.tet != dummytet) { if (!infected(neightet)) { if (!marktested(neightet)) { ppt = (point *) &(neightet.tet[4]); sign = insphere_s(ppt[0], ppt[1], ppt[2], ppt[3], insertpt); enqflag = (sign < 0.0); // Avoid redundant insphere tests. marktest(neightet); } } else { enqflag = true; } } if (enqflag) { // Found a tet in the cavity. if (!infected(neightet)) { // Avoid to add it multiple times. // Put other three faces in check list. neineitet.tet = neightet.tet; for (j = 0; j < 3; j++) { neineitet.loc = locpivot[neightet.loc][j]; cavetetlist->newindex((void **) &parytet1); *parytet1 = neineitet; } infect(neightet); caveoldtetlist->newindex((void **) &parytet1); *parytet1 = neightet; tetcount++; } } else { // Found a boundary face of the cavity. if (neightet.tet == dummytet) { // Check for a possible flat tet (see m27.node, use -J option). pa = org(*parytet); pb = dest(*parytet); pc = apex(*parytet); ori = orient3d(pa, pb, pc, insertpt); if (ori != 0) { cavebdrylist->newindex((void **) &parytet1); *parytet1 = *parytet; // futureflip = flippush(futureflip, parytet, insertpt); } } else { cavebdrylist->newindex((void **) &parytet1); *parytet1 = *parytet; } } } // i if (b->verbose > 1) { printf(" Cavity formed: %ld tets, %ld faces.\n", tetcount, cavebdrylist->objects); } totaldeadtets += tetcount; totalbowatcavsize += cavebdrylist->objects; if (maxbowatcavsize < (long) cavebdrylist->objects) { maxbowatcavsize = cavebdrylist->objects; } if (checksubsegs || noencsegflag) { // Check if some (sub)segments are inside the cavity. for (i = 0; i < (int) caveoldtetlist->objects; i++) { parytet = (triface *) fastlookup(caveoldtetlist, i); for (j = 0; j < 6; j++) { parytet->loc = edge2locver[j][0]; parytet->ver = edge2locver[j][1]; tsspivot1(*parytet, checkseg); if ((checkseg.sh != dummysh) && !sinfected(checkseg)) { // Check if this segment is inside the cavity. spintet = *parytet; pa = apex(spintet); enqflag = true; hitbdry = 0; while (1) { tfnextself(spintet); if (spintet.tet == dummytet) { hitbdry++; if (hitbdry == 2) break; esym(*parytet, spintet); tfnextself(spintet); if (spintet.tet == dummytet) break; } if (!infected(spintet)) { enqflag = false; break; // It is not inside. } if (apex(spintet) == pa) break; } if (enqflag) { if (b->verbose > 1) { printf(" Queue a missing segment (%d, %d).\n", pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); } sinfect(checkseg); // Only save it once. subsegstack->newindex((void **) &paryseg); *paryseg = checkseg; } } } } } if (noencsegflag && (subsegstack->objects > 0)) { // Found encroached subsegments! Do not insert this point. for (i = 0; i < (int) caveoldtetlist->objects; i++) { parytet = (triface *) fastlookup(caveoldtetlist, i); uninfect(*parytet); unmarktest(*parytet); } // Unmark cavity neighbor tets (outside the cavity). for (i = 0; i < (int) cavebdrylist->objects; i++) { parytet = (triface *) fastlookup(cavebdrylist, i); sym(*parytet, neightet); if (neightet.tet != dummytet) { unmarktest(neightet); } } cavetetlist->restart(); cavebdrylist->restart(); caveoldtetlist->restart(); return ENCSEGMENT; } if (checksubfaces || noencsubflag) { // Check if some subfaces are inside the cavity. for (i = 0; i < (int) caveoldtetlist->objects; i++) { parytet = (triface *) fastlookup(caveoldtetlist, i); neightet.tet = parytet->tet; for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { tspivot(neightet, checksh); if (checksh.sh != dummysh) { sym(neightet, neineitet); // Do not check it if it is a hull tet. if (neineitet.tet != dummytet) { if (infected(neineitet)) { if (b->verbose > 1) { printf(" Queue a missing subface (%d, %d, %d).\n", pointmark(sorg(checksh)), pointmark(sdest(checksh)), pointmark(sapex(checksh))); } tsdissolve(neineitet); // Disconnect a tet-sub bond. stdissolve(checksh); // Disconnect the sub-tet bond. sesymself(checksh); stdissolve(checksh); // Add the missing subface into list. subfacstack->newindex((void **) &pssub); *pssub = checksh; } } } } } } if (noencsubflag && (subfacstack->objects > 0)) { // Found encroached subfaces! Do not insert this point. /*for (i = 0; i < caveoldtetlist->objects; i++) { cavetet = (triface *) fastlookup(caveoldtetlist, i); uninfect(*cavetet); unmarktest(*cavetet); } for (i = 0; i < cavebdrylist->objects; i++) { cavetet = (triface *) fastlookup(cavebdrylist, i); unmarktest(*cavetet); // Unmark it. } if (bwflag && (futureflip != NULL)) { flippool->restart(); futureflip = NULL; } cavetetlist->restart(); cavebdrylist->restart(); caveoldtetlist->restart(); return ENCFACE; */ } if (visflag) { // If T is not a Delaunay triangulation, the formed cavity may not be // star-shaped (fig/dump-cavity-case8). Validation is needed. cavetetlist->restart(); // Re-use it. for (i = 0; i < (int) cavebdrylist->objects; i++) { cavetet = (triface *) fastlookup(cavebdrylist, i); if (infected(*cavetet)) { sym(*cavetet, neightet); if (neightet.tet == dummytet || !infected(neightet)) { if (neightet.tet != dummytet) { cavetet->ver = 4; // CCW edge ring. pa = dest(*cavetet); pb = org(*cavetet); pc = apex(*cavetet); ori = orient3d(pa, pb, pc, insertpt); orient3dcount++; assert(ori != 0.0); // SELF_CHECK enqflag = (ori > 0.0); } else { enqflag = true; // A hull face. } if (enqflag) { // This face is valid, save it. cavetetlist->newindex((void **) &parytet); *parytet = *cavetet; } else { if (b->verbose > 1) { printf(" Cut tet (%d, %d, %d, %d)\n", pointmark(pb), pointmark(pa), pointmark(pc), pointmark(oppo(*cavetet))); } uninfect(*cavetet); unmarktest(*cavetet); if (neightet.tet != dummytet) { unmarktest(neightet); } updatecount++; // Add three new faces to find new boundaries. for (j = 0; j < 3; j++) { fnext(*cavetet, neineitet); sym(neineitet, neightet); if (neightet.tet != dummytet) { if (infected(neightet)) { neightet.ver = 4; cavebdrylist->newindex((void **) &parytet); *parytet = neightet; } else { unmarktest(neightet); } } enextself(*cavetet); } } } else { // This face is not on the cavity boundary anymore. unmarktest(*cavetet); } } else { assert(!marktested(*cavetet)); } } if (updatecount > 0) { // Update the cavity boundary faces (fig/dump-cavity-case9). cavebdrylist->restart(); for (i = 0; i < (int) cavetetlist->objects; i++) { cavetet = (triface *) fastlookup(cavetetlist, i); // 'cavetet' was boundary face of the cavity. if (infected(*cavetet)) { sym(*cavetet, neightet); if ((neightet.tet != dummytet) || !infected(neightet)) { // It is a cavity boundary face. cavebdrylist->newindex((void **) &parytet); *parytet = *cavetet; } else { // Not a cavity boundary face. unmarktest(*cavetet); } } else { assert(!marktested(*cavetet)); } } // Update the list of old tets. cavetetlist->restart(); for (i = 0; i < (int) caveoldtetlist->objects; i++) { cavetet = (triface *) fastlookup(caveoldtetlist, i); if (infected(*cavetet)) { cavetetlist->newindex((void **) &parytet); *parytet = *cavetet; } } assert((int) cavetetlist->objects < i); // Swap 'cavetetlist' and 'caveoldtetlist'. swaplist = caveoldtetlist; caveoldtetlist = cavetetlist; cavetetlist = swaplist; if (b->verbose > 1) { printf(" Size of the updated cavity: %d faces %d tets.\n", (int) cavebdrylist->objects, (int) caveoldtetlist->objects); } } } // Re-use this list for new cavity faces. cavetetlist->restart(); // Create new tetrahedra in the Bowyer-Watson cavity and Connect them. for (i = 0; i < (int) cavebdrylist->objects; i++) { parytet = (triface *) fastlookup(cavebdrylist, i); assert(infected(*parytet)); // The tet is inside the cavity. parytet->ver = 0; // In CCW edge ring. maketetrahedron(&newtet); setorg (newtet, org(*parytet)); setdest(newtet, dest(*parytet)); setapex(newtet, apex(*parytet)); setoppo(newtet, insertpt); for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(parytet->tet, j); setelemattribute(newtet.tet, j, attrib); } if (b->varvolume) { volume = volumebound(parytet->tet); setvolumebound(newtet.tet, volume); } // Bond the new tet to the adjacent tet outside the cavity. sym(*parytet, neightet); if (neightet.tet != dummytet) { // The tet was marked (to avoid redundant insphere tests). unmarktest(neightet); bond(newtet, neightet); } else { // Bond newtet to dummytet. dummytet[0] = encode(newtet); } // mark the other three faces of this tet as "open". neightet.tet = newtet.tet; for (j = 0; j < 3; j++) { neightet.tet[locpivot[0][j]] = NULL; } // Let the oldtet knows newtet (for connecting adjacent new tets). parytet->tet[parytet->loc] = encode(newtet); if (checksubsegs) { // newtet and parytet share at the same edge. for (j = 0; j < 3; j++) { tsspivot1(*parytet, checkseg); if (checkseg.sh != dummysh) { if (sinfected(checkseg)) { // This subsegment is not missing. Unmark it. if (b->verbose > 1) { printf(" Dequeue a segment (%d, %d).\n", pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); } suninfect(checkseg); // Dequeue a non-missing segment. } tssbond1(newtet, checkseg); } enextself(*parytet); enextself(newtet); } } if (checksubfaces) { // Bond subface to the new tet. tspivot(*parytet, checksh); if (checksh.sh != dummysh) { tsbond(newtet, checksh); // The other-side-connection of checksh should be no change. } } } // i // Set a handle for speeding point location. recenttet = newtet; setpoint2tet(insertpt, encode(newtet)); // Connect adjacent new tetrahedra together. Here we utilize the connections // of the old cavity tets to find the new adjacent tets. for (i = 0; i < (int) cavebdrylist->objects; i++) { parytet = (triface *) fastlookup(cavebdrylist, i); decode(parytet->tet[parytet->loc], newtet); // assert(org(newtet) == org(*parytet)); // SELF_CHECK // assert((newtet.ver & 1) == 0); // in CCW edge ring. for (j = 0; j < 3; j++) { fnext(newtet, neightet); // Go to the "open" face. if (neightet.tet[neightet.loc] == NULL) { spintet = *parytet; while (1) { fnextself(spintet); symedgeself(spintet); if (spintet.tet == dummytet) break; if (!infected(spintet)) break; } if (spintet.tet != dummytet) { // 'spintet' is the adjacent tet of the cavity. fnext(spintet, neineitet); assert(neineitet.tet[neineitet.loc] == NULL); // SELF_CHECK bond(neightet, neineitet); } else { // This side is a hull face. neightet.tet[neightet.loc] = (tetrahedron) dummytet; dummytet[0] = encode(neightet); } } setpoint2tet(org(newtet), encode(newtet)); enextself(newtet); enextself(*parytet); } } // Delete the old cavity tets. for (i = 0; i < (int) caveoldtetlist->objects; i++) { parytet = (triface *) fastlookup(caveoldtetlist, i); tetrahedrondealloc(parytet->tet); } // Set the point type. if (pointtype(insertpt) == UNUSEDVERTEX) { setpointtype(insertpt, FREEVOLVERTEX); } cavetetlist->restart(); cavebdrylist->restart(); caveoldtetlist->restart(); return loc; } /////////////////////////////////////////////////////////////////////////////// // // // unifypoint() Unify two distinct points if they're very close. // // // // This function is used for dealing with inputs from CAD tools. Two points // // p and q are unified if: dist(p, q) / longest < eps. Where dist() is the // // Euclidean distance between p and q, longest is the maximum edge size of // // the input point set, eps is the tolerrence specified by user, default is // // 1e-6, it can be adjusted by '-T' switch. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::unifypoint(point testpt, triface *starttet, enum locateresult loc, REAL eps) { triface symtet, spintet; point checkpt, tapex; REAL tol; bool merged; int hitbdry; int i; merged = false; tol = longest * eps; if ((loc == OUTSIDE) || (loc == INTETRAHEDRON) || (loc == ONFACE)) { // Check p is close to the four corners of the tet. for (i = 0; i < 4; i++) { checkpt = (point) starttet->tet[4 + i]; if (distance(testpt, checkpt) < tol) { merged = true; // Found a merge point p'. break; } } if (!merged && (loc == ONFACE)) { // Check the opposite point of the neighbor tet if it exists. sym(*starttet, symtet); if (symtet.tet != dummytet) { checkpt = oppo(symtet); if (distance(testpt, checkpt) < tol) { merged = true; // Found a merge point p'. } } } } else if (loc == ONEDGE) { // Check two endpoints of the edge. checkpt = org(*starttet); if (distance(testpt, checkpt) < tol) { merged = true; // Found a merge point p'. } if (!merged) { checkpt = dest(*starttet); if (distance(testpt, checkpt) < tol) { merged = true; // Found a merge point p'. } } if (!merged) { // Check apexes of the faces having the edge. spintet = *starttet; tapex = apex(*starttet); hitbdry = 0; do { checkpt = apex(spintet); if (distance(testpt, checkpt) < tol) { merged = true; // Found a merge point p'. break; } if (!fnextself(spintet)) { hitbdry++; if (hitbdry < 2) { esym(*starttet, spintet); if (!fnextself(spintet)) { hitbdry++; } } } } while ((apex(spintet) != tapex) && (hitbdry < 2)); } } if (merged) { if (b->object != tetgenbehavior::STL) { if (!b->quiet) { printf("Warning: Point %d is unified to point %d.\n", pointmark(testpt), pointmark(checkpt)); } // Count the number of duplicated points. dupverts++; } // Remember it is a duplicated point. setpointtype(testpt, DUPLICATEDVERTEX); // Set a pointer to the point it duplicates. setpoint2ppt(testpt, checkpt); } return merged; } /////////////////////////////////////////////////////////////////////////////// // // // incrflipdelaunay() Construct a delaunay tetrahedrization from a set of // // 3D points by the incremental flip algorithm. // // // // The incremental flip algorithm (by Edelsbrunner and Shah) can be describ- // // ed as follows: // // // // S be a set of points in 3D, Let 4 <= i <= n and assume that the // // Delaunay tetrahedralization of the first i-1 points in S is already // // constructed; call it D(i-1). Add the i-th point p_i (belong to S) to // // D(i-1), and restore Delaunayhood by flipping; this result in D(i). // // Repeat this procedure until i = n. // // // // This strategy always leads to the Delaunay triangulation of a point set. // // The return value is the number of convex hull faces of D. // // // // If the input point set is degenerate, i.e., all points are collinear or // // are coplanar, then no 3D DT is created and return FALSE. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::incrflipdelaunay(triface* oldtet, point* insertarray, long arraysize, bool jump, bool merge, REAL eps, queue* flipque) { triface newtet, searchtet; point swappt, lastpt; enum locateresult loc; REAL det; REAL attrib, volume; int i, j; // The initial tetrahedralization T only has one tet formed by 4 affinely // linear independent vertices of the point set V = 'insertarray'. The // first point a = insertarray[0]. // Get the second point b, that is not identical or very close to a. for (i = 1; i < arraysize; i++) { det = distance(insertarray[0], insertarray[i]); if (det > (longest * eps)) break; } if (i == arraysize) { // printf("\nAll points seem to be identical.\n"); return false; } else { // Swap to move b from index i to index 1. swappt = insertarray[i]; insertarray[i] = insertarray[1]; insertarray[1] = swappt; } // Get the third point c, that is not collinear with a and b. for (i++; i < arraysize; i++) { if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps)) break; } if (i == arraysize) { // printf("\nAll points seem to be collinear.\n"); return false; } else { // Swap to move c from index i to index 2. swappt = insertarray[i]; insertarray[i] = insertarray[2]; insertarray[2] = swappt; } // Get the fourth point d, that is not coplanar with a, b, and c. for (i++; i < arraysize; i++) { det = orient3d(insertarray[0], insertarray[1], insertarray[2], insertarray[i]); if (det == 0.0) continue; if (!iscoplanar(insertarray[0], insertarray[1], insertarray[2], insertarray[i], det, eps)) break; } if (i == arraysize) { return false; } else { // Swap to move d from index i to index 3. swappt = insertarray[i]; insertarray[i] = insertarray[3]; insertarray[3] = swappt; lastpt = insertarray[3]; // The index of the next inserting point is 4. i = 4; } if (det > 0.0) { // For keeping the positive orientation. swappt = insertarray[0]; insertarray[0] = insertarray[1]; insertarray[1] = swappt; } // Create the initial tet. if (b->verbose > 1) { printf(" Create the first tet (%d, %d, %d, %d).\n", pointmark(insertarray[0]), pointmark(insertarray[1]), pointmark(insertarray[2]), pointmark(lastpt)); } maketetrahedron(&newtet); setorg(newtet, insertarray[0]); setdest(newtet, insertarray[1]); setapex(newtet, insertarray[2]); setoppo(newtet, lastpt); if (oldtet != (triface *) NULL) { for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(oldtet->tet, j); setelemattribute(newtet.tet, j, attrib); } if (b->varvolume) { volume = volumebound(oldtet->tet); setvolumebound(newtet.tet, volume); } } // Set vertex type be FREEVOLVERTEX if it has no type yet. if (pointtype(insertarray[0]) == UNUSEDVERTEX) { setpointtype(insertarray[0], FREEVOLVERTEX); } if (pointtype(insertarray[1]) == UNUSEDVERTEX) { setpointtype(insertarray[1], FREEVOLVERTEX); } if (pointtype(insertarray[2]) == UNUSEDVERTEX) { setpointtype(insertarray[2], FREEVOLVERTEX); } if (pointtype(lastpt) == UNUSEDVERTEX) { setpointtype(lastpt, FREEVOLVERTEX); } // Bond to 'dummytet' for point location. dummytet[0] = encode(newtet); recenttet = newtet; // Update the point-to-tet map. setpoint2tet(insertarray[0], encode(newtet)); setpoint2tet(insertarray[1], encode(newtet)); setpoint2tet(insertarray[2], encode(newtet)); setpoint2tet(lastpt, encode(newtet)); if (b->verbose > 3) { printf(" Creating tetra "); printtet(&newtet); } // At init, all faces of this tet are hull faces. hullsize = 4; if (b->verbose > 1) { printf(" Incrementally inserting points.\n"); } // Insert the rest of points, one by one. for (; i < arraysize; i++) { if (jump) { searchtet.tet = NULL; } else { searchtet = recenttet; } loc = insertvertexbw(insertarray[i],&searchtet,true,false,false,false); } return true; } /////////////////////////////////////////////////////////////////////////////// // // // delaunizevertices() Form a Delaunay tetrahedralization. // // // // Given a point set V (saved in 'points'). The Delaunay tetrahedralization // // D of V is created by incrementally inserting vertices. Returns the number // // of triangular faces bounding the convex hull of D. // // // /////////////////////////////////////////////////////////////////////////////// long tetgenmesh::delaunizevertices() { point *insertarray; long arraysize; bool success; int i, j; if (!b->quiet) { printf("Constructing Delaunay tetrahedralization.\n"); } if (cavetetlist == NULL) { cavetetlist = new arraypool(sizeof(triface), 10); cavebdrylist = new arraypool(sizeof(triface), 10); caveoldtetlist = new arraypool(sizeof(triface), 10); } // Prepare the array of points for inserting. arraysize = points->items; insertarray = new point[arraysize]; points->traversalinit(); if (b->nojettison == 1) { // -J option, debug only. // Use the input order. for (i = 0; i < arraysize; i++) { insertarray[i] = pointtraverse(); } } else { // Randomize the point order. for (i = 0; i < arraysize; i++) { j = (int) randomnation(i + 1); // 0 <= j <= i; insertarray[i] = insertarray[j]; insertarray[j] = pointtraverse(); } } // Form the DT by incremental flip Delaunay algorithm. success = incrflipdelaunay(NULL, insertarray, arraysize, true, b->plc, 0.0, NULL); delete [] insertarray; if (!success) { return 0l; } else { return hullsize; } } //// //// //// //// //// delaunay_cxx ///////////////////////////////////////////////////////////// //// surface_cxx ////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // sinsertvertex() Insert a vertex into a triangulation of a facet. // // // // The new point (p) will be located. Searching from 'splitsh'. If 'splitseg'// // is not NULL, p is on a segment, no search is needed. // // // // If 'cflag' is not TRUE, the triangulation may be not convex. Don't insert // // p if it is found in outside. // // // // Comment: This routine assumes the 'abovepoint' of this facet has been set,// // i.e., the routine getabovepoint() has been executed before it is called. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::locateresult tetgenmesh::sinsertvertex(point insertpt, face *splitsh, face *splitseg, bool bwflag, bool cflag) { face *abfaces, *parysh, *pssub; face neighsh, newsh, casout, casin; face aseg, bseg, aoutseg, boutseg; face checkseg; triface neightet; point pa, pb, pc, *ppt; enum locateresult loc; REAL sign, ori, area; int n, s, i, j; if (splitseg != NULL) { spivot(*splitseg, *splitsh); loc = ONEDGE; } else { // Locate the point, '1' means the flag stop-at-segment is on. loc = locatesub(insertpt, splitsh, 1, 0); } // Return if p lies on a vertex. if (loc == ONVERTEX) return loc; if (loc == OUTSIDE) { // Return if 'cflag' is not set. if (!cflag) return loc; } if (loc == ONEDGE) { if (splitseg == NULL) { // Do not split a segment. sspivot(*splitsh, checkseg); if (checkseg.sh != dummysh) return loc; // return ONSUBSEG; // Check if this edge is on the hull. spivot(*splitsh, neighsh); if (neighsh.sh == dummysh) { // A convex hull edge. The new point is on the hull. loc = OUTSIDE; } } } if (b->verbose > 1) { pa = sorg(*splitsh); pb = sdest(*splitsh); pc = sapex(*splitsh); printf(" Insert point %d (%d, %d, %d) loc %d\n", pointmark(insertpt), pointmark(pa), pointmark(pb), pointmark(pc), (int) loc); } // Does 'insertpt' lie on a segment? if (splitseg != NULL) { splitseg->shver = 0; pa = sorg(*splitseg); // Count the number of faces at segment [a, b]. n = 0; neighsh = *splitsh; do { spivotself(neighsh); n++; } while ((neighsh.sh != dummysh) && (neighsh.sh != splitsh->sh)); // n is at least 1. abfaces = new face[n]; // Collect faces at seg [a, b]. abfaces[0] = *splitsh; if (sorg(abfaces[0]) != pa) sesymself(abfaces[0]); for (i = 1; i < n; i++) { spivot(abfaces[i - 1], abfaces[i]); if (sorg(abfaces[i]) != pa) sesymself(abfaces[i]); } } // Initialize the cavity. if (loc == ONEDGE) { smarktest(*splitsh); caveshlist->newindex((void **) &parysh); *parysh = *splitsh; if (splitseg != NULL) { for (i = 1; i < n; i++) { smarktest(abfaces[i]); caveshlist->newindex((void **) &parysh); *parysh = abfaces[i]; } } else { spivot(*splitsh, neighsh); if (neighsh.sh != dummysh) { smarktest(neighsh); caveshlist->newindex((void **) &parysh); *parysh = neighsh; } } } else if (loc == ONFACE) { smarktest(*splitsh); caveshlist->newindex((void **) &parysh); *parysh = *splitsh; } else { // loc == OUTSIDE; // This is only possible when T is convex. assert(cflag); // SELF_CHECK // Adjust 'abovepoint' to be above the 'splitsh'. 2009-07-21. ori = orient3d(sorg(*splitsh), sdest(*splitsh), sapex(*splitsh), abovepoint); assert(ori != 0); if (ori > 0) { sesymself(*splitsh); } // Assume p is on top of the edge ('splitsh'). Find a right-most edge // which is visible by p. neighsh = *splitsh; while (1) { senext2self(neighsh); spivot(neighsh, casout); if (casout.sh == dummysh) { // A convex hull edge. Is it visible by p. pa = sorg(neighsh); pb = sdest(neighsh); ori = orient3d(pa, pb, abovepoint, insertpt); if (ori < 0) { *splitsh = neighsh; // Update 'splitsh'. } else { break; // 'splitsh' is the right-most visible edge. } } else { if (sorg(casout) != sdest(neighsh)) sesymself(casout); neighsh = casout; } } // Create new triangles for all visible edges of p (from right to left). casin.sh = dummysh; // No adjacent face at right. pa = sorg(*splitsh); pb = sdest(*splitsh); while (1) { // Create a new subface on top of the (visible) edge. makeshellface(subfaces, &newsh); // setshvertices(newsh, pb, pa, insertpt); setsorg(newsh, pb); setsdest(newsh, pa); setsapex(newsh, insertpt); setshellmark(newsh, shellmark(*splitsh)); if (b->quality && varconstraint) { area = areabound(*splitsh); setareabound(newsh, area); } // Connect the new subface to the bottom subfaces. sbond1(newsh, *splitsh); sbond1(*splitsh, newsh); // Connect the new subface to its right-adjacent subface. if (casin.sh != dummysh) { senext(newsh, casout); sbond1(casout, casin); sbond1(casin, casout); } // The left-adjacent subface has not been created yet. senext2(newsh, casin); // Add the new face into list. smarktest(newsh); caveshlist->newindex((void **) &parysh); *parysh = newsh; // Move to the convex hull edge at the left of 'splitsh'. neighsh = *splitsh; while (1) { senextself(neighsh); spivot(neighsh, casout); if (casout.sh == dummysh) { *splitsh = neighsh; break; } if (sorg(casout) != sdest(neighsh)) sesymself(casout); neighsh = casout; } // A convex hull edge. Is it visible by p. pa = sorg(*splitsh); pb = sdest(*splitsh); ori = orient3d(pa, pb, abovepoint, insertpt); if (ori >= 0) break; } } // Form the Bowyer-Watson cavity. for (i = 0; i < (int) caveshlist->objects; i++) { parysh = (face *) fastlookup(caveshlist, i); for (j = 0; j < 3; j++) { sspivot(*parysh, checkseg); if (checkseg.sh == dummysh) { spivot(*parysh, neighsh); if (neighsh.sh != dummysh) { if (!smarktested(neighsh)) { if (bwflag) { pa = sorg(neighsh); pb = sdest(neighsh); pc = sapex(neighsh); sign = incircle3d(pa, pb, pc, insertpt); if (sign < 0) { smarktest(neighsh); caveshlist->newindex((void **) &pssub); *pssub = neighsh; } } else { sign = 1; // A boundary edge. } } else { sign = -1; // Not a boundary edge. } } else { if (loc == OUTSIDE) { // It is a boundary edge if it does not contain insertp. if ((sorg(*parysh)==insertpt) || (sdest(*parysh)==insertpt)) { sign = -1; // Not a boundary edge. } else { sign = 1; // A boundary edge. } } else { sign = 1; // A boundary edge. } } } else { sign = 1; // A segment! } if (sign >= 0) { // Add a boundary edge. caveshbdlist->newindex((void **) &pssub); *pssub = *parysh; } senextself(*parysh); } } // Creating new subfaces. for (i = 0; i < (int) caveshbdlist->objects; i++) { parysh = (face *) fastlookup(caveshbdlist, i); sspivot(*parysh, checkseg); if ((parysh->shver & 01) != 0) sesymself(*parysh); pa = sorg(*parysh); pb = sdest(*parysh); // Create a new subface. makeshellface(subfaces, &newsh); // setshvertices(newsh, pa, pb, insertpt); setsorg(newsh, pa); setsdest(newsh, pb); setsapex(newsh, insertpt); setshellmark(newsh, shellmark(*parysh)); if (b->quality && varconstraint) { area = areabound(*parysh); setareabound(newsh, area); } // Connect newsh to outer subfaces. spivot(*parysh, casout); if (casout.sh != dummysh) { if (casout.sh != parysh->sh) { // It is not self-bonded. casin = casout; if (checkseg.sh != dummysh) { spivot(casin, neighsh); while (neighsh.sh != parysh->sh) { casin = neighsh; spivot(casin, neighsh); } } sbond1(newsh, casout); sbond1(casin, newsh); } else { // This side is empty. } } else { // This is a hull side. Save it in dummysh[0] (it will be used by // the routine locatesub()). 2009-07-20. dummysh[0] = sencode(newsh); } if (checkseg.sh != dummysh) { ssbond(newsh, checkseg); } // Connect oldsh <== newsh (for connecting adjacent new subfaces). sbond1(*parysh, newsh); } // Set a handle for searching. // recentsh = newsh; // Connect adjacent new subfaces together. for (i = 0; i < (int) caveshbdlist->objects; i++) { // Get an old subface at edge [a, b]. parysh = (face *) fastlookup(caveshbdlist, i); sspivot(*parysh, checkseg); spivot(*parysh, newsh); // The new subface [a, b, p]. senextself(newsh); // At edge [b, p]. spivot(newsh, neighsh); if (neighsh.sh == dummysh) { // Find the adjacent new subface at edge [b, p]. pb = sdest(*parysh); neighsh = *parysh; while (1) { senextself(neighsh); spivotself(neighsh); if (neighsh.sh == dummysh) break; if (!smarktested(neighsh)) break; if (sdest(neighsh) != pb) sesymself(neighsh); } if (neighsh.sh != dummysh) { // Now 'neighsh' is a new subface at edge [b, #]. if (sorg(neighsh) != pb) sesymself(neighsh); assert(sorg(neighsh) == pb); // SELF_CHECK assert(sapex(neighsh) == insertpt); // SELF_CHECK senext2self(neighsh); // Go to the open edge [p, b]. spivot(neighsh, casout); // SELF_CHECK assert(casout.sh == dummysh); // SELF_CHECK sbond(newsh, neighsh); } else { assert(loc == OUTSIDE); // SELF_CHECK // It is a hull edge. 2009-07-21 dummysh[0] = sencode(newsh); } } spivot(*parysh, newsh); // The new subface [a, b, p]. senext2self(newsh); // At edge [p, a]. spivot(newsh, neighsh); if (neighsh.sh == dummysh) { // Find the adjacent new subface at edge [p, a]. pa = sorg(*parysh); neighsh = *parysh; while (1) { senext2self(neighsh); spivotself(neighsh); if (neighsh.sh == dummysh) break; if (!smarktested(neighsh)) break; if (sorg(neighsh) != pa) sesymself(neighsh); } if (neighsh.sh != dummysh) { // Now 'neighsh' is a new subface at edge [#, a]. if (sdest(neighsh) != pa) sesymself(neighsh); assert(sdest(neighsh) == pa); // SELF_CHECK assert(sapex(neighsh) == insertpt); // SELF_CHECK senextself(neighsh); // Go to the open edge [a, p]. spivot(neighsh, casout); // SELF_CHECK assert(casout.sh == dummysh); // SELF_CHECK sbond(newsh, neighsh); } else { assert(loc == OUTSIDE); // SELF_CHECK // It is a hull edge. 2009-07-21 dummysh[0] = sencode(newsh); } } } if (splitseg != NULL) { // Split the segment [a, b]. aseg = *splitseg; pa = sorg(aseg); pb = sdest(aseg); if (b->verbose > 1) { printf(" Split seg (%d, %d) by %d.\n", pointmark(pa), pointmark(pb), pointmark(insertpt)); } // Insert the new point p. makeshellface(subsegs, &bseg); // setshvertices(bseg, insertpt, pb, NULL); setsorg(bseg, insertpt); setsdest(bseg, pb); setsapex(bseg, NULL); setsdest(aseg, insertpt); setshellmark(bseg, shellmark(aseg)); // This is done outside this routine (at where newpt was created). // setpoint2sh(insertpt, sencode(aseg)); if (b->quality && varconstraint) { setareabound(bseg, areabound(aseg)); } // Update the point-to-seg map. setpoint2seg(pb, sencode(bseg)); setpoint2seg(insertpt, sencode(bseg)); // Connect [p, b]<->[b, #]. senext(aseg, aoutseg); spivotself(aoutseg); if (aoutseg.sh != dummysh) { senext(bseg, boutseg); sbond(boutseg, aoutseg); } // Connect [a, p] <-> [p, b]. senext(aseg, aoutseg); senext2(bseg, boutseg); sbond(aoutseg, boutseg); // Connect subsegs [a, p] and [p, b] to the true new subfaces. for (i = 0; i < n; i++) { spivot(abfaces[i], newsh); // The faked new subface. if (sorg(newsh) != pa) sesymself(newsh); senext2(newsh, neighsh); // The edge [p, a] in newsh spivot(neighsh, casout); ssbond(casout, aseg); senext(newsh, neighsh); // The edge [b, p] in newsh spivot(neighsh, casout); ssbond(casout, bseg); } if (n > 1) { // Create the two face rings at [a, p] and [p, b]. for (i = 0; i < n; i++) { spivot(abfaces[i], newsh); // The faked new subface. if (sorg(newsh) != pa) sesymself(newsh); spivot(abfaces[(i + 1) % n], neighsh); // The next faked new subface. if (sorg(neighsh) != pa) sesymself(neighsh); senext2(newsh, casout); // The edge [p, a] in newsh. senext2(neighsh, casin); // The edge [p, a] in neighsh. spivotself(casout); spivotself(casin); sbond1(casout, casin); // Let the i's face point to (i+1)'s face. senext(newsh, casout); // The edge [b, p] in newsh. senext(neighsh, casin); // The edge [b, p] in neighsh. spivotself(casout); spivotself(casin); sbond1(casout, casin); } } else { // Only one subface contains this segment. // assert(n == 1); spivot(abfaces[0], newsh); // The faked new subface. if (sorg(newsh) != pa) sesymself(newsh); senext2(newsh, casout); // The edge [p, a] in newsh. spivotself(casout); sdissolve(casout); // Disconnect to faked subface. senext(newsh, casout); // The edge [b, p] in newsh. spivotself(casout); sdissolve(casout); // Disconnect to faked subface. } // Delete the faked new subfaces. for (i = 0; i < n; i++) { spivot(abfaces[i], newsh); // The faked new subface. shellfacedealloc(subfaces, newsh.sh); } if (checksubsegs) { // Add two subsegs into stack (for recovery). if (!sinfected(aseg)) { s = randomnation(subsegstack->objects + 1); subsegstack->newindex((void **) &parysh); *parysh = * (face *) fastlookup(subsegstack, s); sinfect(aseg); parysh = (face *) fastlookup(subsegstack, s); *parysh = aseg; } assert(!sinfected(bseg)); // SELF_CHECK s = randomnation(subsegstack->objects + 1); subsegstack->newindex((void **) &parysh); *parysh = * (face *) fastlookup(subsegstack, s); sinfect(bseg); parysh = (face *) fastlookup(subsegstack, s); *parysh = bseg; } delete [] abfaces; } if (checksubfaces) { // Add all new subfaces into list. for (i = 0; i < (int) caveshbdlist->objects; i++) { // Get an old subface at edge [a, b]. parysh = (face *) fastlookup(caveshbdlist, i); spivot(*parysh, newsh); // The new subface [a, b, p]. // Some new subfaces may get deleted (when 'splitseg' is a segment). if (!isdead(&newsh)) { if (b->verbose > 1) { printf(" Queue a new subface (%d, %d, %d).\n", pointmark(sorg(newsh)), pointmark(sdest(newsh)), pointmark(sapex(newsh))); } subfacstack->newindex((void **) &pssub); *pssub = newsh; } } } // Update the point-to-subface map. for (i = 0; i < (int) caveshbdlist->objects; i++) { // Get an old subface at edge [a, b]. parysh = (face *) fastlookup(caveshbdlist, i); spivot(*parysh, newsh); // The new subface [a, b, p]. // Some new subfaces may get deleted (when 'splitseg' is a segment). if (!isdead(&newsh)) { ppt = (point *) &(newsh.sh[3]); for (j = 0; j < 3; j++) { setpoint2sh(ppt[j], sencode(newsh)); } } } // Delete the old subfaces. for (i = 0; i < (int) caveshlist->objects; i++) { parysh = (face *) fastlookup(caveshlist, i); if (checksubfaces) { // Disconnect in the neighbor tets. for (j = 0; j < 2; j++) { stpivot(*parysh, neightet); if (neightet.tet != dummytet) { tsdissolve(neightet); // symself(neightet); // tsdissolve(neightet); } sesymself(*parysh); } } shellfacedealloc(subfaces, parysh->sh); } // Clean the working lists. caveshlist->restart(); caveshbdlist->restart(); return loc; } /////////////////////////////////////////////////////////////////////////////// // // // formstarpolygon() Form the star polygon of a point in facet. // // // // The polygon P is formed by all coplanar subfaces having 'pt' as a vertex. // // P is bounded by segments, e.g, if no segments, P is the full star of pt. // // // // 'trilist' T returns the subfaces, it has one of such subfaces on input. // // In addition, if f is in T, then sapex(f) = p. 'vertlist' V are verts of P.// // Topologically, T is the star of p; V and the edges of T are the link of p.// // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formstarpolygon(point pt, list* trilist, list* vertlist) { face steinsh, lnextsh, rnextsh; face checkseg; point pa, pb, pc, pd; int i; // Get a subface f containing p. steinsh = * (face *)(* trilist)[0]; steinsh.shver = 0; // CCW // Let sapex(f) be p. for (i = 0; i < 3; i++) { if (sapex(steinsh) == pt) break; senextself(steinsh); } assert(i < 3); // Add the edge f into list. * (face *)(* trilist)[0] = steinsh; pa = sorg(steinsh); pb = sdest(steinsh); if (vertlist != (list *) NULL) { // Add two verts a, b into V, vertlist->append(&pa); vertlist->append(&pb); } // Rotate edge pa to the left (CW) until meet pb or a segment. lnextsh = steinsh; pc = pa; do { senext2self(lnextsh); assert(sorg(lnextsh) == pt); sspivot(lnextsh, checkseg); if (checkseg.sh != dummysh) break; // Do not cross a segment. // Get neighbor subface n (must exist). spivotself(lnextsh); if (lnextsh.sh == dummysh) break; // It's a hull edge. // Go to the edge ca opposite to p. if (sdest(lnextsh) != pt) sesymself(lnextsh); assert(sdest(lnextsh) == pt); senext2self(lnextsh); // Add n (at edge ca) to T. trilist->append(&lnextsh); // Add edge ca to E. pc = sorg(lnextsh); if (pc == pb) break; // Rotate back. if (vertlist != (list *) NULL) { // Add vert c into V. vertlist->append(&pc); } } while (true); if (pc != pb) { // Rotate edge bp to the right (CCW) until meet a segment. rnextsh = steinsh; do { senextself(rnextsh); assert(sdest(rnextsh) == pt); sspivot(rnextsh, checkseg); if (checkseg.sh != dummysh) break; // Do not cross a segment. // Get neighbor subface n (must exist). spivotself(rnextsh); if (rnextsh.sh == dummysh) break; // It's a hull edge. // Go to the edge bd opposite to p. if (sorg(rnextsh) != pt) sesymself(rnextsh); assert(sorg(rnextsh) == pt); senextself(rnextsh); // Add n (at edge bd) to T. trilist->append(&rnextsh); // Add edge bd to E. pd = sdest(rnextsh); if (pd == pa) break; // Rotate back. if (vertlist != (list *) NULL) { // Add vert d into V. vertlist->append(&pd); } } while (true); } } /////////////////////////////////////////////////////////////////////////////// // // // About the 'abovepoint' // // // // The 'abovepoint' of a facet is a point which is exactly non-coplanar with // // the plane containing that facet. With such an point, the 3D predicates: // // orient3d(), and insphere() can be used to substitute the corresponding 2D // // siblings, e.g. orient2d(), and incircle(). Its location is not critical, // // but floating-point accuracy is improved if it is nicely placed over the // // facet, not too close or too far away. // // // // We take the convention that the abovepoint of a facet always lies above // // the facet. By this convention, given three points a, b, and c in a facet, // // we say c has the counterclockwise order with ab is corresponding to say // // that c is below the plane abp, where p is the lift point. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // getfacetabovepoint() Get a point above a plane pass through a facet. // // // // The calculcated point is saved in 'facetabovepointarray'. The 'abovepoint'// // is set on return. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::getfacetabovepoint(face* facetsh) { list *verlist, *trilist, *tetlist; triface adjtet; face symsh; point p1, p2, p3, pa; // enum locateresult loc; REAL smallcos, cosa; REAL largevol, volume; REAL v1[3], v2[3], len; int smallidx, largeidx; int shmark; int i, j; abovecount++; // Initialize working lists. verlist = new list(sizeof(point *), NULL); trilist = new list(sizeof(face), NULL); tetlist = new list(sizeof(triface), NULL); // Get three pivotal points p1, p2, and p3 in the facet as a base triangle // which is non-trivil and has good base angle (close to 90 degree). // p1 is chosen as the one which has the smallest index in pa, pb, pc. p1 = sorg(*facetsh); pa = sdest(*facetsh); if (pointmark(pa) < pointmark(p1)) p1 = pa; pa = sapex(*facetsh); if (pointmark(pa) < pointmark(p1)) p1 = pa; // Form the star polygon of p1. trilist->append(facetsh); formstarpolygon(p1, trilist, verlist); // Get the second pivotal point p2. p2 = * (point *)(* verlist)[0]; // Get vector v1 = p1->p2. for (i = 0; i < 3; i++) v1[i] = p2[i] - p1[i]; len = sqrt(dot(v1, v1)); assert(len > 0.0); // p2 != p1. for (i = 0; i < 3; i++) v1[i] /= len; // Get the third pivotal point p3. p3 is chosen as the one in 'verlist' // which forms an angle with v1 closer to 90 degree than others do. smallcos = 1.0; // The cosine value of 0 degree. smallidx = 1; // Default value. for (i = 1; i < verlist->len(); i++) { p3 = * (point *)(* verlist)[i]; for (j = 0; j < 3; j++) v2[j] = p3[j] - p1[j]; len = sqrt(dot(v2, v2)); if (len > 0.0) { // v2 is not too small. cosa = fabs(dot(v1, v2)) / len; if (cosa < smallcos) { smallidx = i; smallcos = cosa; } } } assert(smallcos < 1.0); // p1->p3 != p1->p2. p3 = * (point *)(* verlist)[smallidx]; verlist->clear(); if (tetrahedrons->items > 0l) { // Get a tet having p1 as a vertex. point2tetorg(p1, adjtet); assert(org(adjtet) == p1); if (adjtet.tet != dummytet) { // Get the star polyhedron of p1. tetlist->append(&adjtet); formstarpolyhedron(p1, tetlist, verlist, false); } } // Get the abovepoint in 'verlist'. It is the one form the largest valid // volumw with the base triangle over other points in 'verlist. largevol = 0.0; largeidx = 0; for (i = 0; i < verlist->len(); i++) { pa = * (point *)(* verlist)[i]; volume = orient3d(p1, p2, p3, pa); if (!iscoplanar(p1, p2, p3, pa, volume, b->epsilon * 1e+2)) { if (fabs(volume) > largevol) { largevol = fabs(volume); largeidx = i; } } } // Do we have the abovepoint? if (largevol > 0.0) { abovepoint = * (point *)(* verlist)[largeidx]; if (b->verbose > 1) { printf(" Chosen abovepoint %d for facet %d.\n", pointmark(abovepoint), shellmark(*facetsh)); } } else { // Calculate an abovepoint for this facet. facenormal(p1, p2, p3, v1, &len); if (len != 0.0) for (i = 0; i < 3; i++) v1[i] /= len; // Take the average edge length of the bounding box. len = (0.5*(xmax - xmin) + 0.5*(ymax - ymin) + 0.5*(zmax - zmin)) / 3.0; // Temporarily create a point. It will be removed by jettison(); makepoint(&abovepoint); setpointtype(abovepoint, UNUSEDVERTEX); unuverts++; for (i = 0; i < 3; i++) abovepoint[i] = p1[i] + len * v1[i]; if (b->verbose > 1) { printf(" Calculated abovepoint %d for facet %d.\n", pointmark(abovepoint), shellmark(*facetsh)); } } // Save the abovepoint in 'facetabovepointarray'. shmark = shellmark(*facetsh); facetabovepointarray[shmark] = abovepoint; delete trilist; delete tetlist; delete verlist; } /////////////////////////////////////////////////////////////////////////////// // // // incrflipdelaunaysub() Create a DT from a 3D coplanar point set using // // the incremental flip algorithm. // // // // Let T be the current Delaunay triangulation (of vertices of a facet F). // // 'shmark', the index of F in 'in->facetlist' (starts from 1). // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::incrflipdelaunaysub(int shmark, REAL eps, list* ptlist, int holes, REAL* holelist, queue* flipque) { face newsh, startsh; point *insertarray; point swappt; pbcdata *pd; enum locateresult loc; REAL det, area; bool aboveflag; int arraysize; int epscount; int fmarker; int idx, i, j, k; // Get the point array (saved in 'ptlist'). insertarray = (point *) ptlist->base; arraysize = ptlist->len(); if (arraysize < 3) return false; // Do calculation of 'abovepoint' if number of points > 3. aboveflag = (arraysize > 3); // The initial triangulation T only has one triangle formed by 3 not // cillinear points of the set V = 'insertarray'. The first point: // a = insertarray[0]. epscount = 0; while (true) { for (i = 1; i < arraysize; i++) { det = distance(insertarray[0], insertarray[i]); if (det > (longest * eps)) break; } if (i < arraysize) { // Swap to move b from index i to index 1. swappt = insertarray[i]; insertarray[i] = insertarray[1]; insertarray[1] = swappt; } // Get the third point c, that is not collinear with a and b. for (i++; i < arraysize; i++) { if (!iscollinear(insertarray[0], insertarray[1], insertarray[i], eps)) break; } if (i < arraysize) { // Swap to move c from index i to index 2. swappt = insertarray[i]; insertarray[i] = insertarray[2]; insertarray[2] = swappt; i = 3; // The next inserting point. } else { // The set of vertices is not good (or nearly degenerate). if ((eps == 0.0) || (epscount > 3)) { printf("Warning: Discard an invalid facet.\n"); printf(" #%d (%d, %d, %d", shmark, pointmark(insertarray[0]), pointmark(insertarray[1]), pointmark(insertarray[2])); if (ptlist->len() > 3) { printf(", ..."); } printf(") looks like a line.\n"); // terminatetetgen(1); return false; } // Decrease the eps, and continue to try. eps *= 1e-2; epscount++; continue; } break; } // while (true); // Create the initial triangle. makeshellface(subfaces, &newsh); setsorg(newsh, insertarray[0]); setsdest(newsh, insertarray[1]); setsapex(newsh, insertarray[2]); // Remeber the facet it belongs to. setshellmark(newsh, shmark); // Set vertex type be FREESUBVERTEX if it has no type yet. if (pointtype(insertarray[0]) == FREEVOLVERTEX) { setpointtype(insertarray[0], FREESUBVERTEX); } if (pointtype(insertarray[1]) == FREEVOLVERTEX) { setpointtype(insertarray[1], FREESUBVERTEX); } if (pointtype(insertarray[2]) == FREEVOLVERTEX) { setpointtype(insertarray[2], FREESUBVERTEX); } // Let 'dummysh' point to it (for point location). dummysh[0] = sencode(newsh); // Update the point-to-subface map. for (i = 0; i < 3; i++) { setpoint2sh(insertarray[i], sencode(newsh)); } // Are there area constraints? if (b->quality && (in->facetconstraintlist != (REAL *) NULL)) { idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker. for (k = 0; k < in->numberoffacetconstraints; k++) { fmarker = (int) in->facetconstraintlist[k * 2]; if (fmarker == idx) { area = in->facetconstraintlist[k * 2 + 1]; setareabound(newsh, area); break; } } } // Are there pbc conditions? if (checkpbcs) { idx = in->facetmarkerlist[shmark - 1]; // The actual facet marker. for (k = 0; k < in->numberofpbcgroups; k++) { pd = &subpbcgrouptable[k]; for (j = 0; j < 2; j++) { if (pd->fmark[j] == idx) { setshellpbcgroup(newsh, k); pd->ss[j] = newsh; } } } } if (aboveflag) { // Compute the 'abovepoint' for orient3d(). abovepoint = facetabovepointarray[shmark]; if (abovepoint == (point) NULL) { getfacetabovepoint(&newsh); } } if (holes > 0) { // Project hole points onto the plane containing the facet. REAL prj[3]; for (k = 0; k < holes; k++) { projpt2face(&(holelist[k * 3]), insertarray[0], insertarray[1], insertarray[2], prj); for (j = 0; j < 3; j++) holelist[k * 3 + j] = prj[j]; } } // Incrementally insert the rest of points into T. for (; i < arraysize; i++) { // Insert p_i. startsh.sh = dummysh; loc = sinsertvertex(insertarray[i], &startsh, NULL, true, true); // The point-to-subface map has been updated. // Set p_i's type FREESUBVERTEX if it has no type yet. if (pointtype(insertarray[i]) == FREEVOLVERTEX) { setpointtype(insertarray[i], FREESUBVERTEX); } } return true; } /////////////////////////////////////////////////////////////////////////////// // // // finddirectionsub() Find the first subface in a facet on the path from // // one point to another. // // // // Finds the subface in the facet that intersects a line segment drawn from // // the origin of `searchsh' to the point `tend', and returns the result in // // `searchsh'. The origin of `searchsh' does not change, even though the // // subface returned may differ from the one passed in. // // // // The return value notes whether the destination or apex of the found face // // is collinear with the two points in question. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::finddirectionresult tetgenmesh::finddirectionsub( face* searchsh, point tend) { face checksh; point startpoint, leftpoint, rightpoint; REAL leftccw, rightccw; REAL ori, sign; int leftflag, rightflag; startpoint = sorg(*searchsh); // Find the sign to simulate that abovepoint is 'above' the facet. adjustedgering(*searchsh, CCW); // Make sure 'startpoint' is the origin. if (sorg(*searchsh) != startpoint) senextself(*searchsh); rightpoint = sdest(*searchsh); leftpoint = sapex(*searchsh); ori = orient3d(startpoint, rightpoint, leftpoint, abovepoint); sign = ori > 0.0 ? -1 : 1; // Is `tend' to the left? ori = orient3d(tend, startpoint, abovepoint, leftpoint); leftccw = ori * sign; leftflag = leftccw > 0.0; // Is `tend' to the right? ori = orient3d(startpoint, tend, abovepoint, rightpoint); rightccw = ori * sign; rightflag = rightccw > 0.0; if (leftflag && rightflag) { // `searchsh' faces directly away from `tend'. We could go left or // right. Ask whether it's a triangle or a boundary on the left. senext2(*searchsh, checksh); spivotself(checksh); if (checksh.sh == dummysh) { leftflag = 0; } else { rightflag = 0; } } while (leftflag) { // Turn left until satisfied. senext2self(*searchsh); spivotself(*searchsh); if (searchsh->sh == dummysh) { printf("Internal error in finddirectionsub(): Unable to find a\n"); printf(" subface leading from %d to %d.\n", pointmark(startpoint), pointmark(tend)); terminatetetgen(2); } if (sorg(*searchsh) != startpoint) sesymself(*searchsh); assert(sorg(*searchsh) == startpoint); leftpoint = sapex(*searchsh); rightccw = leftccw; ori = orient3d(tend, startpoint, abovepoint, leftpoint); leftccw = ori * sign; leftflag = leftccw > 0.0; } while (rightflag) { // Turn right until satisfied. spivotself(*searchsh); if (searchsh->sh == dummysh) { printf("Internal error in finddirectionsub(): Unable to find a\n"); printf(" subface leading from %d to %d.\n", pointmark(startpoint), pointmark(tend)); terminatetetgen(2); } if (sdest(*searchsh) != startpoint) sesymself(*searchsh); assert(sdest(*searchsh) == startpoint); senextself(*searchsh); rightpoint = sdest(*searchsh); leftccw = rightccw; ori = orient3d(startpoint, tend, abovepoint, rightpoint); rightccw = ori * sign; rightflag = rightccw > 0.0; } if (leftccw == 0.0) { return LEFTCOLLINEAR; } else if (rightccw == 0.0) { return RIGHTCOLLINEAR; } else { return ACROSSEDGE; } } /////////////////////////////////////////////////////////////////////////////// // // // insertsubseg() Create a subsegment and insert it between two subfaces. // // // // The new subsegment ab is inserted at the edge of subface 'tri'. If ab is // // not a hull edge, it is inserted between two subfaces. If 'tri' is a hull // // face, the initial face ring of ab will be set only one face which is self-// // bonded. The final face ring will be constructed in 'unifysegments()'. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::insertsubseg(face* tri) { face oppotri; face newsubseg; point pa, pb; REAL len; int e1, e2; int i; // Check if there's already a subsegment here. sspivot(*tri, newsubseg); if (newsubseg.sh == dummysh) { // Make new subsegment and initialize its vertices. makeshellface(subsegs, &newsubseg); pa = sorg(*tri); pb = sdest(*tri); setsorg(newsubseg, pa); setsdest(newsubseg, pb); // Are there length constraints? if (b->quality && (in->segmentconstraintlist != (REAL *) NULL)) { for (i = 0; i < in->numberofsegmentconstraints; i++) { e1 = (int) in->segmentconstraintlist[i * 3]; e2 = (int) in->segmentconstraintlist[i * 3 + 1]; if (((pointmark(pa) == e1) && (pointmark(pb) == e2)) || ((pointmark(pa) == e2) && (pointmark(pb) == e1))) { len = in->segmentconstraintlist[i * 3 + 2]; setareabound(newsubseg, len); break; } } } // Bond new subsegment to the two subfaces it is sandwiched between. ssbond(*tri, newsubseg); spivot(*tri, oppotri); // 'oppotri' might be "out space". if (oppotri.sh != dummysh) { ssbond(oppotri, newsubseg); } /* else { // Outside! Bond '*tri' to itself. sbond(*tri, *tri); } */ } } /////////////////////////////////////////////////////////////////////////////// // // // scoutsegmentsub() Scout the first triangle on the path from one point // // to another, and check for completion (reaching the // // second point), a collinear point,or the intersection // // of two segments. // // // // Returns true if the entire segment is successfully inserted, and false if // // the job must be finished by constrainededge(). // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::scoutsegmentsub(face* searchsh, point tend) { face newsubseg; face crosssub, crosssubseg; point leftpoint, rightpoint; enum finddirectionresult collinear; collinear = finddirectionsub(searchsh, tend); rightpoint = sdest(*searchsh); leftpoint = sapex(*searchsh); if (rightpoint == tend || leftpoint == tend) { // The segment is already an edge. if (leftpoint == tend) { senext2self(*searchsh); } // Insert a subsegment. insertsubseg(searchsh); return true; } else if (collinear == LEFTCOLLINEAR) { // We've collided with a vertex between the segment's endpoints. // Make the collinear vertex be the triangle's origin. senextself(*searchsh); // lprevself(*searchtri); // Insert a subsegment. insertsubseg(searchsh); // Insert the remainder of the segment. return scoutsegmentsub(searchsh, tend); } else if (collinear == RIGHTCOLLINEAR) { // We've collided with a vertex between the segment's endpoints. // Insert a subsegment. insertsubseg(searchsh); // Make the collinear vertex be the triangle's origin. senextself(*searchsh); // lnextself(*searchtri); // Insert the remainder of the segment. return scoutsegmentsub(searchsh, tend); } else { senext(*searchsh, crosssub); // lnext(*searchtri, crosstri); // Check for a crossing segment. sspivot(crosssub, crosssubseg); #ifdef SELF_CHECK assert(crosssubseg.sh == dummysh); #endif return false; } } /////////////////////////////////////////////////////////////////////////////// // // // flipedgerecursive() Flip an edge. // // // // This is a support routine for inserting segments into a CDT. // // // // Let 'flipedge' be ab, and two triangles abc, abd share at it. ab may not // // flipable if the four vertices a, b, c, and d are non-convex. If it is the // // case, recursively flip ad or bd. Return when ab is flipped. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::flipedgerecursive(face* flipedge, queue* flipqueue) { face fixupsh; point pa, pb, pc, pd; REAL oria, orib; bool doflip; pa = sorg(*flipedge); pb = sdest(*flipedge); pc = sapex(*flipedge); do { spivot(*flipedge, fixupsh); pd = sapex(fixupsh); oria = orient3d(pc, pd, abovepoint, pa); orib = orient3d(pc, pd, abovepoint, pb); doflip = (oria * orib < 0.0); if (doflip) { // Flip the edge (a, b) away. flip22sub(flipedge, flipqueue); // Fix flipedge on edge e (c, d). findedge(flipedge, pc, pd); } else { // ab is unflipable. Get the next edge (bd, or da) to flip. if (sorg(fixupsh) != pb) sesymself(fixupsh); assert(sdest(fixupsh) == pa); if (fabs(oria) > fabs(orib)) { // acd has larger area. Choose da. senextself(fixupsh); } else { // bcd has larger area. Choose bd. senext2self(fixupsh); } // Flip the edge. flipedgerecursive(&fixupsh, flipqueue); } } while (!doflip); } /////////////////////////////////////////////////////////////////////////////// // // // constrainededge() Force a segment into a CDT. // // // // The segment s is recovered by flipping away the edges it intersects, and // // triangulating the polygons that form on each side of it. // // // // Generates a single subsegment connecting `tstart' to `tend'. The triangle // // `startsh' has `tstart' as its origin. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::constrainededge(face* startsh, point tend, queue* flipqueue) { point tstart, tright, tleft; REAL rori, lori; bool collision; tstart = sorg(*startsh); do { // Loop edges oppo to tstart until find one crosses the segment. do { tright = sdest(*startsh); tleft = sapex(*startsh); // Is edge (tright, tleft) corss the segment. rori = orient3d(tstart, tright, abovepoint, tend); collision = (rori == 0.0); if (collision) break; // tright is on the segment. lori = orient3d(tstart, tleft, abovepoint, tend); collision = (lori == 0.0); if (collision) { // tleft is on the segment. senext2self(*startsh); break; } if (rori * lori < 0.0) break; // Find the crossing edge. // Both points are at one side of the segment. finddirectionsub(startsh, tend); } while (true); if (collision) break; // Get the neighbor face at edge e (tright, tleft). senextself(*startsh); // Flip the crossing edge. flipedgerecursive(startsh, flipqueue); // After flip, sorg(*startsh) == tstart. assert(sorg(*startsh) == tstart); } while (sdest(*startsh) != tend); // Insert a subsegment to make the segment permanent. insertsubseg(startsh); // If there was a collision with an interceding vertex, install another // segment connecting that vertex with endpoint2. if (collision) { // Insert the remainder of the segment. if (!scoutsegmentsub(startsh, tend)) { constrainededge(startsh, tend, flipqueue); } } } /////////////////////////////////////////////////////////////////////////////// // // // recoversegment() Recover a segment in the surface triangulation. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::recoversegment(point tstart, point tend, queue* flipqueue) { face searchsh; if (b->verbose > 2) { printf(" Insert seg (%d, %d).\n", pointmark(tstart), pointmark(tend)); } // Find a triangle whose origin is the segment's first endpoint. point2shorg(tstart, searchsh); // Scout the segment and insert it if it is found. if (scoutsegmentsub(&searchsh, tend)) { // The segment was easily inserted. return; } // Insert the segment into the triangulation by flips. constrainededge(&searchsh, tend, flipqueue); // Some edges may need flipping. lawson(flipqueue); } /////////////////////////////////////////////////////////////////////////////// // // // infecthullsub() Virally infect all of the triangles of the convex hull // // that are not protected by subsegments. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::infecthullsub(memorypool* viri) { face hulltri, nexttri, starttri; face hullsubseg; shellface **deadshellface; // Find a triangle handle on the hull. hulltri.sh = dummysh; hulltri.shver = 0; spivotself(hulltri); adjustedgering(hulltri, CCW); // Remember where we started so we know when to stop. starttri = hulltri; // Go once counterclockwise around the convex hull. do { // Ignore triangles that are already infected. if (!sinfected(hulltri)) { // Is the triangle protected by a subsegment? sspivot(hulltri, hullsubseg); if (hullsubseg.sh == dummysh) { // The triangle is not protected; infect it. if (!sinfected(hulltri)) { sinfect(hulltri); deadshellface = (shellface **) viri->alloc(); *deadshellface = hulltri.sh; } } } // To find the next hull edge, go clockwise around the next vertex. senextself(hulltri); spivot(hulltri, nexttri); while (nexttri.sh != dummysh) { if (sorg(nexttri) != sdest(hulltri)) { sesymself(nexttri); } senext(nexttri, hulltri); spivot(hulltri, nexttri); } } while (hulltri != starttri); } /////////////////////////////////////////////////////////////////////////////// // // // plaguesub() Spread the virus from all infected triangles to any // // neighbors not protected by subsegments. Delete all // // infected triangles. // // // // This is the procedure that actually creates holes and concavities. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::plaguesub(memorypool* viri) { face testtri, neighbor, ghostsh; face neighborsubseg; shellface **virusloop; shellface **deadshellface; point *ppt; int i, j; // Loop through all the infected triangles, spreading the virus to // their neighbors, then to their neighbors' neighbors. viri->traversalinit(); virusloop = (shellface **) viri->traverse(); while (virusloop != (shellface **) NULL) { testtri.sh = *virusloop; // Check each of the triangle's three neighbors. for (i = 0; i < 3; i++) { // Find the neighbor. spivot(testtri, neighbor); // Check for a subsegment between the triangle and its neighbor. sspivot(testtri, neighborsubseg); // Check if the neighbor is nonexistent or already infected. if ((neighbor.sh == dummysh) || sinfected(neighbor)) { if (neighborsubseg.sh != dummysh) { // There is a subsegment separating the triangle from its // neighbor, but both triangles are dying, so the subsegment // dies too. shellfacedealloc(subsegs, neighborsubseg.sh); if (neighbor.sh != dummysh) { // Make sure the subsegment doesn't get deallocated again // later when the infected neighbor is visited. ssdissolve(neighbor); } } } else { // The neighbor exists and is not infected. if (neighborsubseg.sh == dummysh) { // There is no subsegment protecting the neighbor, so the // neighbor becomes infected. sinfect(neighbor); // Ensure that the neighbor's neighbors will be infected. deadshellface = (shellface **) viri->alloc(); *deadshellface = neighbor.sh; } else { // The neighbor is protected by a subsegment. // Remove this triangle from the subsegment. ssbond(neighbor, neighborsubseg); // Update the point-to-subface map. 2009-07-21. ppt = (point *) &(neighbor.sh[3]); for (j = 0; j < 3; j++) { setpoint2sh(ppt[j], sencode(neighbor)); } } } senextself(testtri); } virusloop = (shellface **) viri->traverse(); } ghostsh.sh = dummysh; // A handle of outer space. viri->traversalinit(); virusloop = (shellface **) viri->traverse(); while (virusloop != (shellface **) NULL) { testtri.sh = *virusloop; // Record changes in the number of boundary edges, and disconnect // dead triangles from their neighbors. for (i = 0; i < 3; i++) { spivot(testtri, neighbor); if (neighbor.sh != dummysh) { // Disconnect the triangle from its neighbor. // sdissolve(neighbor); sbond(neighbor, ghostsh); } senextself(testtri); } // Return the dead triangle to the pool of triangles. shellfacedealloc(subfaces, testtri.sh); virusloop = (shellface **) viri->traverse(); } // Empty the virus pool. viri->restart(); } /////////////////////////////////////////////////////////////////////////////// // // // carveholessub() Find the holes and infect them. Find the area // // constraints and infect them. Infect the convex hull. // // Spread the infection and kill triangles. Spread the // // area constraints. // // // // This routine mainly calls other routines to carry out all these functions.// // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::carveholessub(int holes, REAL* holelist, memorypool *viri) { face searchtri, triangleloop; shellface **holetri; enum locateresult intersect; int i; // Mark as infected any unprotected triangles on the boundary. // This is one way by which concavities are created. infecthullsub(viri); if (holes > 0) { // Infect each triangle in which a hole lies. for (i = 0; i < 3 * holes; i += 3) { // Ignore holes that aren't within the bounds of the mesh. if ((holelist[i] >= xmin) && (holelist[i] <= xmax) && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax) && (holelist[i + 2] >= zmin) && (holelist[i + 2] <= zmax)) { // Start searching from some triangle on the outer boundary. searchtri.sh = dummysh; // Find a triangle that contains the hole. intersect = locatesub(&holelist[i], &searchtri, 0, 0.0); if ((intersect != OUTSIDE) && (!sinfected(searchtri))) { // Infect the triangle. This is done by marking the triangle // as infected and including the triangle in the virus pool. sinfect(searchtri); holetri = (shellface **) viri->alloc(); *holetri = searchtri.sh; } } } } if (viri->items > 0) { // Carve the holes and concavities. plaguesub(viri); } // The virus pool should be empty now. } /////////////////////////////////////////////////////////////////////////////// // // // triangulate() Triangulate a PSLG into a CDT. // // // // A Planar Straight Line Graph (PSLG) P is actually a 2D polygonal region, // // possibly contains holes, segments and vertices in its interior. P is tri- // // angulated into a set of _subfaces_ forming a CDT of P. // // // // The vertices and segments of P are found in 'ptlist' and 'conlist', resp- // // ectively. 'holelist' contains a list of hole points. 'shmark' will be set // // to all subfaces of P. // // // // The CDT is created directly in the pools 'subfaces' and 'subsegs'. It can // // be retrived by a broadth-first searching starting from 'dummysh[0]'(debug // // function 'outsurfmesh()' does it). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::triangulate(int shmark, REAL eps, list* ptlist, list* conlist, int holes, REAL* holelist, memorypool* viri, queue* flipqueue) { face newsh; point *cons; int i; if (b->verbose > 1) { printf(" %d vertices, %d segments", ptlist->len(), conlist->len()); if (holes > 0) { printf(", %d holes", holes); } printf(", shmark: %d.\n", shmark); } // Create the DT of V by the 2D incremental flip algorithm. if (incrflipdelaunaysub(shmark, eps, ptlist, holes, holelist, flipqueue)) { // Recover boundary edges. if (ptlist->len() > 3) { // Insert segments into the DT. for (i = 0; i < conlist->len(); i++) { cons = (point *)(* conlist)[i]; recoversegment(cons[0], cons[1], flipqueue); } // Carve holes and concavities. carveholessub(holes, holelist, viri); } else if (ptlist->len() == 3) { // Insert 3 segments directly. newsh.sh = dummysh; newsh.shver = 0; spivotself(newsh); for (i = 0; i < 3; i++) { insertsubseg(&newsh); senextself(newsh); } } else if (ptlist->len() == 2) { // This facet is actually a segment. It is not support by the mesh data // strcuture. Hence the segment will not be maintained in the mesh. // However, during segment recovery, the segment can be processed. cons = (point *)(* conlist)[0]; makeshellface(subsegs, &newsh); setsorg(newsh, cons[0]); setsdest(newsh, cons[1]); } } } /////////////////////////////////////////////////////////////////////////////// // // // retrievenewsubs() Retrieve newly created subfaces. // // // // The new subfaces created by triangulate() can be found by a broadth-first // // searching starting from 'dummysh[0]'. // // // // 'newshlist' (empty on input) returns the retrieved subfaces. Each edge on // // the hull is bound to 'dummysh' and protected by a segment. If 'removeseg' // // is TRUE, the segment is removed. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::retrievenewsubs(list* newshlist, bool removeseg) { face startsh, neighsh; face deadseg; int i, j; // The first new subface is found at dummysh[0]. startsh.sh = dummysh; startsh.shver = 0; spivotself(startsh); assert(startsh.sh != dummysh); sinfect(startsh); newshlist->append(&startsh); // Find the rest of new subfaces by a broadth-first searching. for (i = 0; i < newshlist->len(); i++) { // Get a new subface s. startsh = * (face *)(* newshlist)[i]; for (j = 0; j < 3; j++) { spivot(startsh, neighsh); if (neighsh.sh != dummysh) { if (!sinfected(neighsh)) { // Discovered a new subface. sinfect(neighsh); newshlist->append(&neighsh); } } else { // Found a boundary edge. if (removeseg) { // This side of s may be protected by a segment. sspivot(startsh, deadseg); if (deadseg.sh != dummysh) { // Detach it from s. ssdissolve(startsh); // Delete the segment. shellfacedealloc(subsegs, deadseg.sh); } } } senextself(startsh); } } for (i = 0; i < newshlist->len(); i++) { startsh = * (face *)(* newshlist)[i]; suninfect(startsh); } } /////////////////////////////////////////////////////////////////////////////// // // // unifysegments() Unify identical segments and build facet connections. // // // // After creating the surface mesh. Each facet has its own segments. There // // are duplicated segments between adjacent facets. This routine has three // // purposes: // // (1) identify the set of segments which have the same endpoints and // // unify them into one segment, remove redundant ones; // // (2) create the face rings of the unified segments, hence setup the // // connections between facets; and // // (3) set a unique marker (1-based) for each segment. // // On finish, each segment is unique and the face ring around it (right-hand // // rule) is constructed. The connections between facets-facets are setup. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::unifysegments() { list *sfacelist; shellface **facesperverlist; face subsegloop, testseg; face sface, sface1, sface2; point torg, tdest; REAL da1, da2; int *idx2facelist; int segmarker; int idx, k, m; if (b->verbose > 0) { printf(" Unifying segments.\n"); } // Compute a mapping from indices of vertices to subfaces. makesubfacemap(idx2facelist, facesperverlist); // Initialize 'sfacelist' for constructing the face link of each segment. sfacelist = new list(sizeof(face), NULL); segmarker = 1; subsegs->traversalinit(); subsegloop.sh = shellfacetraverse(subsegs); while (subsegloop.sh != (shellface *) NULL) { subsegloop.shver = 0; // For sure. torg = sorg(subsegloop); tdest = sdest(subsegloop); idx = pointmark(torg) - in->firstnumber; // Loop through the set of subfaces containing 'torg'. Get all the // subfaces containing the edge (torg, tdest). Save and order them // in 'sfacelist', the ordering is defined by the right-hand rule // with thumb points from torg to tdest. for (k = idx2facelist[idx]; k < idx2facelist[idx + 1]; k++) { sface.sh = facesperverlist[k]; sface.shver = 0; // sface may be died due to the removing of duplicated subfaces. if (!isdead(&sface) && isfacehasedge(&sface, torg, tdest)) { // 'sface' contains this segment. findedge(&sface, torg, tdest); // Save it in 'sfacelist'. if (sfacelist->len() < 2) { sfacelist->append(&sface); } else { for (m = 0; m < sfacelist->len() - 1; m++) { sface1 = * (face *)(* sfacelist)[m]; sface2 = * (face *)(* sfacelist)[m + 1]; da1 = facedihedral(torg, tdest, sapex(sface1), sapex(sface)); da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2)); if (da1 < da2) { break; // Insert it after m. } } sfacelist->insert(m + 1, &sface); } } } if (b->verbose > 1) { printf(" Identifying %d segments of (%d %d).\n", sfacelist->len(), pointmark(torg), pointmark(tdest)); } // Set the connection between this segment and faces containing it, // at the same time, remove redundant segments. for (k = 0; k < sfacelist->len(); k++) { sface = *(face *)(* sfacelist)[k]; sspivot(sface, testseg); // If 'testseg' is not 'subsegloop', it is a redundant segment that // needs be removed. BE CAREFUL it may already be removed. Do not // remove it twice, i.e., do test 'isdead()' together. if ((testseg.sh != subsegloop.sh) && !isdead(&testseg)) { shellfacedealloc(subsegs, testseg.sh); } // 'ssbond' bonds the subface and the segment together, and dissloves // the old bond as well. ssbond(sface, subsegloop); } // Set connection between these faces. sface = *(face *)(* sfacelist)[0]; if (sfacelist->len() > 1) { for (k = 1; k <= sfacelist->len(); k++) { if (k < sfacelist->len()) { sface1 = *(face *)(* sfacelist)[k]; } else { sface1 = *(face *)(* sfacelist)[0]; // Form a face loop. } // Comment: For detecting invalid PLC, here we could check if the // two subfaces "sface" and "sface1" are identical (skipped). if (b->verbose > 2) { printf(" Bond subfaces (%d, %d, %d) and (%d, %d, %d).\n", pointmark(torg), pointmark(tdest), pointmark(sapex(sface)), pointmark(torg), pointmark(tdest), pointmark(sapex(sface1))); } sbond1(sface, sface1); sface = sface1; } } else { // This segment belongs to only on subface. sdissolve(sface); } // Set the unique segment marker into the unified segment. setshellmark(subsegloop, segmarker); // Increase the marker. segmarker++; // Clear the working list. sfacelist->clear(); subsegloop.sh = shellfacetraverse(subsegs); } delete [] idx2facelist; delete [] facesperverlist; delete sfacelist; } /////////////////////////////////////////////////////////////////////////////// // // // assignsegmentmarkers() Assign markers given in "in->edgemarkerlist". // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::assignsegmentmarkers() { shellface **segsperverlist; face sseg; bool isseg; int *idx2seglist; int end1, end2, tend1, tend2; int index, i, j; if (b->verbose > 0) { printf(" Assigning segment markers.\n"); } assert(in->edgemarkerlist != NULL); makesegmentmap(idx2seglist, segsperverlist); for (i = 0; i < in->numberofedges; i++) { end1 = in->edgelist[i * 2]; end2 = in->edgelist[i * 2 + 1]; index = end1 - in->firstnumber; for (j = idx2seglist[index]; j < idx2seglist[index + 1]; j++) { sseg.sh = segsperverlist[j]; sseg.shver = 0; isseg = false; tend1 = pointmark(sorg(sseg)); tend2 = pointmark(sdest(sseg)); if (tend1 == end1) { if (tend2 == end2) isseg = true; } else if (tend1 == end2) { if (tend2 == end1) isseg = true; } if (isseg) { setshellmark(sseg, in->edgemarkerlist[i]); break; } } } delete [] idx2seglist; delete [] segsperverlist; } /////////////////////////////////////////////////////////////////////////////// // // // mergefacets() Merge adjacent facets to be one facet if they are // // coplanar and have the same boundary marker. // // // // Segments between two merged facets will be removed from the mesh. If all // // segments around a vertex have been removed, change its vertex type to be // // FREESUBVERTEX. Edge flips will be performed to ensure the Delaunayness of // // the triangulation of merged facets. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::mergefacets(queue* flipqueue) { face parentsh, neighsh, neineighsh; face segloop; point eorg, edest; REAL ori; bool mergeflag, pbcflag; int* segspernodelist; int fidx1, fidx2; int i, j; if (b->verbose > 0) { printf(" Merging coplanar facets.\n"); } // Create and initialize 'segspernodelist'. segspernodelist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) segspernodelist[i] = 0; // Loop the segments, counter the number of segments sharing each vertex. subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { // Increment the number of sharing segments for each endpoint. for (i = 0; i < 2; i++) { j = pointmark((point) segloop.sh[3 + i]); segspernodelist[j]++; } segloop.sh = shellfacetraverse(subsegs); } // Loop the segments, find out dead segments. subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { eorg = sorg(segloop); edest = sdest(segloop); spivot(segloop, parentsh); if (parentsh.sh != dummysh) { // This segment is not dangling. spivot(parentsh, neighsh); if (neighsh.sh != dummysh) { // This segment belongs to at least two facets. spivot(neighsh, neineighsh); if ((parentsh.sh != neighsh.sh) && (parentsh.sh == neineighsh.sh)) { // Exactly two subfaces at this segment. fidx1 = shellmark(parentsh) - 1; fidx2 = shellmark(neighsh) - 1; pbcflag = false; if (checkpbcs) { pbcflag = (shellpbcgroup(parentsh) >= 0) || (shellpbcgroup(neighsh) >= 0); } // Possibly merge them if they are not in the same facet. if ((fidx1 != fidx2) && !pbcflag) { // Test if they are coplanar. ori = orient3d(eorg, edest, sapex(parentsh), sapex(neighsh)); if (ori != 0.0) { if (iscoplanar(eorg, edest, sapex(parentsh), sapex(neighsh), ori, b->epsilon)) { ori = 0.0; // They are assumed as coplanar. } } if (ori == 0.0) { mergeflag = (in->facetmarkerlist == (int *) NULL || in->facetmarkerlist[fidx1] == in->facetmarkerlist[fidx2]); if (mergeflag) { // This segment becomes dead. if (b->verbose > 1) { printf(" Removing segment (%d, %d).\n", pointmark(eorg), pointmark(edest)); } ssdissolve(parentsh); ssdissolve(neighsh); shellfacedealloc(subsegs, segloop.sh); j = pointmark(eorg); segspernodelist[j]--; if (segspernodelist[j] == 0) { setpointtype(eorg, FREESUBVERTEX); } j = pointmark(edest); segspernodelist[j]--; if (segspernodelist[j] == 0) { setpointtype(edest, FREESUBVERTEX); } // Add 'parentsh' to queue checking for flip. enqueueflipedge(parentsh, flipqueue); } } } } } // neighsh.sh != dummysh } // parentsh.sh != dummysh segloop.sh = shellfacetraverse(subsegs); } if (!flipqueue->empty()) { // Restore the Delaunay property in the facet triangulation. lawson(flipqueue); } delete [] segspernodelist; } /////////////////////////////////////////////////////////////////////////////// // // // meshsurface() Create the surface mesh of a PLC. // // // // Let X be the PLC, the surface mesh S of X consists of triangulated facets.// // S is created mainly in the following steps: // // // // (1) Form the CDT of each facet of X separately (by routine triangulate()).// // After it is done, the subfaces of each facet are connected to each other, // // however there is no connection between facets yet. Notice each facet has // // its own segments, some of them are duplicated. // // // // (2) Remove the redundant segments created in step (1) (by routine unify- // // segment()). The subface ring of each segment is created, the connection // // between facets are established as well. // // // // The return value indicates the number of segments of X. // // // /////////////////////////////////////////////////////////////////////////////// long tetgenmesh::meshsurface() { list *ptlist, *conlist; queue *flipqueue; tetgenio::facet *f; tetgenio::polygon *p; memorypool *viri; point *idx2verlist; point tstart, tend, *cons; int *worklist; int end1, end2; int shmark, i, j; if (!b->quiet) { printf("Creating surface mesh.\n"); } // Compute a mapping from indices to points. makeindex2pointmap(idx2verlist); // // Compute a mapping from points to tets for computing abovepoints. // makepoint2tetmap(); // Initialize 'facetabovepointarray'. facetabovepointarray = new point[in->numberoffacets + 1]; for (i = 0; i < in->numberoffacets + 1; i++) { facetabovepointarray[i] = (point) NULL; } if (checkpbcs) { // Initialize the global array 'subpbcgrouptable'. // createsubpbcgrouptable(); } // Initialize working lists. viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0); flipqueue = new queue(sizeof(badface)); ptlist = new list(sizeof(point *), NULL, 256); conlist = new list(sizeof(point *) * 2, NULL, 256); worklist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) worklist[i] = 0; caveshlist = new arraypool(sizeof(face), 10); caveshbdlist = new arraypool(sizeof(face), 10); // Loop the facet list, triangulate each facet. On finish, all subfaces // are in 'subfaces', all segments are in 'subsegs'. Notice: there're // redundant segments. Remember: All facet indices count from 1. for (shmark = 1; shmark <= in->numberoffacets; shmark++) { // Get a facet F. f = &in->facetlist[shmark - 1]; // Process the duplicated points first, they are marked with type // DUPLICATEDVERTEX by incrflipdelaunay(). Let p and q are dup. // and the index of p is larger than q's, p is substituted by q. // In a STL mesh, duplicated points are implicitly included. if ((b->object == tetgenbehavior::STL) || dupverts) { // Loop all polygons of this facet. for (i = 0; i < f->numberofpolygons; i++) { p = &(f->polygonlist[i]); // Loop other vertices of this polygon. for (j = 0; j < p->numberofvertices; j++) { end1 = p->vertexlist[j]; tstart = idx2verlist[end1 - in->firstnumber]; if (pointtype(tstart) == DUPLICATEDVERTEX) { // Reset the index of vertex-j. tend = point2ppt(tstart); end2 = pointmark(tend); p->vertexlist[j] = end2; } } } } // Loop polygons of F, get the set V of vertices and S of segments. for (i = 0; i < f->numberofpolygons; i++) { // Get a polygon. p = &(f->polygonlist[i]); // Get the first vertex. end1 = p->vertexlist[0]; if ((end1 < in->firstnumber) || (end1 >= in->firstnumber + in->numberofpoints)) { if (!b->quiet) { printf("Warning: Invalid the 1st vertex %d of polygon", end1); printf(" %d in facet %d.\n", i + 1, shmark); } continue; // Skip this polygon. } tstart = idx2verlist[end1 - in->firstnumber]; // Add tstart to V if it haven't been added yet. if (worklist[end1] == 0) { ptlist->append(&tstart); worklist[end1] = 1; } // Loop other vertices of this polygon. for (j = 1; j <= p->numberofvertices; j++) { // get a vertex. if (j < p->numberofvertices) { end2 = p->vertexlist[j]; } else { end2 = p->vertexlist[0]; // Form a loop from last to first. } if ((end2 < in->firstnumber) || (end2 >= in->firstnumber + in->numberofpoints)) { if (!b->quiet) { printf("Warning: Invalid vertex %d in polygon %d", end2, i + 1); printf(" in facet %d.\n", shmark); } } else { if (end1 != end2) { // 'end1' and 'end2' form a segment. tend = idx2verlist[end2 - in->firstnumber]; // Add tstart to V if it haven't been added yet. if (worklist[end2] == 0) { ptlist->append(&tend); worklist[end2] = 1; } // Save the segment in S (conlist). cons = (point *) conlist->append(NULL); cons[0] = tstart; cons[1] = tend; // Set the start for next continuous segment. end1 = end2; tstart = tend; } else { // Two identical vertices represent an isolated vertex of F. if (p->numberofvertices > 2) { // This may be an error in the input, anyway, we can continue // by simply skipping this segment. if (!b->quiet) { printf("Warning: Polygon %d has two identical verts", i + 1); printf(" in facet %d.\n", shmark); } } // Ignore this vertex. } } // Is the polygon degenerate (a segment or a vertex)? if (p->numberofvertices == 2) break; } } // Unmark vertices. for (i = 0; i < ptlist->len(); i++) { tstart = * (point *)(* ptlist)[i]; end1 = pointmark(tstart); assert(worklist[end1] == 1); worklist[end1] = 0; } // Create a CDT of F. triangulate(shmark, b->epsilon * 1e+2, ptlist, conlist, f->numberofholes, f->holelist, viri, flipqueue); // Clear working lists. ptlist->clear(); conlist->clear(); viri->restart(); } delete caveshlist; delete caveshbdlist; caveshlist = NULL; caveshbdlist = NULL; // Unify segments in 'subsegs', remove redundant segments. Face links // of segments are also built. unifysegments(); /*if (in->numberofedges > 0) { if (in->edgemarkerlist != NULL) { assignsegmentmarkers(); } }*/ // Remember the number of input segments (for output). insegments = subsegs->items; if (checkpbcs) { // Create the global array 'segpbcgrouptable'. // createsegpbcgrouptable(); } if (b->object == tetgenbehavior::STL) { // Remove redundant vertices (for .stl input mesh). jettisonnodes(); } if (!b->nomerge && !b->nobisect && !checkpbcs) { // No '-M' switch - merge adjacent facets if they are coplanar. mergefacets(flipqueue); } // Create the point-to-segment map. makepoint2segmap(); delete [] idx2verlist; delete [] worklist; delete ptlist; delete conlist; delete flipqueue; delete viri; return subsegs->items; } /////////////////////////////////////////////////////////////////////////////// // // // interecursive() Recursively do intersection test on a set of triangles.// // // // Recursively split the set 'subfacearray' of subfaces into two sets using // // a cut plane parallel to x-, or, y-, or z-axies. The split criteria are // // follows. Assume the cut plane is H, and H+ denotes the left halfspace of // // H, and H- denotes the right halfspace of H; and s be a subface: // // // // (1) If all points of s lie at H+, put it into left array; // // (2) If all points of s lie at H-, put it into right array; // // (3) If some points of s lie at H+ and some of lie at H-, or some // // points lie on H, put it into both arraies. // // // // Partitions by x-axis if axis == '0'; by y-axis if axis == '1'; by z-axis // // if axis == '2'. If current cut plane is parallel to the x-axis, the next // // one will be parallel to y-axis, and the next one after the next is z-axis,// // and then alternately return back to x-axis. // // // // Stop splitting when the number of triangles of the input array is not // // decreased anymore. Do tests on the current set. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh:: interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax, int* internum) { shellface **leftarray, **rightarray; face sface1, sface2; point p1, p2, p3; point p4, p5, p6; enum interresult intersect; REAL split; bool toleft, toright; int leftsize, rightsize; int i, j; if (b->verbose > 1) { printf(" Recur %d faces. Bbox (%g, %g, %g),(%g, %g, %g). %s-axis\n", arraysize, bxmin, bymin, bzmin, bxmax, bymax, bzmax, axis == 0 ? "x" : (axis == 1 ? "y" : "z")); } leftarray = new shellface*[arraysize]; if (leftarray == NULL) { terminatetetgen(1); } rightarray = new shellface*[arraysize]; if (rightarray == NULL) { terminatetetgen(1); } leftsize = rightsize = 0; if (axis == 0) { // Split along x-axis. split = 0.5 * (bxmin + bxmax); } else if (axis == 1) { // Split along y-axis. split = 0.5 * (bymin + bymax); } else { // Split along z-axis. split = 0.5 * (bzmin + bzmax); } for (i = 0; i < arraysize; i++) { sface1.sh = subfacearray[i]; p1 = (point) sface1.sh[3]; p2 = (point) sface1.sh[4]; p3 = (point) sface1.sh[5]; toleft = toright = false; if (p1[axis] < split) { toleft = true; if (p2[axis] >= split || p3[axis] >= split) { toright = true; } } else if (p1[axis] > split) { toright = true; if (p2[axis] <= split || p3[axis] <= split) { toleft = true; } } else { // p1[axis] == split; toleft = true; toright = true; } // At least one is true; #ifdef SELF_CHECK assert(!(toleft == false && toright == false)); #endif if (toleft) { leftarray[leftsize] = sface1.sh; leftsize++; } if (toright) { rightarray[rightsize] = sface1.sh; rightsize++; } } if (leftsize < arraysize && rightsize < arraysize) { // Continue to partition the input set. Now 'subfacearray' has been // split into two sets, it's memory can be freed. 'leftarray' and // 'rightarray' will be freed in the next recursive (after they're // partitioned again or performing tests). delete [] subfacearray; // Continue to split these two sets. if (axis == 0) { interecursive(leftarray, leftsize, 1, bxmin, split, bymin, bymax, bzmin, bzmax, internum); interecursive(rightarray, rightsize, 1, split, bxmax, bymin, bymax, bzmin, bzmax, internum); } else if (axis == 1) { interecursive(leftarray, leftsize, 2, bxmin, bxmax, bymin, split, bzmin, bzmax, internum); interecursive(rightarray, rightsize, 2, bxmin, bxmax, split, bymax, bzmin, bzmax, internum); } else { interecursive(leftarray, leftsize, 0, bxmin, bxmax, bymin, bymax, bzmin, split, internum); interecursive(rightarray, rightsize, 0, bxmin, bxmax, bymin, bymax, split, bzmax, internum); } } else { if (b->verbose > 1) { printf(" Checking intersecting faces.\n"); } // Perform a brute-force compare on the set. for (i = 0; i < arraysize; i++) { sface1.sh = subfacearray[i]; p1 = (point) sface1.sh[3]; p2 = (point) sface1.sh[4]; p3 = (point) sface1.sh[5]; for (j = i + 1; j < arraysize; j++) { sface2.sh = subfacearray[j]; p4 = (point) sface2.sh[3]; p5 = (point) sface2.sh[4]; p6 = (point) sface2.sh[5]; intersect = tri_tri_inter(p1, p2, p3, p4, p5, p6); if (intersect == INTERSECT || intersect == SHAREFACE) { if (!b->quiet) { if (intersect == INTERSECT) { printf(" Facet #%d intersects facet #%d at triangles:\n", shellmark(sface1), shellmark(sface2)); printf(" (%4d, %4d, %4d) and (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4), pointmark(p5), pointmark(p6)); } else { printf(" Facet #%d duplicates facet #%d at triangle:\n", shellmark(sface1), shellmark(sface2)); printf(" (%4d, %4d, %4d)\n", pointmark(p1), pointmark(p2), pointmark(p3)); } } // Increase the number of intersecting pairs. (*internum)++; // Infect these two faces (although they may already be infected). sinfect(sface1); sinfect(sface2); } } } // Don't forget to free all three arrays. No further partition. delete [] leftarray; delete [] rightarray; delete [] subfacearray; } } /////////////////////////////////////////////////////////////////////////////// // // // detectinterfaces() Detect intersecting triangles. // // // // Given a set of triangles, find the pairs of intersecting triangles from // // them. Here the set of triangles is in 'subfaces' which is a surface mesh // // of a PLC (.poly or .smesh). // // // // To detect whether two triangles are intersecting is done by the routine // // 'tri_tri_inter()'. The algorithm for the test is very simple and stable. // // It is based on geometric orientation test which uses exact arithmetics. // // // // Use divide-and-conquer algorithm for reducing the number of intersection // // tests. Start from the bounding box of the input point set, recursively // // partition the box into smaller boxes, until the number of triangles in a // // box is not decreased anymore. Then perform triangle-triangle tests on the // // remaining set of triangles. The memory allocated in the input set is // // freed immediately after it has been partitioned into two arrays. So it // // can be re-used for the consequent partitions. // // // // On return, the pool 'subfaces' will be cleared, and only the intersecting // // triangles remain for output (to a .face file). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::detectinterfaces() { shellface **subfacearray; face shloop; int internum; int i; if (!b->quiet) { printf("Detecting intersecting facets.\n"); } // Construct a map from indices to subfaces; subfacearray = new shellface*[subfaces->items]; subfaces->traversalinit(); shloop.sh = shellfacetraverse(subfaces); i = 0; while (shloop.sh != (shellface *) NULL) { subfacearray[i] = shloop.sh; shloop.sh = shellfacetraverse(subfaces); i++; } internum = 0; // Recursively split the set of triangles into two sets using a cut plane // parallel to x-, or, y-, or z-axies. Stop splitting when the number // of subfaces is not decreasing anymore. Do tests on the current set. interecursive(subfacearray, subfaces->items, 0, xmin, xmax, ymin, ymax, zmin, zmax, &internum); if (!b->quiet) { if (internum > 0) { printf("\n!! Found %d pairs of faces are intersecting.\n\n", internum); } else { printf("\nNo faces are intersecting.\n\n"); } } if (internum > 0) { // Traverse all subfaces, deallocate those have not been infected (they // are not intersecting faces). Uninfect those have been infected. // After this loop, only intersecting faces remain. subfaces->traversalinit(); shloop.sh = shellfacetraverse(subfaces); while (shloop.sh != (shellface *) NULL) { if (sinfected(shloop)) { suninfect(shloop); } else { shellfacedealloc(subfaces, shloop.sh); } shloop.sh = shellfacetraverse(subfaces); } } else { // Deallocate all subfaces. subfaces->restart(); } } //// //// //// //// //// surface_cxx ////////////////////////////////////////////////////////////// //// constrained_cxx ////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // markacutevertices() Mark acute vertices. // // // // A vertex v is called acute if there are two segments sharing at v forming // // an acute angle (i.e. smaller than 90 degree). // // // // This routine finds all acute vertices in the PLC and marks them as point- // // type ACUTEVERTEX. The other vertices of segments which are non-acute will // // be marked as NACUTEVERTEX. Vertices which are not endpoints of segments // // (such as DUPLICATEDVERTEX, UNUSEDVERTEX, etc) are not infected. // // // // NOTE: This routine should be called before Steiner points are introduced. // // That is, no point has type like FREESEGVERTEX, etc. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::markacutevertices(REAL acuteangle) { shellface **segsperverlist; face segloop, nextseg; point pointloop, edest, eapex; REAL cosbound, anglearc; REAL v1[3], v2[3], L, D; bool isacute; int *idx2seglist; int acutecount; int idx, i, j, k; if (b->verbose > 0) { printf(" Marking acute vertices.\n"); } anglearc = acuteangle * PI / 180.0; cosbound = cos(anglearc); acutecount = 0; // Constructing a map from vertex to segments. makesegmentmap(idx2seglist, segsperverlist); // Loop over the set of vertices. points->traversalinit(); pointloop = pointtraverse(); while (pointloop != (point) NULL) { idx = pointmark(pointloop) - in->firstnumber; // Only do test if p is an endpoint of some segments. if (idx2seglist[idx + 1] > idx2seglist[idx]) { // Init p to be non-acute. setpointtype(pointloop, NACUTEVERTEX); isacute = false; // Loop through all segments sharing at p. for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isacute; i++) { segloop.sh = segsperverlist[i]; // segloop.shver = 0; if (sorg(segloop) != pointloop) sesymself(segloop); edest = sdest(segloop); for (j = i + 1; j < idx2seglist[idx + 1] && !isacute; j++) { nextseg.sh = segsperverlist[j]; // nextseg.shver = 0; if (sorg(nextseg) != pointloop) sesymself(nextseg); eapex = sdest(nextseg); // Check the angle formed by segs (p, edest) and (p, eapex). for (k = 0; k < 3; k++) { v1[k] = edest[k] - pointloop[k]; v2[k] = eapex[k] - pointloop[k]; } L = sqrt(v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2]); for (k = 0; k < 3; k++) v1[k] /= L; L = sqrt(v2[0] * v2[0] + v2[1] * v2[1] + v2[2] * v2[2]); for (k = 0; k < 3; k++) v2[k] /= L; D = v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; // Is D acute? isacute = (D >= cosbound); } } if (isacute) { // Mark p to be acute. setpointtype(pointloop, ACUTEVERTEX); acutecount++; } } pointloop = pointtraverse(); } delete [] idx2seglist; delete [] segsperverlist; if ((b->verbose > 0) && (acutecount > 0)) { printf(" %d acute vertices.\n", acutecount); } } /////////////////////////////////////////////////////////////////////////////// // // // finddirection() Find the first tetrahedron on the path from one point // // to another. // // // // Find the tetrahedron that intersects a line segment L (from the origin of // // 'searchtet' to the point 'tend'), and returns the result in 'searchtet'. // // The origin of 'searchtet' does not change, even though the tetrahedron // // returned may differ from the one passed in. This routine is used to find // // the direction to move in to get from one point to another. // // // // The return value notes the location of the line segment L with respect to // // 'searchtet': // // - Returns RIGHTCOLLINEAR indicates L is collinear with the line segment // // from the origin to the destination of 'searchtet'. // // - Returns LEFTCOLLINEAR indicates L is collinear with the line segment // // from the origin to the apex of 'searchtet'. // // - Returns TOPCOLLINEAR indicates L is collinear with the line segment // // from the origin to the opposite of 'searchtet'. // // - Returns ACROSSEDGE indicates L intersects with the line segment from // // the destination to the apex of 'searchtet'. // // - Returns ACROSSFACE indicates L intersects with the face opposite to // // the origin of 'searchtet'. // // - Returns BELOWHULL indicates L crosses outside the mesh domain. This // // can only happen when the domain is non-convex. // // // // NOTE: This routine only works correctly when the mesh is exactly Delaunay.// // // // If 'maxtetnumber' > 0, stop the searching process if the number of passed // // tets is larger than it. Return BELOWHULL. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::finddirectionresult tetgenmesh:: finddirection(triface *searchtet, point tend, long maxtetnumber) { triface neightet; point tstart, tdest, tapex, toppo; REAL ori1, ori2, ori3; long tetnumber; tstart = org(*searchtet); #ifdef SELF_CHECK assert(tstart != tend); #endif adjustedgering(*searchtet, CCW); if (tstart != org(*searchtet)) { enextself(*searchtet); // For keeping the same origin. } tdest = dest(*searchtet); if (tdest == tend) { return RIGHTCOLLINEAR; } tapex = apex(*searchtet); if (tapex == tend) { return LEFTCOLLINEAR; } ori1 = orient3d(tstart, tdest, tapex, tend); if (ori1 > 0.0) { // 'tend' is below the face, get the neighbor of this side. sym(*searchtet, neightet); if (neightet.tet != dummytet) { findorg(&neightet, tstart); adjustedgering(neightet, CCW); if (org(neightet) != tstart) { enextself(neightet); // keep the same origin. } // Set the changed configuratiuon. *searchtet = neightet; ori1 = -1.0; tdest = dest(*searchtet); tapex = apex(*searchtet); } else { // A hull face. Only possible for a nonconvex mesh. #ifdef SELF_CHECK assert(nonconvex); #endif return BELOWHULL; } } // Repeatedly change the 'searchtet', remain 'tstart' be its origin, until // find a tetrahedron contains 'tend' or is crossed by the line segment // from 'tstart' to 'tend'. tetnumber = 0l; while ((maxtetnumber > 0) && (tetnumber <= maxtetnumber)) { tetnumber++; toppo = oppo(*searchtet); if (toppo == tend) { return TOPCOLLINEAR; } ori2 = orient3d(tstart, toppo, tdest, tend); if (ori2 > 0.0) { // 'tend' is below the face, get the neighbor at this side. fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { findorg(&neightet, tstart); adjustedgering(neightet, CCW); if (org(neightet) != tstart) { enextself(neightet); // keep the same origin. } // Set the changed configuration. *searchtet = neightet; ori1 = -1.0; tdest = dest(*searchtet); tapex = apex(*searchtet); // Continue the search from the changed 'searchtet'. continue; } else { // A hull face. Only possible for a nonconvex mesh. #ifdef SELF_CHECK assert(nonconvex); #endif return BELOWHULL; } } ori3 = orient3d(tapex, toppo, tstart, tend); if (ori3 > 0.0) { // 'tend' is below the face, get the neighbor at this side. enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { findorg(&neightet, tstart); adjustedgering(neightet, CCW); if (org(neightet) != tstart) { enextself(neightet); // keep the same origin. } // Set the changed configuration. *searchtet = neightet; ori1 = -1.0; tdest = dest(*searchtet); tapex = apex(*searchtet); // Continue the search from the changed 'searchtet'. continue; } else { // A hull face. Only possible for a nonconvex mesh. #ifdef SELF_CHECK assert(nonconvex); #endif return BELOWHULL; } } // Now 'ori1', 'ori2' and 'ori3' are possible be 0.0 or all < 0.0; if (ori1 < 0.0) { // Possible cases are: ACROSSFACE, ACROSSEDGE, TOPCOLLINEAR. if (ori2 < 0.0) { if (ori3 < 0.0) { return ACROSSFACE; } else { // ori3 == 0.0; // Cross edge (apex, oppo) enext2fnextself(*searchtet); esymself(*searchtet); // org(*searchtet) == tstart; return ACROSSEDGE; } } else { // ori2 == 0.0; if (ori3 < 0.0) { // Cross edge (dest, oppo) fnextself(*searchtet); esymself(*searchtet); enextself(*searchtet); // org(*searchtet) == tstart; return ACROSSEDGE; } else { // ori3 == 0.0; // Collinear with edge (org, oppo) return TOPCOLLINEAR; } } } else { // ori1 == 0.0; // Possible cases are: RIGHTCOLLINEAR, LEFTCOLLINEAR, ACROSSEDGE. if (ori2 < 0.0) { if (ori3 < 0.0) { // Cross edge (tdest, tapex) return ACROSSEDGE; } else { // ori3 == 0.0 // Collinear with edge (torg, tapex) return LEFTCOLLINEAR; } } else { // ori2 == 0.0; #ifdef SELF_CHECK assert(ori3 != 0.0); #endif // Collinear with edge (torg, tdest) return RIGHTCOLLINEAR; } } } // Loop breakout. It may happen when the mesh is non-Delaunay. return BELOWHULL; } /////////////////////////////////////////////////////////////////////////////// // // // finddirection() Find the tet on the path from one point to another. // // // // The path starts from 'searchtet''s origin and ends at 'endpt'. On finish, // // 'searchtet' contains a tet on the path, its origin does not change. // // // // The return value indicates one of the following cases (let 'searchtet' be // // abcd, a is the origin of the path): // // - ACROSSVERT, edge ab is collinear with the path; // // - ACROSSEDGE, edge bc intersects with the path; // // - ACROSSFACE, face bcd intersects with the path. // // // // WARNING: This routine is designed for convex triangulations, and will not // // generally work after the holes and concavities have been carved. // // - BELOWHULL2, the mesh is non-convex and the searching for the path has // // got stucked at a non-convex boundary face. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::finddirection2(triface* searchtet, point endpt) { triface neightet; point pa, pb, pc, pd, pn; enum {HMOVE, RMOVE, LMOVE} nextmove; enum {HCOPLANE, RCOPLANE, LCOPLANE, NCOPLANE} cop; REAL hori, rori, lori; REAL dmin, dist; assert((searchtet->tet != NULL) && (searchtet->tet != dummytet)); // The origin is fixed. pa = org(*searchtet); if (searchtet->ver & 01) { // Switch to the 0th edge ring. esymself(*searchtet); enextself(*searchtet); } pb = dest(*searchtet); if (pb == endpt) { // pa->pb is the search edge. return INTERVERT; } pc = apex(*searchtet); if (pc == endpt) { // pa->pc is the search edge. enext2self(*searchtet); esymself(*searchtet); return INTERVERT; } // Walk through tets at pa until the right one is found. while (1) { pd = oppo(*searchtet); if (b->verbose > 2) { printf(" From tet (%d, %d, %d, %d) to %d.\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd), pointmark(endpt)); } // Check whether the opposite vertex is 'endpt'. if (pd == endpt) { // pa->pd is the search edge. fnextself(*searchtet); enext2self(*searchtet); esymself(*searchtet); return INTERVERT; } // Now assume that the base face abc coincides with the horizon plane, // and d lies above the horizon. The search point 'endpt' may lie // above or below the horizon. We test the orientations of 'endpt' // with respect to three planes: abc (horizon), bad (right plane), // and acd (left plane). hori = orient3d(pa, pb, pc, endpt); rori = orient3d(pb, pa, pd, endpt); lori = orient3d(pa, pc, pd, endpt); orient3dcount += 3; // Now decide the tet to move. It is possible there are more than one // tet are viable moves. Use the opposite points of thier neighbors // to discriminate, i.e., we choose the tet whose opposite point has // the shortest distance to 'endpt'. if (hori > 0) { if (rori > 0) { if (lori > 0) { // Any of the three neighbors is a viable move. nextmove = HMOVE; sym(*searchtet, neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dist = dmin; } if (dist < dmin) { nextmove = RMOVE; dmin = dist; } enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dist = dmin; } if (dist < dmin) { nextmove = LMOVE; dmin = dist; } } else { // Two tets, below horizon and below right, are viable. nextmove = HMOVE; sym(*searchtet, neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dist = dmin; } if (dist < dmin) { nextmove = RMOVE; dmin = dist; } } } else { if (lori > 0) { // Two tets, below horizon and below left, are viable. nextmove = HMOVE; sym(*searchtet, neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dist = dmin; } if (dist < dmin) { nextmove = LMOVE; dmin = dist; } } else { // The tet below horizon is chosen. nextmove = HMOVE; } } } else { if (rori > 0) { if (lori > 0) { // Two tets, below right and below left, are viable. nextmove = RMOVE; fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dmin = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dmin = NORM2(xmax - xmin, ymax - ymin, zmax - zmin); } enext2fnext(*searchtet, neightet); symself(neightet); if (neightet.tet != dummytet) { pn = oppo(neightet); dist = NORM2(endpt[0] - pn[0], endpt[1] - pn[1], endpt[2] - pn[2]); } else { dist = dmin; } if (dist < dmin) { nextmove = LMOVE; dmin = dist; } } else { // The tet below right is chosen. nextmove = RMOVE; } } else { if (lori > 0) { // The tet below left is chosen. nextmove = LMOVE; } else { // 'endpt' lies either on the plane(s) or across face bcd. if (hori == 0) { if (rori == 0) { // pa->'endpt' is COLLINEAR with pa->pb. return INTERVERT; } if (lori == 0) { // pa->'endpt' is COLLINEAR with pa->pc. enext2self(*searchtet); esymself(*searchtet); return INTERVERT; } // pa->'endpt' crosses the edge pb->pc. // enextself(*searchtet); // return INTEREDGE; cop = HCOPLANE; break; } if (rori == 0) { if (lori == 0) { // pa->'endpt' is COLLINEAR with pa->pd. fnextself(*searchtet); // face abd. enext2self(*searchtet); esymself(*searchtet); return INTERVERT; } // pa->'endpt' crosses the edge pb->pd. // fnextself(*searchtet); // face abd. // enextself(*searchtet); // return INTEREDGE; cop = RCOPLANE; break; } if (lori == 0) { // pa->'endpt' crosses the edge pc->pd. // enext2fnextself(*searchtet); // face cad // enext2self(*searchtet); // return INTEREDGE; cop = LCOPLANE; break; } // pa->'endpt' crosses the face bcd. // enextfnextself(*searchtet); // return INTERFACE; cop = NCOPLANE; break; } } } // Move to the next tet, fix pa as its origin. if (nextmove == RMOVE) { tfnextself(*searchtet); } else if (nextmove == LMOVE) { enext2self(*searchtet); tfnextself(*searchtet); enextself(*searchtet); } else { // HMOVE symedgeself(*searchtet); enextself(*searchtet); } // Assume convex case, we should not move to outside. if (searchtet->tet == dummytet) { // This should only happen when the domain is non-convex. return BELOWHULL2; } assert(org(*searchtet) == pa); // SELF_CHECK pb = dest(*searchtet); pc = apex(*searchtet); } // while (1) // Either case INTEREDGE or INTERFACE. /*if (b->epsilon > 0) { // Use tolerance to re-evaluate the orientations. if (cop != HCOPLANE) { if (iscoplanar(pa, pb, pc, endpt, hori)) hori = 0; } if (cop != RCOPLANE) { if (iscoplanar(pb, pa, pd, endpt, rori)) rori = 0; } if (cop != LCOPLANE) { if (iscoplanar(pa, pc, pd, endpt, lori)) lori = 0; } // It is not possible that all orientations are zero. assert(!((hori == 0) && (rori == 0) && (lori == 0))); // SELF_CHECK }*/ // Now decide the degenerate cases. if (hori == 0) { if (rori == 0) { // pa->'endpt' is COLLINEAR with pa->pb. return INTERVERT; } if (lori == 0) { // pa->'endpt' is COLLINEAR with pa->pc. enext2self(*searchtet); esymself(*searchtet); return INTERVERT; } // pa->'endpt' crosses the edge pb->pc. return INTEREDGE; } if (rori == 0) { if (lori == 0) { // pa->'endpt' is COLLINEAR with pa->pd. fnextself(*searchtet); // face abd. enext2self(*searchtet); esymself(*searchtet); return INTERVERT; } // pa->'endpt' crosses the edge pb->pd. fnextself(*searchtet); // face abd. esymself(*searchtet); enextself(*searchtet); return INTEREDGE; } if (lori == 0) { // pa->'endpt' crosses the edge pc->pd. enext2fnextself(*searchtet); // face cad esymself(*searchtet); return INTEREDGE; } // pa->'endpt' crosses the face bcd. return INTERFACE; } /////////////////////////////////////////////////////////////////////////////// // // // finddirection3() Used when finddirection2() returns BELOWHULL2. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::finddirection3(triface* searchtet, point endpt) { arraypool *startetlist; triface *parytet, oppoface, neightet; point startpt, pa, pb, pc; enum interresult dir; int types[2], poss[4]; int pos, i, j; startetlist = new arraypool(sizeof(triface), 8); startpt = org(*searchtet); infect(*searchtet); startetlist->newindex((void **) &parytet); *parytet = *searchtet; if (b->verbose > 1) { printf(" Search path (%d, %d) under non-convexity.\n", pointmark(startpt), pointmark(endpt)); } for (i = 0; i < (int) startetlist->objects; i++) { parytet = (triface *) fastlookup(startetlist, i); *searchtet = *parytet; // assert(org(*searchtet) == startpt); adjustedgering(*searchtet, CCW); if (org(*searchtet) != startpt) { enextself(*searchtet); assert(org(*searchtet) == startpt); } // Go to the opposite face of startpt. enextfnext(*searchtet, oppoface); esymself(oppoface); pa = org(oppoface); pb = dest(oppoface); pc = apex(oppoface); // Check if face [a, b, c] intersects the searching path. if (tri_edge_test(pa, pb, pc, startpt, endpt, NULL, 1, types, poss)) { // They intersect. Get the type of intersection. dir = (enum interresult) types[0]; pos = poss[0]; break; } else { dir = DISJOINT; } // Get the neighbor tets. for (j = 0; j < 3; j++) { if (j == 0) { symedge(*searchtet, neightet); } else if (j == 1) { fnext(*searchtet, neightet); symedgeself(neightet); } else { enext2fnext(*searchtet, neightet); symedgeself(neightet); } if (neightet.tet != dummytet) { if (!infected(neightet)) { if (org(neightet) != startpt) esymself(neightet); infect(neightet); startetlist->newindex((void **) &parytet); *parytet = neightet; } } } } for (i = 0; i < (int) startetlist->objects; i++) { parytet = (triface *) fastlookup(startetlist, i); uninfect(*parytet); } delete startetlist; if (dir == INTERVERT) { // This path passing a vertex of the face [a, b, c]. if (pos == 0) { // The path acrosses pa. enext2self(*searchtet); esymself(*searchtet); } else if (pos == 1) { // The path acrosses pa. } else { // pos == 2 // The path acrosses pc. fnextself(*searchtet); enext2self(*searchtet); esymself(*searchtet); } return INTERVERT; } if (dir == INTEREDGE) { // This path passing an edge of the face [a, b, c]. if (pos == 0) { // The path intersects [pa, pb]. } else if (pos == 1) { // The path intersects [pb, pc]. fnextself(*searchtet); enext2self(*searchtet); esymself(*searchtet); } else { // pos == 2 // The path intersects [pc, pa]. enext2fnextself(*searchtet); esymself(*searchtet); } return INTEREDGE; } if (dir == INTERFACE) { return INTERFACE; } // The path does not intersect any tet at pa. return BELOWHULL2; } /////////////////////////////////////////////////////////////////////////////// // // // scoutsegment() Look for a given segment in the tetrahedralization T. // // // // Search an edge in the tetrahedralization that matches the given segmment. // // If such an edge exists, the segment is 'locked' at the edge. 'searchtet' // // returns this (constrained) edge. Otherwise, the segment is missing. // // // // The returned value indicates one of the following cases: // // - SHAREEDGE, the segment exists and is inserted in T; // // - INTERVERT, the segment intersects a vertex ('refpt'). // // - INTEREDGE, the segment intersects an edge (in 'searchtet'). // // - INTERFACE, the segment crosses a face (in 'searchtet'). // // // // If the returned value is INTEREDGE or INTERFACE, i.e., the segment is // // missing, 'refpt' returns the reference point for splitting thus segment, // // 'searchtet' returns a tet containing the 'refpt'. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::scoutsegment2(face* sseg, triface* searchtet, point* refpt) { triface neightet, reftet; face splitsh, checkseg; point startpt, endpt; point pa, pb, pc, pd; enum interresult dir; REAL angmax, ang; long facecount; int hitbdry; int types[2], poss[4]; int pos, i; // Is 'searchtet' a valid handle? if ((searchtet->tet == NULL) || (searchtet->tet == dummytet)) { startpt = sorg(*sseg); point2tetorg(startpt, *searchtet); } else { startpt = sorg(*sseg); } assert(org(*searchtet) == startpt); // SELF_CHECK endpt = sdest(*sseg); if (b->verbose > 1) { printf(" Scout seg (%d, %d).\n", pointmark(startpt), pointmark(endpt)); } dir = finddirection2(searchtet, endpt); if (dir == INTERVERT) { pd = dest(*searchtet); if (pd == endpt) { // Found! Insert the segment. tsspivot1(*searchtet, checkseg); // SELF_CHECK if (checkseg.sh == dummysh) { neightet = *searchtet; hitbdry = 0; do { tssbond1(neightet, *sseg); tfnextself(neightet); if (neightet.tet == dummytet) { hitbdry++; if (hitbdry == 2) break; esym(*searchtet, neightet); tfnextself(neightet); if (neightet.tet == dummytet) break; } } while (neightet.tet != searchtet->tet); } else { // Collision! This can happy during facet recovery. // See fig/dump-cavity-case19, -case20. assert(checkseg.sh == sseg->sh); // SELF_CHECK } // The job is done. return SHAREEDGE; } else { // A point is on the path. *refpt = pd; return INTERVERT; } } if (b->verbose > 1) { printf(" Scout ref point of seg (%d, %d).\n", pointmark(startpt), pointmark(endpt)); } facecount = across_face_count; enextfnextself(*searchtet); // Go to the opposite face. symedgeself(*searchtet); // Enter the adjacent tet. pa = org(*searchtet); angmax = interiorangle(pa, startpt, endpt, NULL); *refpt = pa; pb = dest(*searchtet); ang = interiorangle(pb, startpt, endpt, NULL); if (ang > angmax) { angmax = ang; *refpt = pb; } // Check whether two segments are intersecting. if (dir == INTEREDGE) { tsspivot1(*searchtet, checkseg); if (checkseg.sh != dummysh) { printf("Error: Invalid PLC. Two segments intersect.\n"); startpt = getsubsegfarorg(sseg); endpt = getsubsegfardest(sseg); pa = getsubsegfarorg(&checkseg); pb = getsubsegfardest(&checkseg); printf(" 1st: (%d, %d), 2nd: (%d, %d).\n", pointmark(startpt), pointmark(endpt), pointmark(pa), pointmark(pb)); terminatetetgen(3); } across_edge_count++; } pc = apex(*searchtet); ang = interiorangle(pc, startpt, endpt, NULL); if (ang > angmax) { angmax = ang; *refpt = pc; } reftet = *searchtet; // Save the tet containing the refpt. // Search intersecting faces along the segment. while (1) { pd = oppo(*searchtet); if (b->verbose > 2) { printf(" Passing face (%d, %d, %d, %d), dir(%d).\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd), (int) dir); } across_face_count++; // Stop if we meet 'endpt'. if (pd == endpt) break; ang = interiorangle(pd, startpt, endpt, NULL); if (ang > angmax) { angmax = ang; *refpt = pd; reftet = *searchtet; } // Find a face intersecting the segment. if (dir == INTERFACE) { // One of the three oppo faces in 'searchtet' intersects the segment. neightet.tet = searchtet->tet; neightet.ver = 0; for (i = 0; i < 3; i++) { neightet.loc = locpivot[searchtet->loc][i]; pa = org(neightet); pb = dest(neightet); pc = apex(neightet); pd = oppo(neightet); // The above point. if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) { dir = (enum interresult) types[0]; pos = poss[0]; break; } else { dir = DISJOINT; pos = 0; } } assert(dir != DISJOINT); // SELF_CHECK } else { // dir == ACROSSEDGE // Check the two opposite faces (of the edge) in 'searchtet'. neightet = *searchtet; neightet.ver = 0; for (i = 0; i < 2; i++) { neightet.loc = locverpivot[searchtet->loc][searchtet->ver][i]; pa = org(neightet); pb = dest(neightet); pc = apex(neightet); pd = oppo(neightet); // The above point. if (tri_edge_test(pa, pb, pc, startpt, endpt, pd, 1, types, poss)) { dir = (enum interresult) types[0]; pos = poss[0]; break; } else { dir = DISJOINT; pos = 0; } } if (dir == DISJOINT) { // No intersection. Go to the next tet. dir = INTEREDGE; tfnextself(*searchtet); continue; } } if (dir == INTERVERT) { // This segment passing a vertex. Choose it and return. for (i = 0; i < pos; i++) { enextself(neightet); } pd = org(neightet); if (b->verbose > 2) { angmax = interiorangle(pd, startpt, endpt, NULL); } *refpt = pd; break; } if (dir == INTEREDGE) { // Get the edge intersects with the segment. for (i = 0; i < pos; i++) { enextself(neightet); } } // Go to the next tet. symedge(neightet, *searchtet); if (dir == INTEREDGE) { // Check whether two segments are intersecting. tsspivot1(*searchtet, checkseg); if (checkseg.sh != dummysh) { printf("Error: Invalid PLC! Two segments intersect.\n"); startpt = getsubsegfarorg(sseg); endpt = getsubsegfardest(sseg); pa = getsubsegfarorg(&checkseg); pb = getsubsegfardest(&checkseg); printf(" 1st: (%d, %d), 2nd: (%d, %d).\n", pointmark(startpt), pointmark(endpt), pointmark(pa), pointmark(pb)); terminatetetgen(3); } across_edge_count++; } } // while (1) // dir is either ACROSSVERT, or ACROSSEDGE, or ACROSSFACE. if (b->verbose > 2) { printf(" Refpt %d (%g), visited %ld faces.\n", pointmark(*refpt), angmax / PI * 180.0, across_face_count - facecount); } if (across_face_count - facecount > across_max_count) { across_max_count = across_face_count - facecount; } *searchtet = reftet; return dir; } /////////////////////////////////////////////////////////////////////////////// // // // getsegmentsplitpoint() Calculate a split point in the given segment. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::getsegmentsplitpoint2(face* sseg, point refpt, REAL* vt) { point ei, ej, ek; REAL split, L, d, d1, d2, d3; int stype, sign; int i; // Decide the type of this segment. sign = 1; ei = sorg(*sseg); ej = sdest(*sseg); if (pointtype(ei) == ACUTEVERTEX) { if (pointtype(ej) == ACUTEVERTEX) { // Both ei and ej are ACUTEVERTEX. stype = 0; } else { // ej is either a NACUTEVERTEX or a STEINERVERTEX. stype = 1; } } else { if (pointtype(ei) == NACUTEVERTEX) { if (pointtype(ej) == ACUTEVERTEX) { stype = 1; sign = -1; } else { if (pointtype(ej) == NACUTEVERTEX) { // Both ei and ej are non-acute. stype = 0; } else { // ej is a STEINERVETEX. ek = getsubsegfardest(sseg); if (pointtype(ek) == ACUTEVERTEX) { stype = 1; sign = -1; } else { stype = 0; } } } } else { // ei is a STEINERVERTEX. if (pointtype(ej) == ACUTEVERTEX) { stype = 1; sign = -1; } else { ek = getsubsegfarorg(sseg); if (pointtype(ej) == NACUTEVERTEX) { if (pointtype(ek) == ACUTEVERTEX) { stype = 1; } else { stype = 0; } } else { // Both ei and ej are STEINERVETEXs. ei has priority. if (pointtype(ek) == ACUTEVERTEX) { stype = 1; } else { ek = getsubsegfardest(sseg); if (pointtype(ek) == ACUTEVERTEX) { stype = 1; sign = -1; } else { stype = 0; } } } } } } // Adjust the endpoints: ei, ej. if (sign == -1) { sesymself(*sseg); ei = sorg(*sseg); ej = sdest(*sseg); } if (b->verbose > 1) { printf(" Split a type-%d seg(%d, %d) ref(%d)", stype, pointmark(ei), pointmark(ej), pointmark(refpt)); if (stype) { ek = getsubsegfarorg(sseg); printf(" ek(%d)", pointmark(ek)); } printf(".\n"); } // Calculate the split point. if (stype == 0) { // Use rule-1. L = DIST(ei, ej); d1 = DIST(ei, refpt); d2 = DIST(ej, refpt); if (d1 < d2) { // Choose ei as center. if (d1 < 0.5 * L) { split = d1 / L; // Adjust split if it is close to middle. (2009-02-01) if ((split > 0.4) || (split < 0.6)) split = 0.5; } else { split = 0.5; } for (i = 0; i < 3; i++) { vt[i] = ei[i] + split * (ej[i] - ei[i]); } } else { // Choose ej as center. if (d2 < 0.5 * L) { split = d2 / L; // Adjust split if it is close to middle. (2009-02-01) if ((split > 0.4) || (split < 0.6)) split = 0.5; } else { split = 0.5; } for (i = 0; i < 3; i++) { vt[i] = ej[i] + split * (ei[i] - ej[i]); } } r1count++; } else { // Use rule-2. ek = getsubsegfarorg(sseg); L = DIST(ek, ej); d = DIST(ek, refpt); split = d / L; for (i = 0; i < 3; i++) { vt[i] = ek[i] + split * (ej[i] - ek[i]); } d1 = DIST(vt, refpt); d2 = DIST(vt, ej); if (d1 > d2) { // Use rule-3. d3 = DIST(ei, refpt); if (d1 < 0.5 * d3) { split = (d - d1) / L; } else { split = (d - 0.5 * d3) / L; } for (i = 0; i < 3; i++) { vt[i] = ek[i] + split * (ej[i] - ek[i]); } } d1 > d2 ? r3count++ : r2count++; } if (b->verbose > 1) { printf(" split (%g), vt (%g, %g, %g).\n", split, vt[0], vt[1], vt[2]); } } /////////////////////////////////////////////////////////////////////////////// // // // delaunizesegments() Recover segments in a Delaunay tetrahedralization. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::delaunizesegments2() { triface searchtet; face splitsh; face *psseg, sseg; // *parysh; point refpt, newpt; enum interresult dir; bool visflag; if (b->verbose) { printf(" Delaunizing segments.\n"); } // Loop until 'subsegstack' is empty. while (subsegstack->objects > 0l) { // seglist is used as a stack. subsegstack->objects--; psseg = (face *) fastlookup(subsegstack, subsegstack->objects); sseg = *psseg; if (!sinfected(sseg)) continue; // Not a missing segment. suninfect(sseg); // Insert the segment. searchtet.tet = NULL; dir = scoutsegment2(&sseg, &searchtet, &refpt); if (dir != SHAREEDGE) { // The segment is missing, split it. spivot(sseg, splitsh); if (dir != INTERVERT) { // Create the new point. makepoint(&newpt); getsegmentsplitpoint2(&sseg, refpt, newpt); setpointtype(newpt, FREESEGVERTEX); setpoint2sh(newpt, sencode(sseg)); // Split the segment by newpt. sinsertvertex(newpt, &splitsh, &sseg, true, false); // Insert newpt into the DT. If 'checksubfaces == 1' the current // mesh is constrained Delaunay (but may not Delaunay). visflag = (checksubfaces == 1); insertvertexbw(newpt, &searchtet, true, visflag, false, false); } else { /*if (getpointtype(refpt) != ACUTEVERTEX) { setpointtype(refpt, RIDGEVERTEX); } // Split the segment by refpt. sinsertvertex(refpt, &splitsh, &sseg, true, false);*/ printf("Error: Invalid PLC! A point and a segment intersect.\n"); point pa, pb; pa = getsubsegfarorg(&sseg); pb = getsubsegfardest(&sseg); printf(" Point: %d. Segment: (%d, %d).\n", pointmark(refpt), pointmark(pa), pointmark(pb)); terminatetetgen(3); } } } if (b->verbose) { printf(" %ld protecting points.\n", r1count + r2count + r3count); } } /////////////////////////////////////////////////////////////////////////////// // // // scoutsubface() Look for a given subface in the tetrahedralization T. // // // // 'ssub' is the subface, denoted as abc. If abc exists in T, it is 'locked' // // at the place where the two tets sharing at it. // // // // 'convexflag' indicates the current mesh is convex (1) or non-convex (0). // // // // The returned value indicates one of the following cases: // // - SHAREFACE, abc exists and is inserted; // // - TOUCHEDGE, a vertex (the origin of 'searchtet') lies on ab. // // - EDGETRIINT, all three edges of abc are missing. // // - ACROSSTET, a tet (in 'searchtet') crosses the facet containg abc. // // // // If the retunred value is ACROSSTET, the subface is missing. 'searchtet' // // returns a tet which shares the same edge as 'pssub'. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::scoutsubface(face* pssub, triface* searchtet, int convexflag) { triface spintet; face checksh; point pa, pb, pc, pd; enum interresult dir; int hitbdry; int i; if ((searchtet->tet == NULL) || (searchtet->tet == dummytet)) { // Search an edge of 'ssub' in tetrahedralization. pssub->shver = 0; for (i = 0; i < 3; i++) { pa = sorg(*pssub); pb = sdest(*pssub); // Get a tet whose origin is pa. point2tetorg(pa, *searchtet); // Search the edge from pa->pb. dir = finddirection2(searchtet, pb); if (dir == INTERVERT) { if (dest(*searchtet) == pb) { // Found the edge. Break the loop. break; } else { // A vertex lies on the search edge. Return it. enextself(*searchtet); return TOUCHEDGE; } } else if (dir == BELOWHULL2) { if (convexflag > 0) { assert(0); } // The domain is non-convex, and we got stucked at a boundary face. point2tetorg(pa, *searchtet); dir = finddirection3(searchtet, pb); if (dir == INTERVERT) { if (dest(*searchtet) == pb) { // Found the edge. Break the loop. break; } else { // A vertex lies on the search edge. Return it. enextself(*searchtet); return TOUCHEDGE; } } } senextself(*pssub); } if (i == 3) { // None of the three edges exists. return EDGETRIINT; // ab intersects the face in 'searchtet'. } } else { // 'searchtet' holds the current edge of 'pssub'. pa = org(*searchtet); pb = dest(*searchtet); } pc = sapex(*pssub); if (b->verbose > 1) { printf(" Scout subface (%d, %d, %d) (%ld).\n", pointmark(pa), pointmark(pb), pointmark(pc), subfacstack->objects); } // Searchtet holds edge pa->pb. Search a face with apex pc. spintet = *searchtet; pd = apex(spintet); hitbdry = 0; while (1) { if (pd == pc) { // Found! Insert the subface. tspivot(spintet, checksh); // SELF_CHECK if (checksh.sh == dummysh) { // Comment: here we know that spintet and pssub refer to the same // edge and the same DIRECTION: pa->pb. if ((spintet.ver & 1) == 1) { // Stay in CCW edge ring. esymself(spintet); } if (sorg(*pssub) != org(spintet)) { sesymself(*pssub); } tsbond(spintet, *pssub); symself(spintet); if (spintet.tet != dummytet) { tspivot(spintet, checksh); // SELF_CHECK assert(checksh.sh == dummysh); // SELF_CHECK sesymself(*pssub); tsbond(spintet, *pssub); } return SHAREFACE; } else { *searchtet = spintet; if (checksh.sh != pssub->sh) { // Another subface is laready inserted. // Comment: This is possible when there are faked tets. return COLLISIONFACE; } else { // The subface has already been inserted (when you do check). return SHAREFACE; } } } if (!fnextself(spintet)) { hitbdry++; if (hitbdry == 2) break; esym(*searchtet, spintet); if (!fnextself(spintet)) break; } pd = apex(spintet); if (pd == apex(*searchtet)) break; } return INTERTET; } /////////////////////////////////////////////////////////////////////////////// // // // scoutcrosstet() Scout a tetrahedron across a facet. // // // // A subface (abc) of the facet (F) is given in 'pssub', 'searchtet' holds // // the edge ab, it is the tet starting the search. 'facpoints' contains all // // points which are co-facet with a, b, and c. // // // // The subface (abc) was produced by a 2D CDT algorithm under the Assumption // // that F is flat. In real data, however, F may not be strictly flat. Hence // // a tet (abde) that crosses abc may be in one of the two cases: (i) abde // // intersects F in its interior, or (ii) abde intersects F on its boundary. // // In case (i) F (or part of it) is missing in DT and needs to be recovered. // // In (ii) F is not missing, the surface mesh of F needs to be adjusted. // // // // This routine distinguishes the two cases by the returned value, which is // // - INTERTET, if it is case (i), 'searchtet' is abde, d and e lies below // // and above abc, respectively, neither d nor e is dummypoint; or // // - INTERFACE, if it is case (ii), 'searchtet' is abde, where the face // // abd intersects abc, i.e., d is co-facet with abc, e may be co-facet // // with abc or dummypoint. // // // /////////////////////////////////////////////////////////////////////////////// enum tetgenmesh::interresult tetgenmesh::scoutcrosstet(face *pssub, triface* searchtet, arraypool* facpoints) { triface spintet, crossface; point pa, pb, pc, pd, pe; REAL ori, ori1, len, n[3]; REAL r, dr, drmin; bool cofacetflag; int hitbdry; int i; if (facpoints != NULL) { // Infect all vertices of the facet. for (i = 0; i < (int) facpoints->objects; i++) { pd = * (point *) fastlookup(facpoints, i); pinfect(pd); } } // Search an edge crossing the facet containing abc. if (searchtet->ver & 01) { esymself(*searchtet); // Adjust to 0th edge ring. sesymself(*pssub); } pa = sorg(*pssub); pb = sdest(*pssub); pc = sapex(*pssub); // 'searchtet' refers to edge pa->pb. assert(org(*searchtet) == pa); assert(dest(*searchtet) == pb); // Search an apex lies below the subface. Note that such apex may not // exist which indicates there is a co-facet apex. cofacetflag = false; pd = apex(*searchtet); spintet = *searchtet; hitbdry = 0; while (1) { ori = orient3d(pa, pb, pc, pd); if ((ori != 0) && pinfected(pd)) { ori = 0; // Force d be co-facet with abc. } if (ori > 0) { break; // Found a lower point (the apex of spintet). } // Go to the next face. if (!fnextself(spintet)) { hitbdry++; if (hitbdry == 2) { cofacetflag = true; break; // Not found. } esym(*searchtet, spintet); if (!fnextself(spintet)) { cofacetflag = true; break; // Not found. } } pd = apex(spintet); if (pd == apex(*searchtet)) { cofacetflag = true; break; // Not found. } } if (!cofacetflag) { if (hitbdry > 0) { // The edge direction is reversed, which means we have to reverse // the face rotation direction to find the crossing edge d->e. esymself(spintet); } // Keep the edge a->b be in the CCW edge ring of spintet. if (spintet.ver & 1) { symedgeself(spintet); assert(spintet.tet != dummytet); } // Search a tet whose apex->oppo crosses the face [a, b, c]. // -- spintet is a face [a, b, d]. // -- the apex (d) of spintet is below [a, b, c]. while (1) { pe = oppo(spintet); ori = orient3d(pa, pb, pc, pe); if ((ori != 0) && pinfected(pe)) { ori = 0; // Force it to be a coplanar point. } if (ori == 0) { cofacetflag = true; break; // Found a co-facet point. } if (ori < 0) { *searchtet = spintet; break; // Found. edge [d, e]. } // Go to the next tet. tfnextself(spintet); if (spintet.tet == dummytet) { cofacetflag = true; break; // There is a co-facet point. } } // Now if "cofacetflag != true", searchtet contains a cross tet (abde), // where d and e lie below and above abc, respectively, and // orient3d(a, b, d, e) < 0. } if (cofacetflag) { // There are co-facet points. Calculate a point above the subface. facenormal2(pa, pb, pc, n, 1); len = sqrt(DOT(n, n)); n[0] /= len; n[1] /= len; n[2] /= len; len = DIST(pa, pb); len += DIST(pb, pc); len += DIST(pc, pa); len /= 3.0; dummypoint[0] = pa[0] + len * n[0]; dummypoint[1] = pa[1] + len * n[1]; dummypoint[2] = pa[2] + len * n[2]; // Search a co-facet point d, s.t. (i) [a, b, d] intersects [a, b, c], // AND (ii) a, b, c, d has the closet circumradius of [a, b, c]. // NOTE: (ii) is needed since there may be several points satisfy (i). // For an example, see file2.poly. circumsphere(pa, pb, pc, NULL, n, &r); crossface.tet = NULL; pe = apex(*searchtet); spintet = *searchtet; hitbdry = 0; while (1) { pd = apex(spintet); ori = orient3d(pa, pb, pc, pd); if ((ori == 0) || pinfected(pd)) { ori1 = orient3d(pa, pb, dummypoint, pd); if (ori1 > 0) { // [a, b, d] intersects with [a, b, c]. if (pinfected(pd)) { len = DIST(n, pd); dr = fabs(len - r); if (crossface.tet == NULL) { // This is the first cross face. crossface = spintet; drmin = dr; } else { if (dr < drmin) { crossface = spintet; drmin = dr; } } } else { assert(ori == 0); // SELF_CHECK // Found a coplanar but not co-facet point (pd). printf("Error: Invalid PLC! A point and a subface intersect\n"); // get_origin_facet_corners(pssub, &pa, &pb, &pc); printf(" Point %d. Subface (#%d) (%d, %d, %d)\n", pointmark(pd), shellmark(*pssub), pointmark(pa), pointmark(pb), pointmark(pc)); terminatetetgen(3); } } } // Go to the next face. if (!fnextself(spintet)) { hitbdry++; if (hitbdry == 2) break; esym(*searchtet, spintet); if (!fnextself(spintet)) break; } if (apex(spintet) == pe) { break; } } if(crossface.tet == NULL) { assert(crossface.tet != NULL); // Not handled yet. } *searchtet = crossface; dummypoint[0] = dummypoint[1] = dummypoint[2] = 0; } if (cofacetflag) { if (b->verbose > 1) { printf(" Found a co-facet face (%d, %d, %d) op (%d).\n", pointmark(pa), pointmark(pb), pointmark(apex(*searchtet)), pointmark(oppo(*searchtet))); } if (facpoints != NULL) { // Unmark all facet vertices. for (i = 0; i < (int) facpoints->objects; i++) { pd = * (point *) fastlookup(facpoints, i); puninfect(pd); } } // Comment: Now no vertex is infected. /*if (getpointtype(apex(*searchtet)) == VOLVERTEX) { // A vertex lies on the facet. enext2self(*searchtet); // org(*searchtet) == pd return TOUCHFACE; }*/ return INTERFACE; } else { // Return a crossing tet. if (b->verbose > 1) { printf(" Found a crossing tet (%d, %d, %d, %d).\n", pointmark(pa), pointmark(pb), pointmark(apex(*searchtet)), pointmark(pe)); } // Comment: if facpoints != NULL, co-facet vertices are stll infected. // They will be uninfected in formcavity(); return INTERTET; // abc intersects the volume of 'searchtet'. } } /////////////////////////////////////////////////////////////////////////////// // // // recoversubfacebyflips() Recover a subface by flips in the surface mesh. // // // // A subface [a, b, c] ('pssub') intersects with a face [a, b, d] ('cross- // // face'), where a, b, c, and d belong to the same facet. It indicates that // // the face [a, b, d] should appear in the surface mesh. // // // // This routine recovers [a, b, d] in the surface mesh through a sequence of // // 2-to-2 flips. No Steiner points is needed. 'pssub' returns [a, b, d]. // // // // If 'facfaces' is not NULL, all flipped subfaces are queued for recovery. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::recoversubfacebyflips(face* pssub, triface* crossface, arraypool *facfaces) { triface neightet; face flipfaces[2], *parysh; face checkseg; point pa, pb, pc, pd, pe; REAL ori, len, n[3]; // Get the missing subface is [a, b, c]. pa = sorg(*pssub); pb = sdest(*pssub); pc = sapex(*pssub); // The crossface is [a, b, d, e]. // assert(org(*crossface) == pa); // assert(dest(*crossface) == pb); pd = apex(*crossface); pe = dummypoint; // oppo(*crossface); if (pe == dummypoint) { // Calculate a point above the faces. facenormal2(pa, pb, pd, n, 1); len = sqrt(DOT(n, n)); n[0] /= len; n[1] /= len; n[2] /= len; len = DIST(pa, pb); len += DIST(pb, pd); len += DIST(pd, pa); len /= 3.0; pe[0] = pa[0] + len * n[0]; pe[1] = pa[1] + len * n[1]; pe[2] = pa[2] + len * n[2]; } // Adjust face [a, b, c], so that edge [b, c] crosses edge [a, d]. ori = orient3d(pb, pc, pe, pd); assert(ori != 0); // SELF_CHECK if (ori > 0) { // Swap a and b. sesymself(*pssub); esymself(*crossface); // symedgeself(*crossface); pa = sorg(*pssub); pb = sdest(*pssub); if (pe == dummypoint) { pe[0] = pe[1] = pe[2] = 0; } pe = dummypoint; // oppo(*crossface); } while (1) { // Flip edge [b, c] to edge [a, d]. senext(*pssub, flipfaces[0]); sspivot(flipfaces[0], checkseg); // SELF_CHECK assert(checkseg.sh == dummysh); // SELF_CHECK spivot(flipfaces[0], flipfaces[1]); stpivot(flipfaces[1], neightet); if (neightet.tet != dummytet) { // A recovered subface, clean sub<==>tet connections. tsdissolve(neightet); symself(neightet); tsdissolve(neightet); stdissolve(flipfaces[1]); sesymself(flipfaces[1]); stdissolve(flipfaces[1]); sesymself(flipfaces[1]); // flipfaces[1] refers to edge [b, c] (either b->c or c->b). } flip22sub(&(flipfaces[0]), NULL); flip22count++; // Comment: now flipfaces[0] is [d, a, b], flipfaces[1] is [a, d, c]. // Add them into list (make ensure that they must be recovered). facfaces->newindex((void **) &parysh); *parysh = flipfaces[0]; facfaces->newindex((void **) &parysh); *parysh = flipfaces[1]; // Find the edge [a, b]. senext(flipfaces[0], *pssub); assert(sorg(*pssub) == pa); // SELF_CHECK assert(sdest(*pssub) == pb); // SELF_CHECK pc = sapex(*pssub); if (pc == pd) break; if (pe == dummypoint) { // Calculate a point above the faces. facenormal2(pa, pb, pd, n, 1); len = sqrt(DOT(n, n)); n[0] /= len; n[1] /= len; n[2] /= len; len = DIST(pa, pb); len += DIST(pb, pd); len += DIST(pd, pa); len /= 3.0; pe[0] = pa[0] + len * n[0]; pe[1] = pa[1] + len * n[1]; pe[2] = pa[2] + len * n[2]; } while (1) { ori = orient3d(pb, pc, pe, pd); assert(ori != 0); // SELF_CHECK if (ori > 0) { senext2self(*pssub); spivotself(*pssub); if (sorg(*pssub) != pa) sesymself(*pssub); pb = sdest(*pssub); pc = sapex(*pssub); continue; } break; } } if (pe == dummypoint) { pe[0] = pe[1] = pe[2] = 0; } } /////////////////////////////////////////////////////////////////////////////// // // // formcavity() Form the cavity of a missing region. // // // // A missing region R is a set of co-facet (co-palanr) subfaces. 'pssub' is // // a missing subface [a, b, c]. 'crosstets' contains only one tet, [a, b, d, // // e], where d and e lie below and above [a, b, c], respectively. Other // // crossing tets are sought from this tet and saved in 'crosstets'. // // // // The cavity C is divided into two parts by R,one at top and one at bottom. // // 'topfaces' and 'botfaces' return the upper and lower boundary faces of C. // // 'toppoints' contains vertices of 'crosstets' in the top part of C, and so // // does 'botpoints'. Both 'toppoints' and 'botpoints' contain vertices of R. // // // // NOTE: 'toppoints' may contain points which are not vertices of any top // // faces, and so may 'botpoints'. Such points may belong to other facets and // // need to be present after the recovery of this cavity (P1029.poly). // // // // A pair of boundary faces: 'firsttopface' and 'firstbotface', are saved. // // They share the same edge in the boundary of the missing region. // // // // 'facpoints' contains all vertices of the facet containing R. They are // // used for searching the crossing tets. On input all vertices are infected. // // They are uninfected after the cavity is formed. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formcavity(face *pssub, arraypool* crosstets, arraypool* topfaces, arraypool* botfaces, arraypool* toppoints, arraypool* botpoints, arraypool* facpoints, arraypool* facfaces) { arraypool *crossedges; triface *parytet, crosstet, spintet, neightet, faketet; face neighsh, checksh, *parysh; face checkseg; point pa, pb, pc, pf, pg; point pd, pe; point *ppt; // REAL ori; int i, j; // For triangle-edge test. enum interresult dir; int types[2], poss[4]; // Get the missing subface abc. pa = sorg(*pssub); pb = sdest(*pssub); pc = sapex(*pssub); // Comment: Now all facet vertices are infected. // Get a crossing tet abde. parytet = (triface *) fastlookup(crosstets, 0); // face abd. // The edge de crosses the facet. d lies below abc. enext2fnext(*parytet, crosstet); enext2self(crosstet); esymself(crosstet); // the edge d->e at face [d,e,a] infect(crosstet); *parytet = crosstet; // Save it in list. // Temporarily re-use 'topfaces' for storing crossing edges. crossedges = topfaces; crossedges->newindex((void **) &parytet); *parytet = crosstet; // Collect all crossing tets. Each cross tet is saved in the standard // form deab, where de is a corrsing edge, orient3d(d,e,a,b) < 0. // NOTE: hull tets may be collected. See fig/dump-cavity-case2a(b).lua. // Make sure that neither d nor e is dummypoint. for (i = 0; i < (int) crossedges->objects; i++) { crosstet = * (triface *) fastlookup(crossedges, i); // It may already be tested. if (!edgemarked(crosstet)) { // Collect all tets sharing at the edge. pg = apex(crosstet); spintet = crosstet; while (1) { // Mark this edge as tested. markedge(spintet); if (!infected(spintet)) { infect(spintet); crosstets->newindex((void **) &parytet); *parytet = spintet; } // Go to the neighbor tet. tfnextself(spintet); if (spintet.tet != dummytet) { // Check the validity of the PLC. tspivot(spintet, checksh); if (checksh.sh != dummysh) { printf("Error: Invalid PLC! Two subfaces intersect.\n"); printf(" 1st (#%4d): (%d, %d, %d)\n", shellmark(*pssub), pointmark(pa), pointmark(pb), pointmark(pc)); printf(" 2nd (#%4d): (%d, %d, %d)\n", shellmark(checksh), pointmark(sorg(checksh)), pointmark(sdest(checksh)), pointmark(sapex(checksh))); terminatetetgen(3); } } else { // Encounter a boundary face. assert(0); // Not handled yet. } if (apex(spintet) == pg) break; } // Detect new cross edges. // Comment: A crossing edge must intersect one missing subface of // this facet. We do edge-face tests. pd = org(spintet); pe = dest(spintet); while (1) { // Remember: spintet is edge d->e, d lies below [a, b, c]. pf = apex(spintet); // if (pf != dummypoint) { // Do not grab a hull edge. if (!pinfected(pf)) { for (j = 0; j < (int) facfaces->objects; j++) { parysh = (face *) fastlookup(facfaces, j); pa = sorg(*parysh); pb = sdest(*parysh); pc = sapex(*parysh); // Check if pd->pf crosses the facet. if (tri_edge_test(pa, pb, pc, pd, pf, NULL, 1, types, poss)) { dir = (enum interresult) types[0]; if ((dir == INTEREDGE) || (dir == INTERFACE)) { // The edge d->f corsses the facet. enext2fnext(spintet, neightet); esymself(neightet); // d->f. // pd must lie below the subface. break; } } // Check if pe->pf crosses the facet. if (tri_edge_test(pa, pb, pc, pe, pf, NULL, 1, types, poss)) { dir = (enum interresult) types[0]; if ((dir == INTEREDGE) || (dir == INTERFACE)) { // The edge f->e crosses the face. enextfnext(spintet, neightet); esymself(neightet); // f->e. // pf must lie below the subface. break; } } } // There must exist a crossing edge. assert(j < (int) facfaces->objects); /*// There exist a crossing edge, either d->f, or f->e. ori = orient3d(pa, pb, pc, pf); if (ori == 0) { printf("Error: Invalid PLC! Point and subface intersect.\n"); printf(" Point %d, subface (#%4d): (%d, %d, %d)\n", pointmark(pf), shellmark(*pssub), pointmark(pa), pointmark(pb), pointmark(pc)); terminatetetgen(3); } if (ori < 0) { // The edge d->f corsses the facet. enext2fnext(spintet, neightet); esymself(neightet); // d->f. } else { // The edge f->e crosses the face. enextfnext(spintet, neightet); esymself(neightet); // f->e. } */ if (!edgemarked(neightet)) { // Add a new cross edge. crossedges->newindex((void **) &parytet); *parytet = neightet; } } // } tfnextself(spintet); if (spintet.tet == dummytet) { // Encounter a boundary face. assert(0); // Not handled yet. } if (apex(spintet) == pg) break; } } } // Unmark all facet vertices. for (i = 0; i < (int) facpoints->objects; i++) { ppt = (point *) fastlookup(facpoints, i); puninfect(*ppt); } // Comments: Now no vertex is marked. Next we will mark vertices which // belong to the top and bottom boundary faces of the cavity and put // them in 'toppopints' and 'botpoints', respectively. // All cross tets are found. Unmark cross edges. for (i = 0; i < (int) crossedges->objects; i++) { crosstet = * (triface *) fastlookup(crossedges, i); if (edgemarked(crosstet)) { // Add the vertices of the cross edge [d, e] in lists. It must be // that d lies below the facet (i.e., its a bottom vertex). // Note that a cross edge contains no dummypoint. pf = org(crosstet); // assert(pf != dummypoint); // SELF_CHECK if (!pinfected(pf)) { pinfect(pf); botpoints->newindex((void **) &ppt); // Add a bottom vertex. *ppt = pf; } pf = dest(crosstet); // assert(pf != dummypoint); // SELF_CHECK if (!pinfected(pf)) { pinfect(pf); toppoints->newindex((void **) &ppt); // Add a top vertex. *ppt = pf; } // Unmark this edge in all tets containing it. pg = apex(crosstet); spintet = crosstet; while (1) { assert(edgemarked(spintet)); // SELF_CHECK unmarkedge(spintet); tfnextself(spintet); // Go to the neighbor tet. if (spintet.tet == dummytet) { assert(0); // Not handled yet. } if (apex(spintet) == pg) break; } } } if (b->verbose > 1) { printf(" Formed cavity: %ld (%ld) cross tets (edges).\n", crosstets->objects, crossedges->objects); } crossedges->restart(); // Find a pair of cavity boundary faces from the top and bottom sides of // the facet each, and they share the same edge. Save them in the // global variables: firsttopface, firstbotface. They will be used in // fillcavity() for gluing top and bottom new tets. for (i = 0; i < (int) crosstets->objects; i++) { crosstet = * (triface *) fastlookup(crosstets, i); enextfnext(crosstet, spintet); enextself(spintet); symedge(spintet, neightet); // if (!infected(neightet)) { if ((neightet.tet == dummytet) || !infected(neightet)) { // A top face. if (neightet.tet == dummytet) { // Create a fake tet to hold the boundary face. maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); bond(faketet, spintet); tspivot(spintet, checksh); if (checksh.sh != dummysh) { sesymself(checksh); tsbond(faketet, checksh); } for (j = 0; j < 3; j++) { // Bond segments. tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } firsttopface = faketet; } else { firsttopface = neightet; } } else { continue; // Go to the next cross tet. } enext2fnext(crosstet, spintet); enext2self(spintet); symedge(spintet, neightet); // if (!infected(neightet)) { if ((neightet.tet == dummytet) || !infected(neightet)) { // A bottom face. if (neightet.tet == dummytet) { // Create a fake tet to hold the boundary face. maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); bond(spintet, faketet); tspivot(spintet, checksh); if (checksh.sh != dummysh) { sesymself(checksh); tsbond(faketet, checksh); } for (j = 0; j < 3; j++) { // Bond segments. tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } firstbotface = faketet; } else { firstbotface = neightet; } } else { continue; } break; } assert(i < (int) crosstets->objects); // SELF_CHECK // Collect the top and bottom faces and the middle vertices. Since all top // and bottom vertices have been marked in above. Unmarked vertices are // middle vertices. // NOTE 1: Hull tets may be collected. Process them as normal one. // (see fig/dump-cavity-case2.lua.) // NOTE 2: Some previously recovered subfaces may be completely // contained in a cavity (see fig/dump-cavity-case6.lua). In such case, // we create two faked tets to hold this subface, one at each side. // The faked tets will be removed in fillcavity(). for (i = 0; i < (int) crosstets->objects; i++) { crosstet = * (triface *) fastlookup(crosstets, i); enextfnext(crosstet, spintet); enextself(spintet); symedge(spintet, neightet); // if (!infected(neightet)) { if ((neightet.tet == dummytet) || !infected(neightet)) { // A top face. topfaces->newindex((void **) &parytet); if (neightet.tet == dummytet) { // Create a fake tet to hold the boundary face. maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); bond(spintet, faketet); tspivot(spintet, checksh); if (checksh.sh != dummysh) { sesymself(checksh); tsbond(faketet, checksh); } for (j = 0; j < 3; j++) { // Bond segments. tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } *parytet = faketet; } else { *parytet = neightet; } } else { if ((neightet.tet != dummytet) && infected(neightet)) { // Check if this side is a subface. tspivot(spintet, neighsh); if (neighsh.sh != dummysh) { // Found a subface (inside the cavity)! maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); marktest(faketet); // To distinguish it from other faked tets. sesymself(neighsh); tsbond(faketet, neighsh); // Let it hold the subface. for (j = 0; j < 3; j++) { // Bond segments. tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } // Add a top face (at faked tet). topfaces->newindex((void **) &parytet); *parytet = faketet; } } } enext2fnext(crosstet, spintet); enext2self(spintet); symedge(spintet, neightet); // if (!infected(neightet)) { if ((neightet.tet == dummytet) || !infected(neightet)) { // A bottom face. botfaces->newindex((void **) &parytet); if (neightet.tet == dummytet) { // Create a fake tet to hold the boundary face. maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); bond(spintet, faketet); tspivot(spintet, checksh); if (checksh.sh != dummysh) { sesymself(checksh); tsbond(faketet, checksh); } for (j = 0; j < 3; j++) { // Bond segments. tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } *parytet = faketet; } else { *parytet = neightet; } } else { if ((neightet.tet != dummytet) && infected(neightet)) { tspivot(spintet, neighsh); if (neighsh.sh != dummysh) { // Found a subface (inside the cavity)! maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); marktest(faketet); // To distinguish it from other faked tets. sesymself(neighsh); tsbond(faketet, neighsh); // Let it hold the subface. for (j = 0; j < 3; j++) { // Bond segments. tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } // Add a bottom face (at faked tet). botfaces->newindex((void **) &parytet); *parytet = faketet; } } } // Add middle vertices if there are (skip dummypoint). pf = org(spintet); if (!pinfected(pf)) { // if (pf != dummypoint) { pinfect(pf); botpoints->newindex((void **) &ppt); // Add a bottom vertex. *ppt = pf; toppoints->newindex((void **) &ppt); // Add a top vertex. *ppt = pf; // } } pf = dest(spintet); if (!pinfected(pf)) { // if (pf != dummypoint) { pinfect(pf); botpoints->newindex((void **) &ppt); // Add a bottom vertex. *ppt = pf; toppoints->newindex((void **) &ppt); // Add a top vertex. *ppt = pf; // } } } // Unmark all collected top, bottom, and middle vertices. for (i = 0; i < (int) toppoints->objects; i++) { ppt = (point *) fastlookup(toppoints, i); puninfect(*ppt); } for (i = 0; i < (int) botpoints->objects; i++) { ppt = (point *) fastlookup(botpoints, i); puninfect(*ppt); } // Comments: Now no vertex is marked. } /////////////////////////////////////////////////////////////////////////////// // // // delaunizecavity() Fill a cavity by Delaunay tetrahedra. // // // // The tetrahedralizing cavity is the half (top or bottom part) of the whole // // cavity. The boundary faces of the half cavity are given in 'cavfaces', // // the bounday faces of the internal facet are not given. These faces will // // be recovered later in fillcavity(). // // // // This routine first constructs the DT of the vertices by the Bowyer-Watson // // algorithm. Then it identifies the boundary faces of the cavity in DT. // // The DT is returned in 'newtets'. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::delaunizecavity(arraypool *cavpoints, arraypool *cavfaces, arraypool *cavshells, arraypool *newtets, arraypool *crosstets, arraypool *misfaces) { triface *parytet, searchtet, neightet, spintet, *parytet1; triface newtet, faketet; face checksh, tmpsh, *parysh; face checkseg; point pa, pb, pc, pd, pt[3], *parypt; // badface *newflipface; enum interresult dir; REAL ori; // int miscount; int i, j, k; if (b->verbose > 1) { printf(" Delaunizing cavity: %ld points, %ld faces.\n", cavpoints->objects, cavfaces->objects); } // Get four non-coplanar points (no dummypoint). parytet = (triface *) fastlookup(cavfaces, 0); pa = org(*parytet); pb = dest(*parytet); pc = apex(*parytet); pinfect(pa); pinfect(pb); pinfect(pc); pd = NULL; for (i = 1; i < (int) cavfaces->objects; i++) { parytet = (triface *) fastlookup(cavfaces, i); pt[0] = org(*parytet); pt[1] = dest(*parytet); pt[2] = apex(*parytet); for (j = 0; j < 3; j++) { // if (pt[j] != dummypoint) { // Do not include a hull point. if (!pinfected(pt[j])) { ori = orient3d(pa, pb, pc, pt[j]); if (ori != 0) { pd = pt[j]; if (ori > 0) { // Swap pa and pb. pt[j] = pa; pa = pb; pb = pt[j]; } break; } } // } } if (pd != NULL) break; } assert(i < (int) cavfaces->objects); // SELF_CHECK pinfect(pd); // Create an init DT. // initialDT(pa, pb, pc, pd); // Create the initial tet. maketetrahedron(&newtet); if (b->verbose > 2) { printf(" Create the first tet (%d, %d, %d, %d).\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(pd)); } setorg(newtet, pa); setdest(newtet, pb); setapex(newtet, pc); setoppo(newtet, pd); // Update the point-to-tet map. setpoint2tet(pa, encode(newtet)); setpoint2tet(pb, encode(newtet)); setpoint2tet(pc, encode(newtet)); setpoint2tet(pd, encode(newtet)); // Bond to 'dummytet' for point location. dummytet[0] = encode(newtet); recenttet = newtet; // At init, all faces of this tet are hull faces. hullsize = 4; for (i = 0; i < (int) cavpoints->objects; i++) { pt[0] = * (point *) fastlookup(cavpoints, i); assert(pt[0] != dummypoint); // SELF_CHECK if (!pinfected(pt[0])) { searchtet = recenttet; insertvertexbw(pt[0], &searchtet, true, false, false, false); } else { puninfect(pt[0]); // It is already inserted. } } // Comment: All vertices of the cavity are NOT marked. while (1) { // Identify boundary faces. Remember interior tets. Save missing faces. // For each identified boundary face in the new DT, we insert a subface // temporarily at that place. The subface also contains a pointer to // the adjacent tet outside of the cavity. We save the temp subface // with its side facing to the interior of the cavity. for (i = 0; i < (int) cavfaces->objects; i++) { parytet = (triface *) fastlookup(cavfaces, i); // Skip an interior face (due to the enlargement of the cavity). if (infected(*parytet)) continue; // Choose the CCW edge ring. parytet->ver = 4; pt[0] = org(*parytet); pt[1] = dest(*parytet); pt[2] = apex(*parytet); // Create a temp subface. makeshellface(subfaces, &tmpsh); // setshvertices(tmpsh, pt[0], pt[1], pt[2]); setsorg(tmpsh, pt[0]); setsdest(tmpsh, pt[1]); setsapex(tmpsh, pt[2]); // Comment: This side of tmpsh faces to the outside of the cavity. // Insert tmpsh in DT. searchtet.tet = NULL; dir = scoutsubface(&tmpsh, &searchtet, 1); if (dir == SHAREFACE) { // Let tmpsh face to the interior tet of the cavity. if (sorg(tmpsh) == pt[0]) { sesymself(tmpsh); } assert(sorg(tmpsh) == pt[1]); assert(sdest(tmpsh) == pt[0]); } else if (dir == COLLISIONFACE) { // A subface is already inserted. This case can only happen when there // exist a subface inside the cavity, and two faked tets were created // for protecting such a subface (see fig/dum-cavity-case6). assert(oppo(*parytet) == dummypoint); assert(marktested(*parytet)); // This subface is redundant. But it is needed here (to remember the // faked tet and the real subface which is inside the cavity). if ((searchtet.ver & 01) != 0) esymself(searchtet); // Adjust the searchtet to edge pt[1]->pt[0]. if (org(searchtet) != pt[1]) { symedgeself(searchtet); assert(org(searchtet) == pt[1]); // SELF_CHECK } assert(dest(searchtet) == pt[0]); // SELF_CHECK // Only connect: tmpsh<--searchtet. So stpivot() works. sesymself(tmpsh); tmpsh.sh[6 + EdgeRing(tmpsh.shver)] = (shellface) encode(searchtet); } else { if (b->verbose > 1) { printf(" p:draw_subface(%d, %d, %d) -- %d is missing\n", pointmark(pt[0]), pointmark(pt[1]), pointmark(pt[2]), i); } shellfacedealloc(subfaces, tmpsh.sh); // Save this face in list. misfaces->newindex((void **) &parytet1); *parytet1 = *parytet; continue; } // Remember the boundary tet in tmpsh (use the adjacent subface slot). tmpsh.sh[0] = (shellface) encode(*parytet); // Save this subface. cavshells->newindex((void **) &parysh); *parysh = tmpsh; } if (misfaces->objects > 0) { // Removing tempoaray subfaces. for (i = 0; i < (int) cavshells->objects; i++) { parysh = (face *) fastlookup(cavshells, i); stpivot(*parysh, neightet); tsdissolve(neightet); // Detach it from adj. tets. symself(neightet); tsdissolve(neightet); shellfacedealloc(subfaces, parysh->sh); } cavshells->restart(); // Infect the points which are of the cavity for detecting new // cavity point due to the enlargement. for (i = 0; i < (int) cavpoints->objects; i++) { pt[0] = * (point *) fastlookup(cavpoints, i); pinfect(pt[0]); // Mark it as inserted. } // Enlarge the cavity. for (i = 0; i < (int) misfaces->objects; i++) { // Get a missing face. parytet = (triface *) fastlookup(misfaces, i); if (!infected(*parytet)) { if (oppo(*parytet) == dummypoint) { printf("Internal error: A convex hull is missing.\n"); terminatetetgen(2); } // Put it into crossing tet list. infect(*parytet); crosstets->newindex((void **) &parytet1); *parytet1 = *parytet; // Insert the opposite point if it is not in DT. pd = oppo(*parytet); if (!pinfected(pd)) { if (b->verbose > 1) { printf(" Insert the opposite point %d.\n", pointmark(pd)); } pinfect(pd); cavpoints->newindex((void **) &parypt); *parypt = pd; searchtet = recenttet; insertvertexbw(pd, &searchtet, true, false, false, false); } // Check for a missing subface. tspivot(*parytet, checksh); if (checksh.sh != dummysh) { if (b->verbose > 1) { printf(" Queue a subface x%lx (%d, %d, %d).\n", (unsigned long) checksh.sh, pointmark(sorg(checksh)), pointmark(sdest(checksh)), pointmark(sapex(checksh))); } stdissolve(checksh); sesymself(checksh); stdissolve(checksh); subfacstack->newindex((void **) &parysh); *parysh = checksh; } // Add three opposite faces into the boundary list. for (j = 0; j < 3; j++) { fnext(*parytet, spintet); symedge(spintet, neightet); if ((neightet.tet == dummytet) || !infected(neightet)) { if (b->verbose > 1) { printf(" Add a cavface (%d, %d, %d).\n", pointmark(org(spintet)), pointmark(dest(spintet)), pointmark(apex(spintet))); } cavfaces->newindex((void **) &parytet1); if (neightet.tet == dummytet) { maketetrahedron(&faketet); // Create a faked tet. setorg(faketet, org(spintet)); setdest(faketet, dest(spintet)); setapex(faketet, apex(spintet)); setoppo(faketet, dummypoint); bond(spintet, faketet); tspivot(spintet, checksh); if (checksh.sh != dummysh) { sesymself(checksh); tspivot(faketet, checksh); } for (k = 0; k < 3; k++) { tsspivot1(spintet, checkseg); if (checkseg.sh != dummysh) { tssbond1(faketet, checkseg); } enextself(spintet); enextself(faketet); } *parytet1 = faketet; } else { *parytet1 = neightet; } } else { // Check if a subface is missing again. tspivot(neightet, checksh); if (checksh.sh != dummysh) { if (b->verbose > 1) { printf(" Queue a subface x%lx (%d, %d, %d).\n", (unsigned long) checksh.sh, pointmark(sorg(checksh)), pointmark(sdest(checksh)), pointmark(sapex(checksh))); } stdissolve(checksh); sesymself(checksh); stdissolve(checksh); subfacstack->newindex((void **) &parysh); *parysh = checksh; } } enextself(*parytet); } // j } // if (!infected(parytet)) } // Uninfect the points which are of the cavity. for (i = 0; i < (int) cavpoints->objects; i++) { pt[0] = * (point *) fastlookup(cavpoints, i); puninfect(pt[0]); } misfaces->restart(); cavityexpcount++; continue; } break; } // while (1) // Collect all tets of the DT. All new tets are marktested. marktest(recenttet); newtets->newindex((void **) &parytet); *parytet = recenttet; for (i = 0; i < (int) newtets->objects; i++) { searchtet = * (triface *) fastlookup(newtets, i); for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) { sym(searchtet, neightet); if (neightet.tet != dummytet) { if (!marktested(neightet)) { marktest(neightet); newtets->newindex((void **) &parytet); *parytet = neightet; } } } } cavpoints->restart(); // Comment: Now no vertex is marked. cavfaces->restart(); if (cavshells->objects > (unsigned long) maxcavsize) { maxcavsize = cavshells->objects; } return true; } /////////////////////////////////////////////////////////////////////////////// // // // fillcavity() Fill new tets into the cavity. // // // // The new tets are stored in two disjoint sets(which share the same facet). // // 'topfaces' and 'botfaces' are the boundaries of these two sets, respect- // // ively. 'midfaces' is empty on input, and will store faces in the facet. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::fillcavity(arraypool* topshells, arraypool* botshells, arraypool* midfaces, arraypool* facpoints) { arraypool *cavshells; triface *parytet, bdrytet, toptet, bottet, neightet, midface, spintet; face checksh, *parysh; face checkseg; point pa, pb, pc, pf, pg; REAL ori, len, n[3]; bool mflag, bflag; int i, j, k; // Connect newtets to tets outside the cavity. for (k = 0; k < 2; k++) { cavshells = (k == 0 ? topshells : botshells); if (cavshells != NULL) { for (i = 0; i < (int) cavshells->objects; i++) { // Get a temp subface. parysh = (face *) fastlookup(cavshells, i); // Get the boundary tet outsode the cavity. decode(parysh->sh[0], bdrytet); pa = sorg(*parysh); pb = sdest(*parysh); // Fix bdrytet at the edge pb->pa. bdrytet.ver = 0; for (j = 0; j < 3; j++) { if (org(bdrytet) == pb) break; enextself(bdrytet); } assert(j < 3); assert(dest(bdrytet) == pa); // pa = org(bdrytet); // pb = dest(bdrytet); pc = apex(bdrytet); // Get the adjacent new tet which is in the cavity. stpivot(*parysh, neightet); // Fix neightet at the edge pa->pb. neightet.ver = 0; for (j = 0; j < 3; j++) { if (org(neightet) == pa) break; enextself(neightet); } assert(j < 3); assert(dest(neightet) == pb); // SELF_CHECK // Mark neightet as an interior tet of this cavity, 2009-04-24. if (!infected(neightet)) { infect(neightet); } // Comment: bdrytet may be a faked tet, Bond it if it is not // marktested, i.e., it is not created for holding an interor // subface. The connections will be used in fillcavity for // finding middle faces. if (!marktested(bdrytet)) { // Bond the two tets. bond(bdrytet, neightet); // } else { // A new boundary face. // dummytet[0] = encode(neightet); } // Bond a subface (if it exists). tspivot(bdrytet, checksh); if (checksh.sh != dummysh) { sesymself(checksh); tsbond(neightet, checksh); // Also cleared the pointer to tmpsh. } else { tsdissolve(neightet); // No subface, clear the pointer to tmpsh. } // Bond subsegments for (j = 0; j < 3; j++) { tsspivot1(bdrytet, checkseg); if (checkseg.sh != dummysh) { spintet = neightet; while (1) { tssbond1(spintet, checkseg); tfnextself(spintet); if (spintet.tet == dummytet) break; // Outside the cavity. if (!marktested(spintet)) break; // Outside the cavity. if (spintet.tet == neightet.tet) break; // Turn back. } } enextself(bdrytet); enext2self(neightet); } // Update the point-to-tets map. setpoint2tet(pa, encode(neightet)); setpoint2tet(pb, encode(neightet)); setpoint2tet(pc, encode(neightet)); // Delete the temp subface. // shellfacedealloc(subfacepool, parysh->sh); // if (oppo(bdrytet) == dummypoint) { // Delete a faked tet. // tetrahedrondealloc(bdrytet.tet); // } } } // if (cavshells != NULL) } mflag = true; // Initialize it. if (midfaces != NULL) { // Mark all facet vertices for finding middle subfaces. for (i = 0; i < (int) facpoints->objects; i++) { pf = * (point *) fastlookup(facpoints, i); pinfect(pf); } // The first pair of top and bottom tets share the same edge [a, b]. // toptet = * (triface *) fastlookup(topfaces, 0); if (infected(firsttopface)) { // The cavity was enlarged. This tet is included in the interior // (as those of a crossing tet). Find the updated top boundary face // by rotating the faces around this edge (until an uninfect tet). pa = apex(firsttopface); while (1) { tfnextself(firsttopface); assert(firsttopface.tet != dummytet); if (!infected(firsttopface)) break; assert(apex(firsttopface) != pa); // SELF_CHECK } } toptet = firsttopface; symedgeself(toptet); assert(marktested(toptet)); // It must be a new tet. // Search a subface from the top mesh. while (1) { fnextself(toptet); // The next face in the same tet. pc = apex(toptet); if (pinfected(pc)) break; // [a,b,c] is a subface. symedgeself(toptet); // Go to the same face in the adjacent tet. assert(toptet.tet != dummytet); } // Search the subface [a,b,c] in the bottom mesh. // bottet = * (triface *) fastlookup(botfaces, 0); if (infected(firstbotface)) { pa = apex(firstbotface); while (1) { tfnextself(firstbotface); assert(firstbotface.tet != dummytet); if (!infected(firstbotface)) break; assert(apex(firstbotface) != pa); // SELF_CHECK } } bottet = firstbotface; symedgeself(bottet); assert(marktested(bottet)); // It must be a new tet. while (1) { fnextself(bottet); // The next face in the same tet. pf = apex(bottet); if (pf == pc) break; // Face matched. if (pinfected(pf)) { mflag = false; break; // Not matched. } symedgeself(bottet); assert(bottet.tet != dummytet); } if (mflag) { // Connect the two tets together. bond(toptet, bottet); // Both are interior tets. infect(toptet); infect(bottet); // Add this face into search list. // esymself(toptet); // Choose the 0th edge ring. markface(toptet); midfaces->newindex((void **) &parytet); *parytet = toptet; } // Match pairs of subfaces (middle faces), connect top and bottom tets. for (i = 0; i < (int) midfaces->objects && mflag; i++) { // Get a matched middle face [a, b, c] midface = * (triface *) fastlookup(midfaces, i); // It is inside the cavity. assert(marktested(midface)); // SELF_CHECK // Check the neighbors at edges [b, c] and [c, a]. midface.ver = 0; for (j = 0; j < 3 && mflag; j++) { pg = apex(midface); toptet = midface; bflag = false; while (1) { // Go to the next face in the same tet. fnextself(toptet); pc = apex(toptet); if (pinfected(pc)) { break; // Find a subface. } // if (pc == dummypoint) { // break; // Find a subface. // } /* if (pc == pg) { // The adjacent face is not a middle face. bflag = true; break; }*/ symedgeself(toptet); assert(toptet.tet != dummytet); // The adjacent tet must exist. // Do we walk outside the cavity? if (!marktested(toptet)) { // Yes, the adjacent face is not a middle face. bflag = true; break; } } if (!bflag) { // assert(marktested(toptet)); // SELF_CHECK if (!facemarked(toptet)) { symedge(midface, bottet); while (1) { fnextself(bottet); pf = apex(bottet); if (pf == pc) break; // Face matched. if (pinfected(pf)) { mflag = false; break; // Not matched. } symedgeself(bottet); assert(bottet.tet != dummytet); // The adjacent tet must exist. } if (mflag) { if (marktested(bottet)) { // Connect two tets together. bond(toptet, bottet); // Both are interior tets. infect(toptet); infect(bottet); // Add this face into list. // esymself(toptet); markface(toptet); midfaces->newindex((void **) &parytet); *parytet = toptet; } else { // The 'bottet' is not inside the cavity! // This case can happen when the cavity was enlarged, and the // 'toptet' is a co-facet (sub)face adjacent to the missing // region, and it is a boundary face of the top cavity. // So the toptet and bottet should be bonded already through // a temp subface. See fig/dump-cavity-case18. Check it. symedge(toptet, neightet); assert(neightet.tet == bottet.tet); // SELF_CHECK assert(neightet.loc == bottet.loc); // SELF_CHECK // Do not add this face into 'midfaces'. } } } } enextself(midface); // Go to the next edge. } // j } // i } // if (midfaces != NULL) if (mflag) { if (midfaces != NULL) { if (b->verbose > 1) { printf(" Found %ld middle subfaces.\n", midfaces->objects); } if (midfaces->objects > (unsigned long) maxregionsize) { maxregionsize = (long) midfaces->objects; } // Unmark middle faces. for (i = 0; i < (int) midfaces->objects; i++) { // Get a matched middle face [a, b, c] midface = * (triface *) fastlookup(midfaces, i); assert(facemarked(midface)); // SELF_CHECK unmarkface(midface); } } } else { // Faces at top and bottom are not matched. There exists non-Delaunay // subedges. See fig/dump-cavity-case5.lua. pa = org(toptet); pb = dest(toptet); pc = apex(toptet); pf = apex(bottet); if (0) { // if (b->verbose > 1) { printf(" p:draw_tet(%d, %d, %d, %d) -- top tet.\n", pointmark(pa), pointmark(pb), pointmark(pc), pointmark(oppo(toptet))); printf(" p:draw_tet(%d, %d, %d, %d) -- bot tet.\n", pointmark(org(bottet)), pointmark(dest(bottet)), pointmark(apex(bottet)), pointmark(oppo(bottet))); } // Calculate a point above the faces. facenormal2(pa, pb, pc, n, 1); len = sqrt(DOT(n, n)); n[0] /= len; n[1] /= len; n[2] /= len; len = DIST(pa, pb); len += DIST(pb, pc); len += DIST(pc, pa); len /= 3.0; dummypoint[0] = pa[0] + len * n[0]; dummypoint[1] = pa[1] + len * n[1]; dummypoint[2] = pa[2] + len * n[2]; // Find the crossing edges. ori = orient3d(pb, pc, dummypoint, pf); assert(ori != 0); // SELF_CHECK if (ori < 0) { // The top edge [b, c] intersects the bot edge [a, f]. enextself(toptet); enextself(bottet); } else { // The top edge [c, a] intersects the bot edge [f, b]. enext2self(toptet); enext2self(bottet); } // Split one of the edges, choose the one has longer length. n[0] = DIST(org(toptet), dest(toptet)); n[1] = DIST(org(bottet), dest(bottet)); if (n[0] > n[1]) { pf = org(toptet); pg = dest(toptet); } else { pf = org(bottet); pg = dest(bottet); } if (b->verbose > 1) { printf(" Found a non-Delaunay edge (%d, %d)\n", pointmark(pf), pointmark(pg)); } // Create the midpoint of the non-Delaunay edge. for (i = 0; i < 3; i++) { dummypoint[i] = 0.5 * (pf[i] + pg[i]); } // Set a tet for searching the new point. recenttet = firsttopface; // dummypoint[0] = dummypoint[1] = dummypoint[2] = 0; ndelaunayedgecount++; } if (facpoints != NULL) { // Unmark all facet vertices. for (i = 0; i < (int) facpoints->objects; i++) { pf = * (point *) fastlookup(facpoints, i); puninfect(pf); } } // Delete the temp subfaces and faked tets. for (k = 0; k < 2; k++) { cavshells = (k == 0 ? topshells : botshells); if (cavshells != NULL) { for (i = 0; i < (int) cavshells->objects; i++) { parysh = (face *) fastlookup(cavshells, i); decode(parysh->sh[0], bdrytet); if (oppo(bdrytet) == dummypoint) { sym(bdrytet, neightet); if (neightet.tet != dummytet) { // This side is a hull face (not an interior subface). dissolve(neightet); dummytet[0] = encode(neightet); tspivot(neightet, checksh); if (checksh.sh != dummysh) { assert(checksh.sh != parysh->sh); // Dis-coonection tet-subface bond. sesymself(checksh); stdissolve(checksh); } } // Delete a faked tet. tetrahedrondealloc(bdrytet.tet); } shellfacedealloc(subfaces, parysh->sh); } } } topshells->restart(); if (botshells != NULL) { botshells->restart(); } if (midfaces != NULL) { midfaces->restart(); } // Comment: Now no vertex is marked. return mflag; } /////////////////////////////////////////////////////////////////////////////// // // // carvecavity() Delete old tets and outer new tets of the cavity. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::carvecavity(arraypool *crosstets, arraypool *topnewtets, arraypool *botnewtets) { arraypool *newtets; triface *parytet, *pnewtet, neightet; face checkseg; //, *parysh; // int hitbdry; int i, j, k; /*// NOTE: Some subsegments may contained inside the cavity. They must be // queued for recovery. See fig/dump-cavity-case20. for (i = 0; i < (int) crosstets->objects; i++) { parytet = (triface *) fastlookup(crosstets, i); assert(infected(*parytet)); // SELF_CHECK if (parytet->tet[8] != NULL) { for (j = 0; j < 6; j++) { parytet->loc = edge2locver[j][0]; parytet->ver = edge2locver[j][1]; tsspivot1(*parytet, checkseg); if (checkseg.sh != dummysh) { if (!sinfected(checkseg)) { // It is not queued yet. neightet = *parytet; hitbdry = 0; while (1) { tfnextself(neightet); if (neightet.tet == dummytet) { hitbdry++; if (hitbdry == 2) break; esym(*parytet, neightet); tfnextself(neightet); if (neightet.tet == dummytet) break; } if (!infected(neightet)) break; if (apex(neightet) == apex(*parytet)) break; } if (infected(neightet)) { if (b->verbose > 1) { printf(" Queue a missing segment (%d, %d).\n", pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); } sinfect(checkseg); subsegstack->newindex((void **) &parysh); *parysh = checkseg; } } } } } }*/ // Delete the old tets in cavity. for (i = 0; i < (int) crosstets->objects; i++) { parytet = (triface *) fastlookup(crosstets, i); tetrahedrondealloc(parytet->tet); } crosstets->restart(); // crosstets will be re-used. // Collect infected new tets in cavity. for (k = 0; k < 2; k++) { newtets = (k == 0 ? topnewtets : botnewtets); if (newtets != NULL) { for (i = 0; i < (int) newtets->objects; i++) { parytet = (triface *) fastlookup(newtets, i); if (infected(*parytet)) { crosstets->newindex((void **) &pnewtet); *pnewtet = *parytet; } } } } // Collect all new tets in cavity. for (i = 0; i < (int) crosstets->objects; i++) { parytet = (triface *) fastlookup(crosstets, i); if (i == 0) { recenttet = *parytet; // Remember a live handle. } for (j = 0; j < 4; j++) { decode(parytet->tet[j], neightet); if (marktested(neightet)) { // Is it a new tet? if (!infected(neightet)) { // Find an interior tet. assert(neightet.tet != dummytet); // SELF_CHECK infect(neightet); crosstets->newindex((void **) &pnewtet); *pnewtet = neightet; } } } } // Delete outer new tets (those new tets which are not infected). for (k = 0; k < 2; k++) { newtets = (k == 0 ? topnewtets : botnewtets); if (newtets != NULL) { for (i = 0; i < (int) newtets->objects; i++) { parytet = (triface *) fastlookup(newtets, i); if (infected(*parytet)) { // This is an interior tet. uninfect(*parytet); unmarktest(*parytet); } else { // An outer tet. Delete it. tetrahedrondealloc(parytet->tet); } } } } crosstets->restart(); topnewtets->restart(); if (botnewtets != NULL) { botnewtets->restart(); } } /////////////////////////////////////////////////////////////////////////////// // // // restorecavity() Reconnect old tets and delete new tets of the cavity. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::restorecavity(arraypool *crosstets, arraypool *topnewtets, arraypool *botnewtets) { triface *parytet, neightet; face checksh; point *ppt; int i, j; // Reconnect crossing tets to cavity boundary. for (i = 0; i < (int) crosstets->objects; i++) { parytet = (triface *) fastlookup(crosstets, i); assert(infected(*parytet)); // SELF_CHECK if (i == 0) { recenttet = *parytet; // Remember a live handle. } parytet->ver = 0; for (parytet->loc = 0; parytet->loc < 4; parytet->loc++) { sym(*parytet, neightet); // The neighbor may be a deleted faked tet. if (isdead(&neightet) || (neightet.tet == dummytet)) { dissolve(*parytet); // Detach a faked tet. // Remember a boundary tet. dummytet[0] = encode(*parytet); } else if (!infected(neightet)) { bond(*parytet, neightet); tspivot(*parytet, checksh); if (checksh.sh != dummysh) { tsbond(*parytet, checksh); } } } // Update the point-to-tet map. parytet->loc = 0; ppt = (point *) &(parytet->tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(*parytet)); } } // Uninfect all crossing tets. for (i = 0; i < (int) crosstets->objects; i++) { parytet = (triface *) fastlookup(crosstets, i); uninfect(*parytet); } // Delete new tets. for (i = 0; i < (int) topnewtets->objects; i++) { parytet = (triface *) fastlookup(topnewtets, i); tetrahedrondealloc(parytet->tet); } if (botnewtets != NULL) { for (i = 0; i < (int) botnewtets->objects; i++) { parytet = (triface *) fastlookup(botnewtets, i); tetrahedrondealloc(parytet->tet); } } crosstets->restart(); topnewtets->restart(); if (botnewtets != NULL) { botnewtets->restart(); } } /////////////////////////////////////////////////////////////////////////////// // // // splitsubedge() Split a non-Delaunay edge (not a segment) in the // // surface mesh of a facet. // // // // The new point 'newpt' will be inserted in the tetrahedral mesh if it does // // not cause any existing (sub)segments become non-Delaunay. Otherwise, the // // new point is not inserted and one of such subsegments will be split. // // // // Next,the actual inserted new point is also inserted into the surface mesh.// // Non-Delaunay segments and newly created subfaces are queued for recovery. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::splitsubedge(point newpt, face *searchsh, arraypool *facfaces, arraypool *facpoints) { // queue *flipqueue; triface searchtet; face splitsh; face *psseg, sseg; // *parysh; point pa, pb; enum locateresult loc; int s, i; // Try to insert the point. Do not insert if it will encroach any segment // (noencsegflag is TRUE). Queue encroacged subfaces. assert(subsegstack->objects == 0l); // SELF_CHECK searchtet = recenttet; // Start search it from recentet // loc = insertvertexbw(newpt, &searchtet, true, true, true, false); // Always insert this point, missing segments are queued. 2009-06-11. loc = insertvertexbw(newpt, &searchtet, true, true, false, false); if (loc == ENCSEGMENT) { // Some segments are encroached. Randomly pick one to split. assert(subsegstack->objects > 0l); s = randomnation(subsegstack->objects); psseg = (face *) fastlookup(subsegstack, s); sseg = *psseg; pa = sorg(sseg); pb = sdest(sseg); for (i = 0; i < 3; i++) newpt[i] = 0.5 * (pa[i] + pb[i]); setpointtype(newpt, FREESEGVERTEX); setpoint2sh(newpt, sencode(sseg)); // Uninfect all queued segments. for (i = 0; i < (int) subsegstack->objects; i++) { psseg = (face *) fastlookup(subsegstack, i); suninfect(*psseg); } subsegstack->restart(); // Clear the queue. // Split the segment. Two subsegments are queued. sinsertvertex(newpt, searchsh, &sseg, true, false); // Insert the point. Missing segments are queued. searchtet = recenttet; // Start search it from recentet insertvertexbw(newpt, &searchtet, true, true, false, false); } else { /*// Calc an above point for point location in surface triangulation. calculateabovepoint(facpoints, NULL, NULL, NULL); // Insert the new point on facet. New subfaces are queued for reocvery. loc = sinsertvertex(newpt, searchsh, NULL, true, false); if (loc == OUTSIDE) { assert(0); // Not handled yet. } // Clear the above point. dummypoint[0] = dummypoint[1] = dummypoint[2] = 0; */ // Set the abovepoint of f for point location. abovepoint = facetabovepointarray[shellmark(*searchsh)]; if (abovepoint == (point) NULL) { getfacetabovepoint(searchsh); } // Insert the new point on facet. New subfaces are queued for reocvery. loc = sinsertvertex(newpt, searchsh, NULL, true, false); if (loc == OUTSIDE) { assert(0); // Not handled yet. } } } /////////////////////////////////////////////////////////////////////////////// // // // constrainedfacets() Recover subfaces saved in 'subfacestack'. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::constrainedfacets2() { arraypool *crosstets, *topnewtets, *botnewtets; arraypool *topfaces, *botfaces, *midfaces; arraypool *topshells, *botshells, *facfaces; arraypool *toppoints, *botpoints, *facpoints; triface *parytet, searchtet, neightet; face *pssub, ssub, neighsh; face checkseg; point *ppt, pt, newpt; enum interresult dir; bool success, delaunayflag; long bakflip22count; long cavitycount; int facetcount; int bakhullsize; int s, i, j; if (b->verbose) { printf(" Constraining facets.\n"); } // Initialize arrays. crosstets = new arraypool(sizeof(triface), 10); topnewtets = new arraypool(sizeof(triface), 10); botnewtets = new arraypool(sizeof(triface), 10); topfaces = new arraypool(sizeof(triface), 10); botfaces = new arraypool(sizeof(triface), 10); midfaces = new arraypool(sizeof(triface), 10); toppoints = new arraypool(sizeof(point), 8); botpoints = new arraypool(sizeof(point), 8); facpoints = new arraypool(sizeof(point), 8); facfaces = new arraypool(sizeof(face), 10); topshells = new arraypool(sizeof(face), 10); botshells = new arraypool(sizeof(face), 10); bakflip22count = flip22count; cavitycount = 0; facetcount = 0; // Loop until 'subfacstack' is empty. while (subfacstack->objects > 0l) { subfacstack->objects--; pssub = (face *) fastlookup(subfacstack, subfacstack->objects); ssub = *pssub; if (ssub.sh[3] == NULL) continue; // Skip a dead subface. stpivot(ssub, neightet); if (neightet.tet == dummytet) { sesymself(ssub); stpivot(ssub, neightet); } if (neightet.tet == dummytet) { // Find an unrecovered subface. smarktest(ssub); facfaces->newindex((void **) &pssub); *pssub = ssub; // Get all subfaces and vertices of the same facet. for (i = 0; i < (int) facfaces->objects; i++) { ssub = * (face *) fastlookup(facfaces, i); for (j = 0; j < 3; j++) { sspivot(ssub, checkseg); if (checkseg.sh == dummysh) { spivot(ssub, neighsh); assert(neighsh.sh != dummysh); // SELF_CHECK if (!smarktested(neighsh)) { // It may be already recovered. stpivot(neighsh, neightet); if (neightet.tet == dummytet) { sesymself(neighsh); stpivot(neighsh, neightet); } if (neightet.tet == dummytet) { // Add it into list. smarktest(neighsh); facfaces->newindex((void **) &pssub); *pssub = neighsh; } } } pt = sorg(ssub); if (!pinfected(pt)) { pinfect(pt); facpoints->newindex((void **) &ppt); *ppt = pt; } senextself(ssub); } // j } // i // Have found all facet subfaces (vertices). Uninfect them. for (i = 0; i < (int) facfaces->objects; i++) { pssub = (face *) fastlookup(facfaces, i); sunmarktest(*pssub); } for (i = 0; i < (int) facpoints->objects; i++) { ppt = (point *) fastlookup(facpoints, i); puninfect(*ppt); } if (b->verbose > 1) { printf(" Recover facet #%d: %ld subfaces, %ld vertices.\n", facetcount + 1, facfaces->objects, facpoints->objects); } facetcount++; // Loop until 'facfaces' is empty. while (facfaces->objects > 0l) { // Get the last subface of this array. facfaces->objects--; pssub = (face *) fastlookup(facfaces, facfaces->objects); ssub = *pssub; stpivot(ssub, neightet); if (neightet.tet == dummytet) { sesymself(ssub); stpivot(ssub, neightet); } if (neightet.tet != dummytet) continue; // Not a missing subface. // Insert the subface. searchtet.tet = NULL; dir = scoutsubface(&ssub, &searchtet, 1); if (dir == SHAREFACE) continue; // The subface is inserted. assert(dir != COLLISIONFACE); // SELF_CHECK // Not exist. Push the subface back into stack. s = randomnation(facfaces->objects + 1); facfaces->newindex((void **) &pssub); *pssub = * (face *) fastlookup(facfaces, s); * (face *) fastlookup(facfaces, s) = ssub; if (dir == EDGETRIINT) continue; // All three edges are missing. // Search for a crossing tet. dir = scoutcrosstet(&ssub, &searchtet, facpoints); if (dir == INTERTET) { // Recover subfaces by local retetrahedralization. cavitycount++; bakhullsize = hullsize; checksubsegs = checksubfaces = 0; crosstets->newindex((void **) &parytet); *parytet = searchtet; // Form a cavity of crossing tets. formcavity(&ssub, crosstets, topfaces, botfaces, toppoints, botpoints, facpoints, facfaces); delaunayflag = true; // Tetrahedralize the top part. Re-use 'midfaces'. success = delaunizecavity(toppoints, topfaces, topshells, topnewtets, crosstets, midfaces); if (success) { // Tetrahedralize the bottom part. Re-use 'midfaces'. success = delaunizecavity(botpoints, botfaces, botshells, botnewtets, crosstets, midfaces); if (success) { // Fill the cavity with new tets. success = fillcavity(topshells, botshells, midfaces, facpoints); if (success) { // Delete old tets and outer new tets. carvecavity(crosstets, topnewtets, botnewtets); } } else { delaunayflag = false; } } else { delaunayflag = false; } if (!success) { // Restore old tets and delete new tets. restorecavity(crosstets, topnewtets, botnewtets); } /*if (!delaunayflag) { dump_facetof(&ssub, "facet1.lua"); while (futureflip != NULL) { formedgecavity(futureflip->forg, futureflip->fdest, crosstets, topfaces, toppoints); crosstets->restart(); topfaces->restart(); toppoints->restart(); futureflip = futureflip->nextitem; } flippool->restart(); outnodes(0); checkmesh(); checkshells(1); assert(0); // Stop the program. }*/ hullsize = bakhullsize; checksubsegs = checksubfaces = 1; } else if (dir == INTERFACE) { // Recover subfaces by flipping edges in surface mesh. recoversubfacebyflips(&ssub, &searchtet, facfaces); success = true; } else { // dir == TOUCHFACE assert(0); } if (!success) break; } // while if (facfaces->objects > 0l) { // Found a non-Delaunay edge, split it (or a segment close to it). // Create a new point at the middle of this edge, its coordinates // were saved in dummypoint in 'fillcavity()'. makepoint(&newpt); for (i = 0; i < 3; i++) newpt[i] = dummypoint[i]; setpointtype(newpt, FREESUBVERTEX); setpoint2sh(newpt, sencode(ssub)); dummypoint[0] = dummypoint[1] = dummypoint[2] = 0; // Insert the new point. Starting search it from 'ssub'. splitsubedge(newpt, &ssub, facfaces, facpoints); facfaces->restart(); } // Clear the list of facet vertices. facpoints->restart(); // Some subsegments may be queued, recover them. if (subsegstack->objects > 0l) { b->verbose--; // Suppress the message output. delaunizesegments2(); b->verbose++; } // Now the mesh should be constrained Delaunay. } // if (neightet.tet == NULL) } if (b->verbose) { printf(" %ld subedge flips.\n", flip22count - bakflip22count); printf(" %ld cavities remeshed.\n", cavitycount); } // Delete arrays. delete crosstets; delete topnewtets; delete botnewtets; delete topfaces; delete botfaces; delete midfaces; delete toppoints; delete botpoints; delete facpoints; delete facfaces; delete topshells; delete botshells; } /////////////////////////////////////////////////////////////////////////////// // // // formskeleton() Form a constrained tetrahedralization. // // // // The segments and facets of a PLS will be recovered. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::formskeleton(clock_t& tv) { triface searchtet; face *pssub, ssub; int s, i; if (!b->quiet) { printf("Recovering boundaries.\n"); } caveshlist = new arraypool(sizeof(face), 10); caveshbdlist = new arraypool(sizeof(face), 10); // Put all segments into the list. if (b->nojettison == 1) { // '-J' option (for debug) // The sequential order. subsegs->traversalinit(); for (i = 0; i < subsegs->items; i++) { ssub.sh = shellfacetraverse(subsegs); sinfect(ssub); // Only save it once. subsegstack->newindex((void **) &pssub); *pssub = ssub; } } else { // Randomly order the segments. subsegs->traversalinit(); for (i = 0; i < subsegs->items; i++) { s = randomnation(i + 1); // Move the s-th seg to the i-th. subsegstack->newindex((void **) &pssub); *pssub = * (face *) fastlookup(subsegstack, s); // Put i-th seg to be the s-th. ssub.sh = shellfacetraverse(subsegs); sinfect(ssub); // Only save it once. pssub = (face *) fastlookup(subsegstack, s); *pssub = ssub; } } // Segments will be introduced. checksubsegs = 1; // Recover segments. delaunizesegments2(); tv = clock(); // Randomly order the subfaces. subfaces->traversalinit(); for (i = 0; i < subfaces->items; i++) { s = randomnation(i + 1); // Move the s-th subface to the i-th. subfacstack->newindex((void **) &pssub); *pssub = * (face *) fastlookup(subfacstack, s); // Put i-th subface to be the s-th. ssub.sh = shellfacetraverse(subfaces); pssub = (face *) fastlookup(subfacstack, s); *pssub = ssub; } // Subfaces will be introduced. checksubfaces = 1; // Recover facets. constrainedfacets2(); delete caveshlist; delete caveshbdlist; caveshlist = NULL; caveshbdlist = NULL; // Detach all segments from tets. tetrahedrons->traversalinit(); searchtet.tet = tetrahedrontraverse(); while (searchtet.tet != (tetrahedron *) NULL) { if (searchtet.tet[8] != NULL) { for (i = 0; i < 6; i++) { searchtet.loc = edge2locver[i][0]; searchtet.ver = edge2locver[i][1]; tssdissolve1(searchtet); } searchtet.tet[8] = NULL; } searchtet.tet = tetrahedrontraverse(); } // Now no segment is bonded to tets. checksubsegs = 0; // Delete the memory. tet2segpool->restart(); } /////////////////////////////////////////////////////////////////////////////// // // // infecthull() Virally infect all of the tetrahedra of the convex hull // // that are not protected by subfaces. Where there are // // subfaces, set boundary markers as appropriate. // // // // Memorypool 'viri' is used to return all the infected tetrahedra. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::infecthull(memorypool *viri) { triface tetloop, tsymtet; tetrahedron **deadtet; face hullface; // point horg, hdest, hapex; if (b->verbose > 1) { printf(" Marking concavities for elimination.\n"); } tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Is this tetrahedron on the hull? for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { sym(tetloop, tsymtet); if (tsymtet.tet == dummytet) { // Is the tetrahedron protected by a subface? tspivot(tetloop, hullface); if (hullface.sh == dummysh) { // The tetrahedron is not protected; infect it. if (!infected(tetloop)) { infect(tetloop); deadtet = (tetrahedron **) viri->alloc(); *deadtet = tetloop.tet; break; // Go and get next tet. } } else { // The tetrahedron is protected; set boundary markers if appropriate. if (shellmark(hullface) == 0) { setshellmark(hullface, 1); /* horg = sorg(hullface); hdest = sdest(hullface); hapex = sapex(hullface); if (pointmark(horg) == 0) { setpointmark(horg, 1); } if (pointmark(hdest) == 0) { setpointmark(hdest, 1); } if (pointmark(hapex) == 0) { setpointmark(hapex, 1); } */ } } } } tetloop.tet = tetrahedrontraverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // plague() Spread the virus from all infected tets to any neighbors not // // protected by subfaces. // // // // This routine identifies all the tetrahedra that will die, and marks them // // as infected. They are marked to ensure that each tetrahedron is added to // // the virus pool only once, so the procedure will terminate. 'viri' returns // // all infected tetrahedra which are outside the domian. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::plague(memorypool *viri) { tetrahedron **virusloop; tetrahedron **deadtet; triface testtet, neighbor; face neighsh, testseg; face spinsh, casingin, casingout; int firstdadsub; int i; if (b->verbose > 1) { printf(" Marking neighbors of marked tetrahedra.\n"); } firstdadsub = 0; // Loop through all the infected tetrahedra, spreading the virus to // their neighbors, then to their neighbors' neighbors. viri->traversalinit(); virusloop = (tetrahedron **) viri->traverse(); while (virusloop != (tetrahedron **) NULL) { testtet.tet = *virusloop; // Temporarily uninfect this tetrahedron, not necessary. uninfect(testtet); // Check each of the tetrahedron's four neighbors. for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { // Find the neighbor. sym(testtet, neighbor); // Check for a shell between the tetrahedron and its neighbor. tspivot(testtet, neighsh); // Check if the neighbor is nonexistent or already infected. if ((neighbor.tet == dummytet) || infected(neighbor)) { if (neighsh.sh != dummysh) { // There is a subface separating the tetrahedron from its neighbor, // but both tetrahedra are dying, so the subface dies too. // Before deallocte this subface, dissolve the connections between // other subfaces, subsegments and tetrahedra. neighsh.shver = 0; if (!firstdadsub) { firstdadsub = 1; // Report the problem once. if (!b->quiet) { printf("Warning: Detecting an open face (%d, %d, %d).\n", pointmark(sorg(neighsh)), pointmark(sdest(neighsh)), pointmark(sapex(neighsh))); } } // For keep the same enext() direction. findedge(&testtet, sorg(neighsh), sdest(neighsh)); for (i = 0; i < 3; i++) { sspivot(neighsh, testseg); if (testseg.sh != dummysh) { // A subsegment is found at this side, dissolve this subface // from the face link of this subsegment. testseg.shver = 0; spinsh = neighsh; if (sorg(spinsh) != sorg(testseg)) { sesymself(spinsh); } spivot(spinsh, casingout); if ((casingout.sh == spinsh.sh) || (casingout.sh == dummysh)) { // This is a trivial face link, only 'neighsh' itself, // the subsegment at this side is also died. shellfacedealloc(subsegs, testseg.sh); } else { spinsh = casingout; do { casingin = spinsh; spivotself(spinsh); } while (spinsh.sh != neighsh.sh); // Set the link casingin->casingout. sbond1(casingin, casingout); // Bond the subsegment anyway. ssbond(casingin, testseg); } } senextself(neighsh); enextself(testtet); } if (neighbor.tet != dummytet) { // Make sure the subface doesn't get deallocated again later // when the infected neighbor is visited. tsdissolve(neighbor); } // This subface has been separated. if (in->mesh_dim > 2) { shellfacedealloc(subfaces, neighsh.sh); } else { // Dimension is 2. keep it for output. // Dissolve tets at both sides of this subface. stdissolve(neighsh); sesymself(neighsh); stdissolve(neighsh); } } } else { // The neighbor exists and is not infected. if (neighsh.sh == dummysh) { // There is no subface protecting the neighbor, infect it. infect(neighbor); // Ensure that the neighbor's neighbors will be infected. deadtet = (tetrahedron **) viri->alloc(); *deadtet = neighbor.tet; } else { // The neighbor is protected by a subface. // Remove this tetrahedron from the subface. stdissolve(neighsh); // The subface becomes a boundary. Set markers accordingly. if (shellmark(neighsh) == 0) { setshellmark(neighsh, 1); } // This side becomes hull. Update the handle in dummytet. dummytet[0] = encode(neighbor); } } } // Remark the tetrahedron as infected, so it doesn't get added to the // virus pool again. infect(testtet); virusloop = (tetrahedron **) viri->traverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // regionplague() Spread regional attributes and/or volume constraints // // (from a .poly file) throughout the mesh. // // // // This procedure operates in two phases. The first phase spreads an attri- // // bute and/or a volume constraint through a (facet-bounded) region. The // // second phase uninfects all infected tetrahedra, returning them to normal. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh:: regionplague(memorypool *regionviri, REAL attribute, REAL volume) { tetrahedron **virusloop; tetrahedron **regiontet; triface testtet, neighbor; face neighsh; if (b->verbose > 1) { printf(" Marking neighbors of marked tetrahedra.\n"); } // Loop through all the infected tetrahedra, spreading the attribute // and/or volume constraint to their neighbors, then to their neighbors' // neighbors. regionviri->traversalinit(); virusloop = (tetrahedron **) regionviri->traverse(); while (virusloop != (tetrahedron **) NULL) { testtet.tet = *virusloop; // Temporarily uninfect this tetrahedron, not necessary. uninfect(testtet); if (b->regionattrib) { // Set an attribute. setelemattribute(testtet.tet, in->numberoftetrahedronattributes, attribute); } if (b->varvolume) { // Set a volume constraint. setvolumebound(testtet.tet, volume); } // Check each of the tetrahedron's four neighbors. for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { // Find the neighbor. sym(testtet, neighbor); // Check for a subface between the tetrahedron and its neighbor. tspivot(testtet, neighsh); // Make sure the neighbor exists, is not already infected, and // isn't protected by a subface, or is protected by a nonsolid // subface. if ((neighbor.tet != dummytet) && !infected(neighbor) && (neighsh.sh == dummysh)) { // Infect the neighbor. infect(neighbor); // Ensure that the neighbor's neighbors will be infected. regiontet = (tetrahedron **) regionviri->alloc(); *regiontet = neighbor.tet; } } // Remark the tetrahedron as infected, so it doesn't get added to the // virus pool again. infect(testtet); virusloop = (tetrahedron **) regionviri->traverse(); } // Uninfect all tetrahedra. if (b->verbose > 1) { printf(" Unmarking marked tetrahedra.\n"); } regionviri->traversalinit(); virusloop = (tetrahedron **) regionviri->traverse(); while (virusloop != (tetrahedron **) NULL) { testtet.tet = *virusloop; uninfect(testtet); virusloop = (tetrahedron **) regionviri->traverse(); } // Empty the virus pool. regionviri->restart(); } /////////////////////////////////////////////////////////////////////////////// // // // removeholetets() Remove tetrahedra which are outside the domain. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::removeholetets(memorypool* viri) { tetrahedron **virusloop; triface testtet, neighbor; point checkpt; int *tetspernodelist; int i, j; if (b->verbose > 1) { printf(" Deleting marked tetrahedra.\n"); } // Create and initialize 'tetspernodelist'. tetspernodelist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) tetspernodelist[i] = 0; // Loop the tetrahedra list, counter the number of tets sharing each node. tetrahedrons->traversalinit(); testtet.tet = tetrahedrontraverse(); while (testtet.tet != (tetrahedron *) NULL) { // Increment the number of sharing tets for each endpoint. for (i = 0; i < 4; i++) { j = pointmark((point) testtet.tet[4 + i]); tetspernodelist[j]++; } testtet.tet = tetrahedrontraverse(); } viri->traversalinit(); virusloop = (tetrahedron **) viri->traverse(); while (virusloop != (tetrahedron **) NULL) { testtet.tet = *virusloop; // Record changes in the number of boundary faces, and disconnect // dead tetrahedra from their neighbors. for (testtet.loc = 0; testtet.loc < 4; testtet.loc++) { sym(testtet, neighbor); if (neighbor.tet == dummytet) { // There is no neighboring tetrahedron on this face, so this face // is a boundary face. This tetrahedron is being deleted, so this // boundary face is deleted. hullsize--; } else { // Disconnect the tetrahedron from its neighbor. dissolve(neighbor); // There is a neighboring tetrahedron on this face, so this face // becomes a boundary face when this tetrahedron is deleted. hullsize++; } } // Check the four corners of this tet if they're isolated. for (i = 0; i < 4; i++) { checkpt = (point) testtet.tet[4 + i]; j = pointmark(checkpt); tetspernodelist[j]--; if (tetspernodelist[j] == 0) { // If it is added volume vertex or '-j' is not used, delete it. if ((pointtype(checkpt) == FREEVOLVERTEX) || !b->nojettison) { setpointtype(checkpt, UNUSEDVERTEX); unuverts++; } } } // Return the dead tetrahedron to the pool of tetrahedra. tetrahedrondealloc(testtet.tet); virusloop = (tetrahedron **) viri->traverse(); } delete [] tetspernodelist; } /////////////////////////////////////////////////////////////////////////////// // // // assignregionattribs() Assign each tetrahedron a region number. // // // // This routine is called when '-AA' switch is specified. Every tetrahedron // // of a (bounded) region will get a integer number to that region. Default, // // regions are numbered as 1, 2, 3, etc. However, if a number has already // // been used (set by user in the region section in .poly or .smesh), it is // // skipped and the next available number will be used. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::assignregionattribs() { list *regionnumlist; list *regiontetlist; triface tetloop, regiontet, neightet; face checksh; bool flag; int regionnum, num; int attridx, count; int i; if (b->verbose > 1) { printf(" Assign region numbers.\n"); } regionnumlist = new list(sizeof(int), NULL, 256); regiontetlist = new list(sizeof(triface), NULL, 1024); attridx = in->numberoftetrahedronattributes; // Loop through all tets. Infect tets which already have a region number, // and save the used numbers in 'regionnumlist'. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { if (!infected(tetloop)) { regionnum = (int) elemattribute(tetloop.tet, attridx); if (regionnum != 0.0) { // Found a numbered region tet. infect(tetloop); regiontetlist->append(&tetloop); // Found and infect all tets in this region. for (i = 0; i < regiontetlist->len(); i++) { regiontet = * (triface *)(* regiontetlist)[i]; for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) { // Is there a boundary face? tspivot(regiontet, checksh); if (checksh.sh == dummysh) { sym(regiontet, neightet); if ((neightet.tet != dummytet) && !infected(neightet)) { #ifdef SELF_CHECK // neightet should have the same region number. Check it. num = (int) elemattribute(neightet.tet, attridx); assert(num == regionnum); #endif infect(neightet); regiontetlist->append(&neightet); } } } } // Add regionnum to list if it is not exist. flag = false; for (i = 0; i < regionnumlist->len() && !flag; i++) { num = * (int *)(* regionnumlist)[i]; flag = (num == regionnum); } if (!flag) regionnumlist->append(®ionnum); // Clear list for the next region. regiontetlist->clear(); } } tetloop.tet = tetrahedrontraverse(); } if (b->verbose) { printf(" %d user-specified regions.\n", regionnumlist->len()); } // Now loop the tets again. Assign region numbers to uninfected tets. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); regionnum = 1; // Start region number. count = 0; while (tetloop.tet != (tetrahedron *) NULL) { if (!infected(tetloop)) { // An unassigned region tet. count++; do { flag = false; // Check if the region number has been used. for (i = 0; i < regionnumlist->len() && !flag; i++) { num = * (int *)(* regionnumlist)[i]; flag = (num == regionnum); } if (flag) regionnum++; } while (flag); setelemattribute(tetloop.tet, attridx, (REAL) regionnum); infect(tetloop); regiontetlist->append(&tetloop); // Found and infect all tets in this region. for (i = 0; i < regiontetlist->len(); i++) { regiontet = * (triface *)(* regiontetlist)[i]; for (regiontet.loc = 0; regiontet.loc < 4; regiontet.loc++) { // Is there a boundary face? tspivot(regiontet, checksh); if (checksh.sh == dummysh) { sym(regiontet, neightet); if ((neightet.tet != dummytet) && !infected(neightet)) { #ifdef SELF_CHECK // neightet should have not been assigned yet. Check it. num = (int) elemattribute(neightet.tet, attridx); assert(num == 0); #endif setelemattribute(neightet.tet, attridx, (REAL) regionnum); infect(neightet); regiontetlist->append(&neightet); } } } } regiontetlist->clear(); regionnum++; // The next region number. } tetloop.tet = tetrahedrontraverse(); } // Uninfect all tets. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { #ifdef SELF_CHECK assert(infected(tetloop)); #endif uninfect(tetloop); tetloop.tet = tetrahedrontraverse(); } if (b->verbose) { printf(" %d regions are numbered.\n", count); } delete regionnumlist; delete regiontetlist; } /////////////////////////////////////////////////////////////////////////////// // // // carveholes() Find the holes and infect them. Find the volume // // constraints and infect them. Infect the convex hull. // // Spread the infection and kill tetrahedra. Spread the // // volume constraints. // // // // This routine mainly calls other routines to carry out all these functions.// // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::carveholes() { memorypool *holeviri, *regionviri; tetrahedron *tptr, **holetet, **regiontet; triface searchtet, *holetets, *regiontets; enum locateresult intersect; int i; if (!b->quiet) { printf("Removing exterior tetrahedra.\n"); if ((b->verbose > 1) && (in->numberofholes > 0)) { printf(" Marking holes for elimination.\n"); } } // Initialize a pool of viri to be used for holes, concavities. holeviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0); // Mark as infected any unprotected tetrahedra on the boundary. infecthull(holeviri); if (in->numberofholes > 0) { // Allocate storage for the tetrahedra in which hole points fall. holetets = (triface *) new triface[in->numberofholes]; // Infect each tetrahedron in which a hole lies. for (i = 0; i < 3 * in->numberofholes; i += 3) { // Ignore holes that aren't within the bounds of the mesh. if ((in->holelist[i] >= xmin) && (in->holelist[i] <= xmax) && (in->holelist[i + 1] >= ymin) && (in->holelist[i + 1] <= ymax) && (in->holelist[i + 2] >= zmin) && (in->holelist[i + 2] <= zmax)) { searchtet.tet = dummytet; // Find a tetrahedron that contains the hole. intersect = locate(&in->holelist[i], &searchtet); if ((intersect != OUTSIDE) && (!infected(searchtet))) { // Record the tetrahedron for processing carve hole. holetets[i / 3] = searchtet; } } } // Infect the hole tetrahedron. This is done by marking the tet as // infected and including the tetrahedron in the virus pool. for (i = 0; i < in->numberofholes; i++) { infect(holetets[i]); holetet = (tetrahedron **) holeviri->alloc(); *holetet = holetets[i].tet; } // Free up memory. delete [] holetets; } // Mark as infected all tets of the holes and concavities. plague(holeviri); // The virus pool contains all outside tets now. // Is -A switch in use. if (b->regionattrib) { // Assign every tetrahedron a regional attribute of zero. tetrahedrons->traversalinit(); tptr = tetrahedrontraverse(); while (tptr != (tetrahedron *) NULL) { setelemattribute(tptr, in->numberoftetrahedronattributes, 0.0); tptr = tetrahedrontraverse(); } } if (in->numberofregions > 0) { if (b->verbose > 1) { if (b->regionattrib) { if (b->varvolume) { printf("Spreading regional attributes and volume constraints.\n"); } else { printf("Spreading regional attributes.\n"); } } else { printf("Spreading regional volume constraints.\n"); } } // Allocate storage for the tetrahedra in which region points fall. regiontets = (triface *) new triface[in->numberofregions]; // Find the starting tetrahedron for each region. for (i = 0; i < in->numberofregions; i++) { regiontets[i].tet = dummytet; // Ignore region points that aren't within the bounds of the mesh. if ((in->regionlist[5 * i] >= xmin) && (in->regionlist[5 * i] <= xmax) && (in->regionlist[5 * i + 1] >= ymin) && (in->regionlist[5 * i + 1] <= ymax) && (in->regionlist[5 * i + 2] >= zmin) && (in->regionlist[5 * i + 2] <= zmax)) { searchtet.tet = dummytet; // Find a tetrahedron that contains the region point. intersect = locate(&in->regionlist[5 * i], &searchtet); if ((intersect != OUTSIDE) && (!infected(searchtet))) { // Record the tetrahedron for processing after the // holes have been carved. regiontets[i] = searchtet; } } } // Initialize a pool to be used for regional attrs, and/or regional // volume constraints. regionviri = new memorypool(sizeof(tetrahedron *), 1024, POINTER, 0); // Find and set all regions. for (i = 0; i < in->numberofregions; i++) { if (regiontets[i].tet != dummytet) { // Make sure the tetrahedron under consideration still exists. // It may have been eaten by the virus. if (!isdead(&(regiontets[i]))) { // Put one tetrahedron in the virus pool. infect(regiontets[i]); regiontet = (tetrahedron **) regionviri->alloc(); *regiontet = regiontets[i].tet; // Apply one region's attribute and/or volume constraint. regionplague(regionviri, in->regionlist[5 * i + 3], in->regionlist[5 * i + 4]); // The virus pool should be empty now. } } } // Free up memory. delete [] regiontets; delete regionviri; } // Now acutually remove the outside and hole tets. removeholetets(holeviri); // The mesh is nonconvex now. nonconvex = 1; // Update the point-to-tet map. makepoint2tetmap(); if (b->regionattrib) { if (b->regionattrib > 1) { // -AA switch. Assign each tet a region number (> 0). assignregionattribs(); } // Note the fact that each tetrahedron has an additional attribute. in->numberoftetrahedronattributes++; } // Free up memory. delete holeviri; } //// //// //// //// //// constrained_cxx ////////////////////////////////////////////////////////// //// steiner_cxx ////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // initializecavity() Initialize the cavity. // // // // A cavity C is bounded by a list of faces, called fronts. Each front f is // // hold by a tet t adjacent to C, t is not in C (uninfected). If f is a hull // // face, t does't exist, a fake tet t' is created to hold f. t' has the same // // vertices as f but no opposite. t' will be removed automatically after C // // is filled with new tets (by carvecavity()). // // // // The faces of C are given in two lists. 'floorlist' is a set of subfaces, // // each subface has been oriented to face to the inside of C. 'ceillist' is // // a set of tetrahedral faces. 'frontlist' returns the initialized fronts. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::initializecavity(list* floorlist, list* ceillist, list* frontlist, list *ptlist, list* glueshlist) { triface neightet, casingtet; triface faketet; face worksh; point *ppt; int i, j; // Infect all points of the re-triangulated cavity. for (i = 0; i < ptlist->len(); i++) { ppt = (point *)(* ptlist)[i]; pinfect(*ppt); } // Initialize subfaces of C. for (i = 0; i < floorlist->len(); i++) { // Get a subface s. worksh = * (face *)(* floorlist)[i]; #ifdef SELF_CHECK // Current side of s should be empty. stpivot(worksh, neightet); assert(neightet.tet == dummytet); #endif // Do not insert it if some of its vertices are not in Mesh. ppt = (point *) &(worksh.sh[3]); for (j = 0; j < 3; j++) { if (!pinfected(ppt[j])) break; } if (j < 3) { // Found a subface lies outside the cavity. See an example in // dump-SteinerRemoval-case2.lua. // Add this subface in glueshlist (to process it later). glueshlist->append(&worksh); // Do not add this face into frontlist. continue; } // Get the adjacent tet t. sesymself(worksh); stpivot(worksh, casingtet); // Does t exist? if (casingtet.tet == dummytet) { // Create a fake tet t' to hold f temporarily. maketetrahedron(&faketet); setorg(faketet, sorg(worksh)); setdest(faketet, sdest(worksh)); setapex(faketet, sapex(worksh)); setoppo(faketet, (point) NULL); // Indicates it is 'fake'. tsbond(faketet, worksh); frontlist->append(&faketet); } else { frontlist->append(&casingtet); } } // Initialize tet faces of C. for (i = 0; i < ceillist->len(); i++) { // Get a tet face c. neightet = * (triface *) (* ceillist)[i]; #ifdef SELF_CHECK // The tet of c must be inside C (going to be deleted). assert(infected(neightet)); #endif // Get the adjacent tet t. sym(neightet, casingtet); // Does t exist? if (casingtet.tet == dummytet) { // No. Create a fake tet t' to hold f temporarily. maketetrahedron(&faketet); // Be sure that the vertices of t' are CCW oriented. adjustedgering(neightet, CW); // CW edge ring. setorg(faketet, org(neightet)); setdest(faketet, dest(neightet)); setapex(faketet, apex(neightet)); setoppo(faketet, (point) NULL); // Indicates it is 'fake'. // Bond t' to a subface if it exists. tspivot(neightet, worksh); if (worksh.sh != dummysh) { sesymself(worksh); tsbond(faketet, worksh); } // Bond c <--> t'. So we're able to find t' and remove it. bond(faketet, neightet); // c may become uninfected due to the bond(). infect(neightet); frontlist->append(&faketet); } else { frontlist->append(&casingtet); } } // Uninfect all points of the re-triangulated cavity. for (i = 0; i < ptlist->len(); i++) { ppt = (point *)(* ptlist)[i]; puninfect(*ppt); } } /////////////////////////////////////////////////////////////////////////////// // // // delaunizecavvertices() Form a DT of the vertices of a cavity. // // // // 'floorptlist' and 'ceilptlist' are the vertices of the cavity. // // // // The tets of the DT are created directly in the pool 'tetrahedrons', i.e., // // no auxiliary data structure and memory are required. The trick is at the // // time they're created, there are no connections between them to the other // // tets in the pool. You can imagine they form an ioslated island. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::delaunizecavvertices(triface* oldtet, list* floorptlist, list* ceilptlist, list* newtetlist, queue* flipque) { point *insertarray; triface bakhulltet, newtet; long bakhullsize; long arraysize; bool success; int bakchksub; int i, j; // Prepare the array of points for inserting. arraysize = floorptlist->len(); if (ceilptlist != (list *) NULL) { arraysize += ceilptlist->len(); } insertarray = new point[arraysize]; for (i = 0; i < floorptlist->len(); i++) { insertarray[i] = * (point *)(* floorptlist)[i]; } if (ceilptlist != (list *) NULL) { for (j = 0; j < ceilptlist->len(); j++) { insertarray[i + j] = * (point *)(* ceilptlist)[j]; } } // The incrflipdelaunay() is re-used. Backup global variables. decode(dummytet[0], bakhulltet); bakhullsize = hullsize; bakchksub = checksubfaces; checksubfaces = 0; b->verbose--; // Form the DT by incremental flip Delaunay algorithm. Do not jump for // point location, do not merge points. success = incrflipdelaunay(oldtet, insertarray, arraysize, false, false, 0.0, flipque); delete [] insertarray; if (success) { // Get a tet in D. decode(dummytet[0], newtet); newtetlist->append(&newtet); // Get all tets of D. retrievenewtets(newtetlist); } // Restore global variables. dummytet[0] = encode(bakhulltet); hullsize = bakhullsize; checksubfaces = bakchksub; b->verbose++; return success; } /////////////////////////////////////////////////////////////////////////////// // // // retrievenewtets() Retrieve the newly created tets. // // // // On input, 'newtetlist' contains at least one alive new tet. From this tet,// // other new tets can be found by a broadth-first searching. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::retrievenewtets(list* newtetlist) { triface searchtet, casingtet; int i; // There may be dead tets due to flip32(). Delete them first. for (i = 0; i < newtetlist->len(); i++) { searchtet = * (triface *)(* newtetlist)[i]; if (isdead(&searchtet)) { newtetlist->del(i, 0); i--; continue; } infect(searchtet); } // It is possible that all tets are deleted. Check it. 2009-07-27. if (newtetlist->len() == 0) { // We must add a live tet to the list for the retrieving. decode(dummytet[0], searchtet); assert(searchtet.tet != dummytet); assert(!isdead(&searchtet)); infect(searchtet); newtetlist->append(&searchtet); } // Find all new tets. for (i = 0; i < newtetlist->len(); i++) { searchtet = * (triface *)(* newtetlist)[i]; for (searchtet.loc = 0; searchtet.loc < 4; searchtet.loc++) { sym(searchtet, casingtet); if ((casingtet.tet != dummytet) && !infected(casingtet)) { infect(casingtet); newtetlist->append(&casingtet); } } } // Uninfect new tets. for (i = 0; i < newtetlist->len(); i++) { searchtet = * (triface *)(* newtetlist)[i]; uninfect(searchtet); } } /////////////////////////////////////////////////////////////////////////////// // // // insertauxsubface() Fix an auxilary subface in place. // // // // An auxilary subface s is fixed in D as it is a real subface, but s has no // // vertices and neighbors. It has two uses: (1) it protects an identfied // // front f in D; (2) it serves the link to bond a tet in C and f later. The // // first neighbor of s (s->sh[0]) stores a pointer to f. // // // // 'front' is a front f of C. idfront' t is a tet in D where f is identified // // be a face of it. s will be fixed between t and its neighbor. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::insertauxsubface(triface* front, triface* idfront) { triface neightet; face auxsh; // Create the aux subface s. makeshellface(subfaces, &auxsh); // Bond s <--> t. tsbond(*idfront, auxsh); // Does t's neighbor n exist? sym(*idfront, neightet); if (neightet.tet != dummytet) { // Bond s <--> n. sesymself(auxsh); tsbond(neightet, auxsh); } // Let s remember f. auxsh.sh[0] = (shellface) encode(*front); } /////////////////////////////////////////////////////////////////////////////// // // // scoutfront() Scout a face in D. // // // // Search a 'front' f in D. If f is found, return TRUE and the face of D is // // returned in 'idfront'. Otherwise, return FALSE. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::scoutfront(triface* front, triface* idfront) { triface spintet; face checksh; // For debug. point pa, pb, pc; enum finddirectionresult col; int hitbdry; // Let the front we're searching is abc. pa = org(*front); pb = dest(*front); point2tetorg(pa, *idfront); assert(org(*idfront) == pa); recenttet = *idfront; // Search a tet having edge ab. col = finddirection(idfront, pb, tetrahedrons->items); if (col == RIGHTCOLLINEAR) { // b is just the destination. } else if (col == LEFTCOLLINEAR) { enext2self(*idfront); esymself(*idfront); } else if (col == TOPCOLLINEAR) { fnextself(*idfront); enext2self(*idfront); esymself(*idfront); } else if (col == BELOWHULL) { // This front must be a dangling subface outside the cavity. // See an example in dump-SteinerRemoval-case2.lua. assert(0); } if (dest(*idfront) == pb) { // Search a tet having face abc pc = apex(*front); spintet = *idfront; hitbdry = 0; do { if (apex(spintet) == pc) { // Found abc. Insert an auxilary subface s at idfront. // insertauxsubface(front, &spintet); *idfront = spintet; return true; } if (!fnextself(spintet)) { hitbdry ++; if (hitbdry < 2) { esym(*idfront, spintet); if (!fnextself(spintet)) { hitbdry ++; } } } if (apex(spintet) == apex(*idfront)) break; } while (hitbdry < 2); } // f is missing in D. if (b->verbose > 1) { printf(" Front (%d, %d, %d) is missing.\n", pointmark(pa), pointmark(pb), pointmark(apex(*front))); } return false; } /////////////////////////////////////////////////////////////////////////////// // // // gluefronts() Glue two fronts together. // // // // This is a support routine for identifyfront(). Two fronts f and f1 are // // found indentical. This is caused by the non-coplanarity of vertices of a // // facet. Hence f and f1 are a subface and a tet. They are not fronts of the // // cavity anymore. This routine glues f and f1 together. // // // // A tet containing this front and not in the cavity is added into 'gluetet- // // list' (either f or f1). It will be used to maintain the point-to-tet map. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::gluefronts(triface* front, triface* front1, list* gluetetlist, list *glueshlist) { face consh; // Glue f and f1 together. There're four cases: // (1) both f and f1 are not fake; // (2) f is not fake, f1 is fake; // (3) f is fake and f1 is not fake; // (4) both f and f1 are fake. // Case (4) should be not possible. // Is there a concrete subface c at f. tspivot(*front, consh); if (consh.sh != dummysh) { sesymself(consh); tsbond(*front1, consh); // Bond: f1 <--> c. sesymself(consh); // Save this subface if it is not a temp subface. In case the mesh cavity // fails, we need to restore the original state. if (!isdead(&consh)) { // Save this subface into list. glueshlist->append(&consh); } } // Does f hold by a fake tet. if (oppo(*front) == (point) NULL) { // f is fake. Case (3) or (4). assert(oppo(*front1) != (point) NULL); // Eliminate (4). // Case (3). if (consh.sh != dummysh) { stdissolve(consh); // Dissolve: c -x-> f. } // Dealloc f. tetrahedrondealloc(front->tet); // f1 becomes a hull. let 'dummytet' bond to it. dummytet[0] = encode(*front1); } else { // Case (1) or (2). bond(*front, *front1); // Bond f1 <--> f. // Add f into list. gluetetlist->append(front); } // Is f a fake tet? if (!isdead(front)) { // No. Check for case (2). tspivot(*front1, consh); // Is f1 fake? if (oppo(*front1) == (point) NULL) { // Case (2) or (4) assert(oppo(*front) != (point) NULL); // Eliminate (4). // Case (2). if (consh.sh != dummysh) { stdissolve(consh); // Dissolve: c -x-> f1. sesymself(consh); // Bond: f <--> c. tsbond(*front, consh); // Save this subface if it is not a temp subface. In case the mesh // cavity fails, we need to restore the original state. if (!isdead(&consh)) { // Save this subface into list. glueshlist->append(&consh); } } // Dissolve: f -x->f1. dissolve(*front); // Dealloc f1. tetrahedrondealloc(front1->tet); // f becomes a hull. let 'dummytet' bond to it. dummytet[0] = encode(*front); } else { // Case (1). if (consh.sh != dummysh) { sesymself(consh); tsbond(*front, consh); // Bond: f <--> c. // Save this subface if it is not a temp subface. In case the mesh // cavity fails, we need to restore the original state. if (!isdead(&consh)) { // Save this subface into list. glueshlist->append(&consh); } } // Add f1 into list. gluetetlist->append(front1); } } } /////////////////////////////////////////////////////////////////////////////// // // // identifyfronts() Identify cavity faces in D. // // // // 'frontlist' are fronts of C need indentfying. This routine searches each // // front f in D. Once f is found, an auxilary subface s is inserted in D at // // the face. If f is not found in D, remove it from frontlist and save it in // // 'misfrontlist'. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::identifyfronts(list* frontlist, list* misfrontlist, list* gluetetlist, list* glueshlist) { triface front, front1, tfront; triface idfront, neightet; face auxsh, checksh; int len, i, j; misfrontlist->clear(); // Identify all fronts in D. for (i = 0; i < frontlist->len(); i++) { // Get a front f. front = * (triface *)( *frontlist)[i]; if (scoutfront(&front, &idfront)) { // Found f. Insert an aux subface s. tspivot(idfront, auxsh); if (auxsh.sh != dummysh) { // Does s already exist? // There're two identical fronts, f (front) and f1 (s.sh[0])! decode((tetrahedron) auxsh.sh[0], front1); assert((front1.tet != dummytet) && !infected(front1)); // Detach s in D. tsdissolve(idfront); sym(idfront, neightet); if (neightet.tet != dummytet) { tsdissolve(neightet); } // s has fulfilled its duty. Can be deleted. shellfacedealloc(subfaces, auxsh.sh); // Remove f from frontlist. frontlist->del(i, 1); i--; // Remove f1 from frontlist. len = frontlist->len(); for (j = 0; j < frontlist->len(); j++) { tfront = * (triface *)(* frontlist)[j]; if ((tfront.tet == front1.tet) && (tfront.loc == front1.loc)) { // Found f1 in list. Check f1 != f. assert((tfront.tet != front.tet) || (tfront.loc != front.loc)); frontlist->del(j, 1); i--; break; } } assert((frontlist->len() + 1) == len); // Glue f and f1 together. gluefronts(&front, &front1, gluetetlist, glueshlist); } else { // Insert an aux subface to protect f in D. insertauxsubface(&front, &idfront); } } else { // f is missing. frontlist->del(i, 1); i--; // Are there two identical fronts, f (front) and f1 (front1)? for (j = 0; j < misfrontlist->len(); j++) { front1 = * (triface *)(* misfrontlist)[j]; if (isfacehaspoint(&front1, org(front)) && isfacehaspoint(&front1, dest(front)) && isfacehaspoint(&front1, apex(front))) break; } if (j < misfrontlist->len()) { // Found an identical front f1. Remove f1 from the list. misfrontlist->del(j, 1); // Glue f and f1 together. gluefronts(&front, &front1, gluetetlist, glueshlist); } else { // Add f into misfrontlist. misfrontlist->append(&front); } } } return misfrontlist->len() == 0; } /////////////////////////////////////////////////////////////////////////////// // // // detachauxsubfaces() Detach auxilary subfaces in D. // // // // This is a reverse routine of identifyfronts(). Some fronts are missing in // // D. C can not be easily tetrahedralized. It needs remediation (expansion, // // or constrained flips, or adding a Steiner point). This routine detaches // // the auxilary subfaces have been inserted in D and delete them. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::detachauxsubfaces(list* newtetlist) { triface newtet, neightet; face auxsh; int i; for (i = 0; i < newtetlist->len(); i++) { // Get a new tet t. newtet = * (triface *)(* newtetlist)[i]; // t may e dead due to flips. if (isdead(&newtet)) continue; assert(!infected(newtet)); // Check the four faces of t. for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) { tspivot(newtet, auxsh); if (auxsh.sh != dummysh) { // An auxilary subface s. assert(sorg(auxsh) == (point) NULL); tsdissolve(newtet); // t -x-> s. sym(newtet, neightet); if (neightet.tet != dummytet) { assert(!isdead(&neightet)); tsdissolve(neightet); // n -x-> s. } // Delete s. shellfacedealloc(subfaces, auxsh.sh); } } } } /////////////////////////////////////////////////////////////////////////////// // // // carvecavity() Remove redundant (outside) tetrahedra from D. // // // // The fronts of C have been identified in D. Hence C can be tetrahedralized // // by removing the tets outside C. The CDT is then updated by filling C with // // the remaining tets (inside C) of D. // // // // Each front is protected by an auxilary subface s in D. s has a pointer to // // f (s.sh[0]). f can be used to classified the in- and out- tets of C (the // // CW orientation of f faces to the inside of C). The classified out-tets of // // C are marked (infected) for removing. // // // // Notice that the out-tets may not only the tets on the CH of C, but also // // tets completely inside D, eg., there is a "hole" in D. Such tets must be // // marked during classification. The hole tets are poped up and removed too. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::carvecavity(list* newtetlist, list* outtetlist, list* gluetetlist, queue* flipque) { triface newtet, neightet, front, intet, outtet, oldtet; face auxsh, consh; point pa, pb, pc; point pointptr; REAL ori; bool success; int i; // Clear work list. outtetlist->clear(); success = true; // Classify in- and out- tets in D. Mark and queue classified out-tets. for (i = 0; i < newtetlist->len() && success; i++) { // Get a new tet t. newtet = * (triface *)(* newtetlist)[i]; assert(!isdead(&newtet)); // Skip an infected tet (it's an out tet). if (!infected(newtet)) { // Look for aux subfaces attached at t. for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) { tspivot(newtet, auxsh); if (auxsh.sh != dummysh) { // Get the front f. decode((tetrahedron) auxsh.sh[0], front); // Let f face to the inside of C. adjustedgering(front, CW); pa = org(front); pb = dest(front); pc = apex(front); // Has this side a neighbor n? sym(newtet, neightet); if ((neightet.tet != dummytet) && !infected(neightet)) { // Classify t and n (one is "in" and another is "out"). ori = orient3d(pa, pb, pc, oppo(newtet)); if (ori == 0.0) { printf("Internal error at front %d.\n", i); assert(0); } if (ori < 0.0) { // t is in-tet. n is out-tet. outtet = neightet; intet = newtet; } else { // n is in-tet. t is out-tet. outtet = newtet; intet = neightet; } if (!infected(outtet)) { // Check the special case: if this tet is protected by four // subfaces, i.e., all 4 faces of this tet are fronts. // See an example in dbg/dump-SteinerRemoval-case3.lua neightet = outtet; for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { tspivot(neightet, auxsh); if (auxsh.sh == dummysh) break; } if (neightet.loc < 4) { // It is an outside tet. Add it into list. infect(outtet); outtetlist->append(&outtet); } } } else { intet = newtet; } // Make sure that the intet is not iversed. ori = orient3d(pa, pb, pc, oppo(intet)); assert(ori != 0); if (ori > 0) { // Found an inversed inside tet. Stop and return. if (b->verbose > 1) { printf(" Intet x%lx %d (%d, %d, %d, %d) is iversed.\n", (unsigned long) intet.tet, intet.loc, pointmark(pa), pointmark(pb), pointmark(pc), pointmark(oppo(intet))); } success = false; break; } } else { // This side is not protected. Check if it is a hull face. // Comment: This check is necessary. It is possible that all // protected subfaces have been moved in 'gluetetlist'. // If so, without this check, the newtets become orphans // and remain in the output. 2009-07-29. sym(newtet, neightet); if (neightet.tet == dummytet) { // Found an out tet. if (!infected(newtet)) { infect(newtet); outtetlist->append(&newtet); } break; } } } // for (newtet.loc) } // if (!infected) } if (!success) { // Found inversed tet. The carvecavity failed. for (i = 0; i < outtetlist->len(); i++) { outtet = * (triface *)(* outtetlist)[i]; uninfect(outtet); } outtetlist->clear(); return false; } // Find and mark all out-tets. for (i = 0; i < outtetlist->len(); i++) { outtet = * (triface *)(* outtetlist)[i]; for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) { sym(outtet, neightet); // Does the neighbor exist and unmarked? if ((neightet.tet != dummytet) && !infected(neightet)) { // Is it protected by an aux subface? tspivot(outtet, auxsh); if (auxsh.sh == dummysh) { // It's an out-tet. infect(neightet); outtetlist->append(&neightet); } } } } // Remove the out- (and hole) tets. for (i = 0; i < outtetlist->len(); i++) { // Get an out-tet t. outtet = * (triface *)(* outtetlist)[i]; assert(!isdead(&outtet)); // Detach t from the in-tets. for (outtet.loc = 0; outtet.loc < 4; outtet.loc++) { // Is there an aux subface s? tspivot(outtet, auxsh); if (auxsh.sh != dummysh) { // Get the neighbor n. sym(outtet, neightet); // assert(!infected(neightet)); // t must be in-tet. if (infected(neightet)) { printf("Error: A front face (%d, %d, %d) x%lx got deleted.\n", pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), (unsigned long) auxsh.sh); printf(" p:draw_tet(%d, %d, %d, %d) -- in\n", pointmark(org(neightet)), pointmark(dest(neightet)), pointmark(apex(neightet)), pointmark(oppo(neightet))); printf(" p:draw_tet(%d, %d, %d, %d) -- out\n", pointmark(org(outtet)), pointmark(dest(outtet)), pointmark(apex(outtet)), pointmark(oppo(outtet))); assert(0); } // Detach n -x-> t. dissolve(neightet); } } // Dealloc the tet. tetrahedrondealloc(outtet.tet); } // Connect the in-tets of C to fronts. Remove aux subfaces and fake tets. for (i = 0; i < newtetlist->len(); i++) { // Get a new tet t. newtet = * (triface *)(* newtetlist)[i]; // t may be an out-tet and has got deleted. if (isdead(&newtet)) continue; // t is an in-tet. Look for aux subfaces attached at t. for (newtet.loc = 0; newtet.loc < 4; newtet.loc++) { // Is there an aux subface s? tspivot(newtet, auxsh); if (auxsh.sh != dummysh) { // Get the front f. decode((tetrahedron) auxsh.sh[0], front); assert((front.tet != dummytet) && !infected(front)); // s has fulfilled its duty. Can be deleted. tsdissolve(newtet); // dissolve: t -x-> s. // Delete s. shellfacedealloc(subfaces, auxsh.sh); // Connect the newtet t and front f. // Is there a concrete subface c at f. tspivot(front, consh); if (consh.sh != dummysh) { sesymself(consh); // Bond: t <--> c. tsbond(newtet, consh); } // Update point-to-tet map. pointptr = org(front); setpoint2tet(pointptr, encode(newtet)); pointptr = dest(front); setpoint2tet(pointptr, encode(newtet)); pointptr = apex(front); setpoint2tet(pointptr, encode(newtet)); // Does f hold by a fake tet. if (oppo(front) == (point) NULL) { // f is fake. if (consh.sh != dummysh) { sesymself(consh); // Dissolve: c -x-> f. stdissolve(consh); } // Detach the fake tet from its old cavity tet. This is necessary // in case the mesh of other cavities are failed, and we have to // restore the original status. 2009-07-24. sym(front, oldtet); if (oldtet.tet != dummytet) { assert(infected(oldtet)); dissolve(oldtet); } // Dealloc f. tetrahedrondealloc(front.tet); // f becomes a hull. let 'dummytet' bond to it. dummytet[0] = encode(newtet); } else { // Bond t <--> f. bond(newtet, front); } // t may be non-locally Delaunay and flipable. if (flipque != (queue *) NULL) { enqueueflipface(newtet, flipque); } } } // Let the corners of t2 point to it for fast searching. pointptr = org(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = dest(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = apex(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = oppo(newtet); setpoint2tet(pointptr, encode(newtet)); } // The cavity has been re-tetrahedralized. // Maintain point-to-tet map. for (i = 0; i < gluetetlist->len(); i++) { // Get a new tet t. newtet = * (triface *)(* gluetetlist)[i]; if (isdead(&newtet)) { assert(0); } pointptr = org(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = dest(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = apex(newtet); setpoint2tet(pointptr, encode(newtet)); } return true; } /////////////////////////////////////////////////////////////////////////////// // // // replacepolygonsubs() Substitute the subfaces of a polygon. // // // // 'oldshlist' (T_old) contains the old subfaces of P. It will be replaced // // by 'newshlist' (T_new) of new subfaces. Each boundary edge of P is bonded // // to 'dummysh' in T_new. // // // // Notice that Not every boundary edge of T_new is able to bond to a subface,// // e.g., when it is a segment recovered by removing a Steiner point in it. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::replacepolygonsubs(list* oldshlist, list* newshlist) { face newsh, oldsh, spinsh; face casingout, casingin; face checkseg; point pa, pb; int i, j, k, l; for (i = 0; i < newshlist->len(); i++) { // Get a new subface s. newsh = * (face *)(* newshlist)[i]; // Check the three edges of s. for (k = 0; k < 3; k++) { spivot(newsh, casingout); // Is it a boundary edge? if (casingout.sh == dummysh) { // Find the old subface s_o having the same edge as s. pa = sorg(newsh); pb = sdest(newsh); for (j = 0; j < oldshlist->len(); j++) { oldsh = * (face *)(* oldshlist)[j]; for (l = 0; l < 3; l++) { if (((sorg(oldsh) == pa) && (sdest(oldsh) == pb)) || ((sorg(oldsh) == pb) && (sdest(oldsh) == pa))) break; senextself(oldsh); } if (l < 3) break; } // Is there a matched edge? if (j < oldshlist->len()) { // Get the neighbor subface s_out. spivot(oldsh, casingout); sspivot(oldsh, checkseg); if (checkseg.sh != dummysh) { if (casingout.sh != dummysh) { if (oldsh.sh == casingout.sh) { // A subface is self-bounded. Not possible. assert(0); // DEBUG } // A segment. Insert s into the face ring, ie, s_in->s->s_out. spinsh = casingout; do { casingin = spinsh; spivotself(spinsh); } while (sapex(spinsh) != sapex(oldsh)); assert(casingin.sh != oldsh.sh); // Bond s_in -> s -> s_out (and dissolve s_in -> s_old -> s_out). sbond1(casingin, newsh); sbond1(newsh, casingout); } else { sbond(newsh, casingout); } // Bond the segment. ssbond(newsh, checkseg); } else { // Bond s <-> s_out (and dissolve s_out -> s_old). sbond(newsh, casingout); } // Unbound oldsh to indicate it's neighbor has been replaced. // It will be used to indentfy the edge in the inverse. sdissolve(oldsh); ssdissolve(oldsh); } } // Go to the next edge of s. senextself(newsh); } } } /////////////////////////////////////////////////////////////////////////////// // // // orientnewsubs() Orient new subfaces facing to the inside of cavity. // // // // 'newshlist' contains new subfaces of the cavity C (created by re-triangu- // // lation the polygon P). They're not necessary facing to the inside of C. // // 'orientsh', faces to the inside of C, is used to adjust new subfaces. The // // normal of the new subfaces is returned in 'norm'. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::orientnewsubs(list* newshlist, face* orientsh, REAL* norm) { face *newsh; point pa, pb, pc; REAL ref[3], ori, len, l; int i; // Calculate the normal of 'orientsh'. pa = sorg(*orientsh); pb = sdest(*orientsh); pc = sapex(*orientsh); // facenormal(pa, pb, pc, norm, &len); facenormal2(pa, pb, pc, norm, 1); // for (i = 0; i < 3; i++) ref[i] = pa[i] + norm[i]; len = sqrt(norm[0]*norm[0]+norm[1]*norm[1]+norm[2]*norm[2]); for (i = 0; i < 3; i++) norm[i] /= len; // Get the longest edge length of [a, b, c] len = distance(pa, pb); l = distance(pb, pc); if (len < l) len = l; l = distance(pc, pa); if (len < l) len = l; // Calculate a local above point. for (i = 0; i < 3; i++) ref[i] = pa[i] + len * norm[i]; // Orient new subfaces. Let the normal above each one. for (i = 0; i < newshlist->len(); i++) { newsh = (face *)(* newshlist)[i]; pa = sorg(*newsh); pb = sdest(*newsh); pc = sapex(*newsh); ori = orient3d(pa, pb, pc, ref); assert(ori != 0.0); if (ori > 0.0) { sesymself(*newsh); } } } /////////////////////////////////////////////////////////////////////////////// // // // registerelemflip() Register an elementary flip T23, T32, or T22. // // // // If return TRUE, the flip is registered, otherwise, return FALSE, which // // means a conflict, this flip already exists. // // // // Depending on the flip type, not all input points are used, those unused // // points are set to be dummypoint for easily processing. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::registerelemflip(enum fliptype ft, point pa1, point pb1, point pc1, point pa2, point pb2, point pc2) { elemflip *ef; bool rflag; int i; rflag = false; // The flip has not registed yet. pinfect(pa1); pinfect(pb1); pinfect(pc1); pinfect(pa2); pinfect(pb2); pinfect(pc2); // Search the list for a registered flip. for (i = 0; i < (int) elemfliplist->objects; i++) { ef = (elemflip *) fastlookup(elemfliplist, i); if (ef->ft == ft) { rflag = (pinfected(ef->pset1[0]) && pinfected(ef->pset1[1]) && pinfected(ef->pset1[2])); if (rflag) { rflag = (pinfected(ef->pset2[0]) && pinfected(ef->pset2[1]) && pinfected(ef->pset2[2])); if (rflag) { break; // This flip has been registed before. } } } } puninfect(pa1); puninfect(pb1); puninfect(pc1); puninfect(pa2); puninfect(pb2); puninfect(pc2); if (rflag) { if (b->verbose > 1) { printf(" Flip: %s", ft == T23 ? "T23" : (ft == T32 ? "T32" : "T22")); printf(" (%d, %d, %d) - (%d, %d, %d) is registered.\n", pointmark(pa1), pointmark(pb1), pointmark(pc1), pointmark(pa2), pointmark(pb2), pointmark(pc2)); } return false; } // Register this flip. elemfliplist->newindex((void **) &ef); ef->ft = ft; ef->pset1[0] = pa1; ef->pset1[1] = pb1; ef->pset1[2] = pc1; ef->pset2[0] = pa2; ef->pset2[1] = pb2; ef->pset2[2] = pc2; return true; } /////////////////////////////////////////////////////////////////////////////// // // // check4fixededge() Check if the given edge [a, b] is a fixed edge. // // // // A fixed edge is saved in the "fixededgelist". Return TRUE if [a, b] has // // already existed in the list, otherwise, return FALSE. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::check4fixededge(point pa, point pb) { point *ppt; int i; pinfect(pa); pinfect(pb); for (i = 0; i < (int) fixededgelist->objects; i++) { ppt = (point *) fastlookup(fixededgelist, i); if (pinfected(ppt[0]) && pinfected(ppt[1])) { if (b->verbose > 1) { printf(" Edge (%d, %d) is fixed.\n", pointmark(pa), pointmark(pb)); } break; // This edge already exists. } } puninfect(pa); puninfect(pb); return i < (int) fixededgelist->objects; } /////////////////////////////////////////////////////////////////////////////// // // // removeedgebyflips() Remove an edge by flips. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removeedgebyflips(triface* remedge, int *flipcount) { triface abcd; //, badc; // Tet configuration at edge ab. // triface baccasing, abdcasing; triface abtetlist[21]; // Old configuration at ab, save maximum 20 tets. triface bftetlist[21]; // Old configuration at bf, save maximum 20 tets. triface newtetlist[90]; // New configuration after removing ab. face checksh; point pa, pb; bool remflag, subflag; int n, n1, m, i; //, j; triface newtet; // For update point-to-tet map. point *ppt; int j; pa = org(*remedge); pb = dest(*remedge); if (b->verbose > 1) { printf(" Remove edge (%d, %d).\n", pointmark(pa), pointmark(pb)); } // Get the tets configuration at ab. Collect maximum 10 tets. subflag = false; abcd = *remedge; adjustedgering(abcd, CW); n = 0; abtetlist[n] = abcd; do { // Is the list full? if (n == 20) break; // Stop if a subface appears. tspivot(abtetlist[n], checksh); if (checksh.sh != dummysh) { // ab is either a segment or a facet edge. The latter case is not // handled yet! An edge flip is needed. if (b->verbose > 1) { printf(" Can't remove a fixed face (%d, %d, %d).\n", pointmark(pa), pointmark(pb), pointmark(apex(abtetlist[n]))); } subflag = true; break; // return false; } // Get the next tet at ab. if (!fnext(abtetlist[n], abtetlist[n + 1])) { // This edge is on the hull (2-to-2 flip case). subflag = true; break; // assert(0); // Not handled yet. } n++; } while (apex(abtetlist[n]) != apex(abcd)); if (subflag) { // The face link contains subfaces, stop. return false; } // Do not flip this edge if it has been fixed (for recovering a face). if (check4fixededge(pa, pb)) { return false; } // 2 < n < 20. if (n == 3) { // There are three tets at ab. Try to do a flip32 at ab. remflag = removeedgebyflip32(NULL, abtetlist, newtetlist, NULL); } else if ((n > 3) && (n <= b->maxflipedgelinksize)) { // Four tets case. Try to do edge transformation. remflag = removeedgebytranNM(NULL,n,abtetlist,newtetlist,NULL,NULL,NULL); } else { if (b->verbose > 1) { printf(" !! Unhandled case: n = %d.\n", n); } remflag = false; } if (remflag) { // Delete the old tets. for (i = 0; i < n; i++) { tetrahedrondealloc(abtetlist[i].tet); } m = (n - 2) * 2; // The numebr of new tets. if (b->verbose > 1) { printf(" Done flip %d-to-%d.\n", n, m); } // Update the point-to-tet map for (i = 0; i < m; i++) { newtet = newtetlist[i]; ppt = (point *) &(newtet.tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(newtet)); } } *flipcount = *flipcount + 1; return true; } if (n <= b->maxflipedgelinksize) { // Try to do a combination of flips. n1 = 0; remflag = removeedgebycombNM(NULL, n, abtetlist, &n1, bftetlist, newtetlist, NULL); if (remflag) { // Delete the old tets. for (i = 0; i < n; i++) { tetrahedrondealloc(abtetlist[i].tet); } for (i = 0; i < n1; i++) { if (!isdead(&(bftetlist[i]))) { tetrahedrondealloc(bftetlist[i].tet); } } m = ((n1 - 2) * 2 - 1) + (n - 3) * 2; // The number of new tets. if (b->verbose > 1) { printf(" Done flip %d-to-%d (n-1=%d, n1=%d). ", n+n1-2, m, n-1,n1); printf("\n"); } // Update the point-to-tet map for (i = 0; i < m; i++) { newtet = newtetlist[i]; ppt = (point *) &(newtet.tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(newtet)); } } *flipcount = *flipcount + 1; return true; } } return false; } /////////////////////////////////////////////////////////////////////////////// // // // removefacebyflips() Remove a face by a sequence of flips. // // // // The face should not be a subface. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removefacebyflips(triface* remface, int *flipcount) { triface neightet, checkface1, checkface2; face checksh1, checksh2; point pa, pb, pc, pd, pe; enum interresult dir; REAL ori; int types[2], poss[4]; int i; adjustedgering(*remface, CCW); sym(*remface, neightet); if (neightet.tet == dummytet) { // A boundary face. It is not flipable. return false; } pd = oppo(*remface); pe = oppo(neightet); if (b->verbose > 1) { printf(" Remove face (%d, %d, %d) %d, %d\n", pointmark(org(*remface)), pointmark(dest(*remface)), pointmark(apex(*remface)), pointmark(pd), pointmark(pe)); } // Do not remove this face if it is a fixed face. tspivot(*remface, checksh1); if (checksh1.sh != dummysh) { if (b->verbose > 1) { printf(" Can't remove a fixed face (%d, %d, %d)\n", pointmark(org(*remface)), pointmark(dest(*remface)), pointmark(apex(*remface))); } return false; } // Check if edge [d, e] intersects the flip face [a, b, c]. for (i = 0; i < 3; i++) { pa = org(*remface); pb = dest(*remface); pc = apex(*remface); ori = orient3d(pa, pb, pd, pe); if (ori <= 0) break; // Coplanar or Above. enextself(*remface); } if (i == 3) { // A 2-to-3 flip is found. // Regist the flipping face. if (!registerelemflip(T23, pa, pb, pc, pd, pe, dummypoint)) { // Detected a potential flip loop. return false; } // Do a 2-to-3 flip. flip23(remface, NULL); *flipcount = *flipcount + 1; return true; } if (ori == 0) { // Check if [a, b] is a hull edge. If so a flip22() could apply. fnext(*remface, checkface1); tspivot(checkface1, checksh1); symedge(*remface, neightet); fnext(neightet, checkface2); tspivot(checkface2, checksh2); // First check if it is a protected face. if ((checksh1.sh == dummysh) && (checksh2.sh == dummysh)) { // Check if it is a hull face. symself(checkface1); symself(checkface2); if ((checkface1.tet == dummytet) && (checkface2.tet == dummytet)) { // Check if the edge [a, b] intersects [d, e] in its interior. if (tri_edge_test(pa, pb, pc, pd, pe, NULL, 1, types, poss)) { dir = (enum interresult) types[0]; if (dir == INTEREDGE) { // Edge [d, e] intersects [a, b, c]. A flip 2-to-2 is found. // Check if the edge [a, b] is a fixed one (for recovering a face). if (check4fixededge(pa, pb)) { // [a, b] is a fixed edge. Stop the flip. return false; } // Regist this flip. if (!registerelemflip(T22, pa, pb, dummypoint, pd, pe, dummypoint)) { // Detected a potential flip loop. return false; } // We can flip this edge [a, b]. flip22(remface, NULL); *flipcount = *flipcount + 1; return true; } else { // Either a or b is collinear with edge [d, e]. NOT flipable. assert(dir == INTERVERT); return false; } } else { // [a,b] does not intersect with [d, e]. Don't do a 2-to-2 flip. // See an example in dbg/dump-nflip22-case.lua return false; } } } else { if (b->verbose > 1) { printf(" Can't remove a fixed face (%d, %d, %d).\n", pointmark(pa), pointmark(pb), pointmark(apex(neightet))); } return false; } } // The edge [d, e] does not intersect [a, b, c]. Try to flip edge [a, b]. // Comment: We've found that the edge [a, b] is locally non-convex. It // must be an interior edge. return removeedgebyflips(remface, flipcount); } /////////////////////////////////////////////////////////////////////////////// // // // recoveredgebyflips() Recover edge [a, b] by a sequence of flips. // // // // The edge to be recovered is from a = org(*searchtet) to b. Return TRUE if // // the edge [a, b] is recovered, and retruned in 'searchtet', otherwise, // // return FALSE. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::recoveredgebyflips(triface *searchtet,point pb,int *flipcount) { triface remface; point pa; enum interresult dir; bool success; pa = org(*searchtet); if (b->verbose > 1) { printf(" Recover edge (%d, %d)\n", pointmark(pa), pointmark(pb)); } assert(elemfliplist->objects == 0l); while (1) { // Go to the intersected face, try to flip it. enextfnext(*searchtet, remface); // Try to remove this crossing face. success = removefacebyflips(&remface, flipcount); if (!success) break; point2tetorg(pa, *searchtet); assert(org(*searchtet) == pa); dir = finddirection2(searchtet, pb); if (dir == INTERVERT) { break; // The edge has found. } } // while (1) // Clear the recorded flip list. elemfliplist->restart(); return success; } /////////////////////////////////////////////////////////////////////////////// // // // recoverfacebyflips() Recover a missing face by a sequence of flips. // // // // Assume that at least one of the edges of the face exists in the current // // mesh. The face is recovered by continusly removing all crossing edges of // // this face. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::recoverfacebyflips(triface* front, int *flipcount) { triface searchtet, spintet, bdrytet; triface remedge, remface; point pa, pb, pc, pd, pe, *ppt; enum interresult dir; bool success; int hitbdry; int i; if (b->verbose > 1) { printf(" Recover face (%d, %d, %d)\n", pointmark(org(*front)), pointmark(dest(*front)), pointmark(apex(*front))); } assert(fixededgelist->objects == 0l); // First recover three edges of this face. for (i = 0; i < 3; i++) { pa = org(*front); pb = dest(*front); pc = apex(*front); // The apex. point2tetorg(pa, searchtet); assert(org(searchtet) == pa); dir = finddirection2(&searchtet, pb); if (dir == BELOWHULL2) { // Detect an outside front. This happens when a new subface created by // re-triangulating is actually outside the cavity. The gluefront() // is not called in this case. There must be an existing face which // lies outside the cavity that matches this subface. // An example is dump-SteinerRemoval-case2.lua. 2009-07-06. // fixededgelist->restart(); // return false; assert(0); } if (dir != INTERVERT) { if (!recoveredgebyflips(&searchtet, pb, flipcount)) { // Failed to recover edge [a, b], so does the face. fixededgelist->restart(); return false; } } // DIR == INTERVERT if (dest(searchtet) != pb) { // There eixsts a collonear edge but not the desired one. // Failed to recover edge [a, b], so does the face. fixededgelist->restart(); return false; } // Save this edge to avoid flipping it away. fixededgelist->newindex((void **) &ppt); ppt[0] = pa; ppt[1] = pb; // Go to the next edge. enextself(*front); } assert(elemfliplist->objects == 0l); while (1) { success = false; // Adjust edge [a->b] to be in the CCW edge ring. adjustedgering(searchtet, CCW); if (org(searchtet) != pa) { fnextself(searchtet); esymself(searchtet); } assert(org(searchtet) == pa); assert(dest(searchtet) == pb); spintet = searchtet; hitbdry = 0; do { if (apex(spintet) == pc) { // Found abc. Insert an auxilary subface s at idfront. insertauxsubface(front, &spintet); success = true; break; // return true; } if (!fnextself(spintet)) { bdrytet = spintet; // Save the boundary face. hitbdry ++; if (hitbdry < 2) { esym(searchtet, spintet); if (!fnextself(spintet)) { hitbdry++; } } } if (apex(spintet) == apex(searchtet)) break; } while (hitbdry < 2); if (success) break; if (hitbdry > 0) { // Adjust searchtet to be the boundary face at edge [pa->pb]. searchtet = bdrytet; adjustedgering(searchtet, CCW); pa = org(searchtet); pb = dest(searchtet); } // Comments: // Remember that 'front' is the face [a, b, c]. 'spintet' is a tet // [a, b, d, e] at edge [a->b]. // We first check if the edge [d, e] intersects face [a, b, c], if it // does, we try to flip the edge [d, e] away. // We then check if the edge [b, c] intersects face [a, d, e], if it // does, we try to flip the face [a, d, e] away. // We then check if the edge [a, c] intersects face [b, d, e], if it // does, we try to flip the face [b, d, e] away. // Search a crossing edge/face and try to flip it away. remedge.tet = remface.tet = NULL; spintet = searchtet; hitbdry = 0; do { pd = apex(spintet); pe = oppo(spintet); // Check if edge [d, e] intersects [a, b, c]. if (tri_edge_test(pa, pb, pc, pd, pe, NULL, 0, NULL, NULL)) { remedge = spintet; enextfnextself(remedge); enextself(remedge); // Edge [pd->pe]. break; } // Check if [b, c] intersects [a, d, e]. if (!iscollinear(pa, pd, pe, b->epsilon)) { if (tri_edge_test(pa, pd, pe, pb, pc, NULL, 0, NULL, NULL)) { remface = spintet; enext2fnextself(remface); // Face [a, d, e]. break; } } if (!iscollinear(pb, pd, pe, b->epsilon)) { // Check if [a, c] intersects [b, d, e]. if (tri_edge_test(pb, pd, pe, pa, pc, NULL, 0, NULL, NULL)) { remface = spintet; enextfnextself(remface); // Face [b, d, e]. break; } } tfnextself(spintet); if (spintet.tet == dummytet) { break; // Meet boundary. } if (apex(spintet) == apex(searchtet)) break; } while (hitbdry < 2); if (remedge.tet != NULL) { // Try to remove this crossing edge. success = removeedgebyflips(&remedge, flipcount); } else if (remface.tet != NULL) { /*// Do not flip it if it is a subface. tspivot(remface, checksh); if (checksh.sh != dummysh) { return false; }*/ success = removefacebyflips(&remface, flipcount); } else { // Haven't found a crossing edge or face. success = false; } if (!success) break; point2tetorg(pa, searchtet); assert(org(searchtet) == pa); dir = finddirection2(&searchtet, pb); assert(dest(searchtet) == pb); } // while (1) // Clear the recored flips. elemfliplist->restart(); // Clear the fixed edges. fixededgelist->restart(); return success; } /////////////////////////////////////////////////////////////////////////////// // // // constrainedcavity() Tetrahedralize a cavity by constrained tetrahedra. // // // // The cavity C is bounded by faces F in 'floorlist' and 'ceillist'. 'ptlist'// // V is the set of vertices of C. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::constrainedcavity(triface* oldtet, list* floorlist, list* ceillist, list* ptlist, list* frontlist, list* misfrontlist, list* newtetlist, list* gluetetlist, list* glueshlist, queue* flipque) { triface misfront, newtet; point pointptr; // Used with gluetetlist. bool success; int misfacecount; int flipcount, totalflipcount; int i; if (b->verbose > 1) { printf(" Constrained cavity (%d floors, %d ceilings, %d vertices).\n", floorlist->len(), ceillist->len(), ptlist->len()); } // Initialize the cavity C. initializecavity(floorlist, ceillist, frontlist, ptlist, glueshlist); // Form the D of the vertices of C. success = delaunizecavvertices(oldtet, ptlist, NULL, newtetlist, flipque); if (success) { // Identify faces of C in D. if (!identifyfronts(frontlist, misfrontlist, gluetetlist, glueshlist)) { // Some faces are missing. totalflipcount = 0; // Try to recover missing faces by flips. do { misfacecount = misfrontlist->len(); flipcount = 0; for (i = 0; i < misfrontlist->len(); i++) { // Get a missing front f. misfront = * (triface *)(* misfrontlist)[i]; // Let f face toward the inside of C. // adjustedgering(misfront, CW); // if (recoverfront(&misfront, newtetlist, flipque)) { if (recoverfacebyflips(&misfront, &flipcount)) { // f has been recovered. frontlist->append(&misfront); misfrontlist->del(i, 0); i--; } } totalflipcount += flipcount; // Have all faces been recovered? if (misfrontlist->len() == 0) break; // Continue the loop if some missing faces have been recovered. } while (misfacecount > misfrontlist->len()); // Retrieve new tets and purge dead tets in D. retrievenewtets(newtetlist); } success = (misfrontlist->len() == 0); } // if (success) if (success) { // All fronts have identified in D. Get the shape of C by removing out // tets of C. 'misfrontlist' is reused for removing out tets. // Don't do flip since the new tets may get deleted later. if (carvecavity(newtetlist, misfrontlist, gluetetlist, NULL)) { return true; } } // { // Fail to tetrahedralize C. // Remove aux subfaces. detachauxsubfaces(newtetlist); // Remove new tets. for (i = 0; i < newtetlist->len(); i++) { newtet = * (triface *)(* newtetlist)[i]; assert(!isdead(&newtet)); tetrahedrondealloc(newtet.tet); } newtetlist->clear(); // Restore faces of C in frontlist. for (i = 0; i < misfrontlist->len(); i++) { misfront = * (triface *)(* misfrontlist)[i]; frontlist->append(&misfront); } // Some fronts have been removed from the front list (in gluefronts()). // Maintain point-to-tet map. for (i = 0; i < gluetetlist->len(); i++) { // Get a tet t which lies outside the current cavity. newtet = * (triface *)(* gluetetlist)[i]; if (isdead(&newtet)) { assert(0); } pointptr = org(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = dest(newtet); setpoint2tet(pointptr, encode(newtet)); pointptr = apex(newtet); setpoint2tet(pointptr, encode(newtet)); } return false; // } } /////////////////////////////////////////////////////////////////////////////// // // // findrelocatepoint() Find new location for relocating a point. // // // // 'frontlist' contains the boundary faces of the cavity C. Some fronts are // // visible by 'stpt' p, some are coplanar with p. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::findrelocatepoint2(point steinpt, point relocatept, REAL* normal, list* frontlist, list* oldtetlist) { triface oldtet, front; point pa, pb, pc; REAL farpt[3], fcent[3], candpt[3], searchpt[3]; REAL dist, factor; REAL ori, stepx, minvol, minvol1; bool stopflag; // int iter; int i, j; if (b->verbose > 1) { printf(" Find new location for point %d.\n", pointmark(steinpt)); } // Calculate a far enough point on the normal direction. for (i = 0; i < 3; i++) { farpt[i] = steinpt[i] + longest * normal[i]; } // Find the face in oldtet intersecting with the line steinpt->farpt. for (i = 0; i < oldtetlist->len(); i++) { oldtet = * (triface *)(* oldtetlist)[i]; pa = org(oldtet); pb = dest(oldtet); pc = apex(oldtet); if (tri_edge_test(pa, pb, pc, steinpt, farpt, farpt, 0, NULL, NULL)) { // projpt2face(steinpt, pa, pb, pc, fcent); // Find the intersected face. Calculate the intersection. planelineint(pa, pb, pc, steinpt, farpt, fcent, &factor); if (factor != 0) { // assert(factor != 0); if (b->verbose > 1) { printf("p:show_vector(%g, %g, %g, %g, %g, %g) -- L\n", steinpt[0], steinpt[1], steinpt[2], fcent[0], fcent[1], fcent[2]); } break; } } } // There must be an interseced face. if (i == oldtetlist->len()) { return false; // assert(0); } // Start search a relocating point which maximize the min. vol. dist = distance(steinpt, fcent); stepx = dist / 100.0; // Divide the segment into 100 pieces. minvol = 0; stopflag = false; for (i = 1; i < 100 && !stopflag; i++) { // Calculate a candidate point. for (j = 0; j < 3; j++) { candpt[j] = steinpt[j] + (stepx * (double) i) * (fcent[j] - steinpt[j]); } minvol1 = 0; for (j = 0; j < frontlist->len(); j++) { front = * (triface *)(* frontlist)[j]; // Let f face inside C. (f is a face of tet adjacent to C). adjustedgering(front, CW); pa = org(front); pb = dest(front); pc = apex(front); ori = orient3d(pa, pb, pc, candpt); if (ori >= 0) { // An invisible front. (1) fails. stopflag = true; break; } if (j == 0) { minvol1 = -ori; } else { if (minvol1 > (-ori)) { minvol1 = -ori; } } } // j if (!stopflag) { if (minvol < minvol1) { // The min. vol. is improved by this candidate. Choose it. for (j = 0; j < 3; j++) searchpt[j] = candpt[j]; minvol = minvol1; } else { // The min. vol. begins to decrease. Stop the search. stopflag = true; } } } // i if (minvol > 0) { // We've found a valid relocation. Choose it. if (b->verbose > 1) { printf("p:show_vector(%g, %g, %g, %g, %g, %g) -- Relo\n", steinpt[0], steinpt[1], steinpt[2], searchpt[0], searchpt[1], searchpt[2]); } for (i = 0; i < 3; i++) relocatept[i] = searchpt[i]; return true; } else { return false; } } /////////////////////////////////////////////////////////////////////////////// // // // relocatepoint() Relocate a point into the cavity. // // // // 'frontlist' contains the boundary faces of the cavity C. All fronts must // // be visible by 'steinpt'. Some fronts may hold by 'fake' tets (they are // // hull faces). Fake tets will be removed when they're finished. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::relocatepoint(point steinpt, triface* oldtet, list* frontlist, list* newtetlist, queue* flipque) { triface front, newtet, newface, neightet; face checksh; point pa, pb; REAL attrib, volume; bool bdflag; int i, j, k, l; if (b->verbose > 1) { printf(" Insert Steiner point (%.12g, %.12g, %.12g) %d.\n", steinpt[0], steinpt[1], steinpt[2], pointmark(steinpt)); } // Clear the list first. newtetlist->clear(); // Create the tets formed by fronts and 'steinpt'. for (i = 0; i < frontlist->len(); i++) { // Get a front f. front = * (triface *)(* frontlist)[i]; // Let f face inside C. (f is a face of tet adjacent to C). adjustedgering(front, CW); if (b->verbose > 2) { printf(" Get front (%d, %d, %d).\n", pointmark(org(front)), pointmark(dest(front)), pointmark(apex(front))); } maketetrahedron(&newtet); newtetlist->append(&newtet); setorg(newtet, org(front)); setdest(newtet, dest(front)); setapex(newtet, apex(front)); setoppo(newtet, steinpt); if (oldtet != (triface *) NULL) { for (j = 0; j < in->numberoftetrahedronattributes; j++) { attrib = elemattribute(oldtet->tet, j); setelemattribute(newtet.tet, j, attrib); } if (b->varvolume) { volume = volumebound(oldtet->tet); setvolumebound(newtet.tet, volume); } } // Update the point-to-tet map. pa = org(front); setpoint2tet(pa, encode(newtet)); pa = dest(front); setpoint2tet(pa, encode(newtet)); pa = apex(front); setpoint2tet(pa, encode(newtet)); setpoint2tet(steinpt, encode(newtet)); // 'front' may be a 'fake' tet. tspivot(front, checksh); if (oppo(front) == (point) NULL) { if (checksh.sh != dummysh) { stdissolve(checksh); } // Detach the fake tet from its old cavity tet. This is necessary // in case the mesh of other cavities are failed, and we have to // restore the original status. 2009-07-28. sym(front, neightet); if (neightet.tet != dummytet) { assert(infected(neightet)); dissolve(neightet); } // Dealloc the 'fake' tet. tetrahedrondealloc(front.tet); // This side (newtet) is a boundary face, let 'dummytet' bond to it. // Otherwise, 'dummytet' may point to a dead tetrahedron after the // old cavity tets are removed. dummytet[0] = encode(newtet); } else { // Bond two tetrahedra, also dissolve the old bond at 'front'. bond(newtet, front); } if (checksh.sh != dummysh) { sesymself(checksh); tsbond(newtet, checksh); } if (flipque != (queue *) NULL) { // f may be non-locally Delaunay and flipable. enqueueflipface(newtet, flipque); } // The three neighbors are open. Will be finished later. } // Connect new tets in C. All connecting faces must contain 'steinpt'. // The following code should be re-written. 2009-07-30. for (i = 0; i < newtetlist->len(); i++) { newtet = * (triface *)(* newtetlist)[i]; newtet.ver = 0; for (j = 0; j < 3; j++) { fnext(newtet, newface); sym(newface, neightet); if (neightet.tet == dummytet) { // Find a neightet to connect it. bdflag = false; pa = org(newface); pb = dest(newface); assert(apex(newface) == steinpt); for (k = i + 1; k < newtetlist->len() && !bdflag; k++) { neightet = * (triface *)(* newtetlist)[k]; neightet.ver = 0; for (l = 0; l < 3; l++) { if ((org(neightet) == pa && dest(neightet) == pb) || (org(neightet) == pb && dest(neightet) == pa)) { // Find the neighbor. fnextself(neightet); assert(apex(neightet) == steinpt); // Now neightet is a face same as newface, bond them. bond(newface, neightet); bdflag = true; break; } enextself(neightet); } } if (!bdflag) { assert(0); // break; // The relocation failed. } } enextself(newtet); } if (j < 3) break; } if (i < newtetlist->len()) { // Relocation failed. Delete new tets. for (i = 0; i < newtetlist->len(); i++) { newtet = * (triface *)(* newtetlist)[i]; tetrahedrondealloc(newtet.tet); } return false; } if (flipque != (queue *) NULL) { // Recover locally Delaunay faces. lawson3d(flipque); } return true; } /////////////////////////////////////////////////////////////////////////////// // // // findcollapseedge() Find collapseable edge to suppress an endpoint. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::findcollapseedge(point suppt, point *conpt, list* oldtetlist, list* ptlist) { triface front; point pt, pa, pb, pc; REAL *lenarray, ltmp, ori; bool visflag; int *idxarray, itmp; int n, i, j; if (b->verbose > 2) { printf(" Search an edge (in %d edges) for collapse %d.\n", ptlist->len(), pointmark(suppt)); } // Candidate edges are p to the points of B(p) (in 'ptlist'). n = ptlist->len(); lenarray = new REAL[n]; idxarray = new int[n]; // Sort the points of B(p) by distance to p. for (i = 0; i < n; i++) { pt = * (point *)(* ptlist)[i]; lenarray[i] = distance(suppt, pt); idxarray[i] = i; } // Bubble sort. for (i = 0; i < n - 1; i++) { for (j = 0; j < n - 1 - i; j++) { if (lenarray[j + 1] < lenarray[j]) { // compare the two neighbors ltmp = lenarray[j]; // swap a[j] and a[j + 1] lenarray[j] = lenarray[j + 1]; lenarray[j + 1] = ltmp; itmp = idxarray[j]; // swap a[j] and a[j + 1] idxarray[j] = idxarray[j + 1]; idxarray[j + 1] = itmp; } } } // For each point q of B(p), test if the edge (p, q) can be collapseed. for (i = 0; i < n; i++) { pt = * (point *)(* ptlist)[idxarray[i]]; // Is q visible by faces of B(p) not with q as a vertex. lenarray[i] = 0.0; // zero volume. visflag = true; for (j = 0; j < oldtetlist->len() && visflag; j++) { front = * (triface *)(* oldtetlist)[j]; // Let f face to inside of B(p). adjustedgering(front, CCW); pa = org(front); pb = dest(front); pc = apex(front); // Is f contains q? if ((pa != pt) && (pb != pt) && (pc != pt)) { ori = orient3d(pa, pb, pc, pt); if (ori != 0.0) { if (iscoplanar(pa, pb, pc, pt, ori, b->epsilon * 1e+2)) ori = 0.0; } visflag = ori < 0.0; if (visflag) { // Visible, set the smallest volume. if (j == 0) { lenarray[i] = fabs(ori); } else { lenarray[i] = fabs(ori) < lenarray[i] ? fabs(ori) : lenarray[i]; } } else { // Invisible. Do not collapse (p, q). lenarray[i] = 0.0; } } } if ((b->verbose > 2) && visflag) { printf(" Got candidate %d vol(%g).\n", pointmark(pt), lenarray[i]); } } // Select the largest non-zero volume (result in ltmp). ltmp = lenarray[0]; itmp = idxarray[0]; for (i = 1; i < n; i++) { if (lenarray[i] != 0.0) { if (lenarray[i] > ltmp) { ltmp = lenarray[i]; itmp = idxarray[i]; // The index to find the point. } } } delete [] lenarray; delete [] idxarray; if (ltmp == 0.0) { // No edge can be collapseed. *conpt = (point) NULL; return false; } else { pt = * (point *)(* ptlist)[itmp]; *conpt = pt; return true; } } /////////////////////////////////////////////////////////////////////////////// // // // collapseedge() Remove a point by edge collapse. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::collapseedge(point suppt, point conpt, list* oldtetlist, list* deadtetlist) { triface oldtet, deadtet; triface adjtet1, adjtet2; face adjsh; point pa, pb, pc; int i, j; if (b->verbose > 2) { printf(" Collapse edge (%d,%d).\n", pointmark(suppt), pointmark(conpt)); } // Loop in B(p), replace p with np, queue dead tets, uninfect old tets. for (i = 0; i < oldtetlist->len(); i++) { oldtet = * (triface *)(* oldtetlist)[i]; // assert(infected(oldtet)); uninfect(oldtet); pa = org(oldtet); pb = dest(oldtet); pc = apex(oldtet); assert(oppo(oldtet) == suppt); setoppo(oldtet, conpt); if ((pa == conpt) || (pb == conpt) || (pc == conpt)) { deadtetlist->append(&oldtet); // a collpased tet. } else { // A non-collapse tet. Update point-to-tet map. setpoint2tet(pa, encode(oldtet)); setpoint2tet(pb, encode(oldtet)); setpoint2tet(pc, encode(oldtet)); setpoint2tet(conpt, encode(oldtet)); } } // Loop in deadtetlist, glue adjacent tets of dead tets. for (i = 0; i < deadtetlist->len(); i++) { deadtet = * (triface *)(* deadtetlist)[i]; // Get the adjacent tet n1 (outside B(p)). sym(deadtet, adjtet1); tspivot(deadtet, adjsh); // Find the edge in deadtet opposite to conpt. adjustedgering(deadtet, CCW); for (j = 0; j < 3; j++) { if (apex(deadtet) == conpt) break; enextself(deadtet); } assert(j < 3); // Get another adjacent tet n2. fnext(deadtet, adjtet2); symself(adjtet2); assert(adjtet2.tet != dummytet); // n2 is inside B(p). if (adjtet1.tet != dummytet) { bond(adjtet1, adjtet2); // Bond n1 <--> n2. } else { dissolve(adjtet2); // Dissolve at n2. dummytet[0] = encode(adjtet2); // Let dummytet holds n2. } if (adjsh.sh != dummysh) { tsbond(adjtet2, adjsh); // Bond s <--> n2. } // Collapse deadtet. tetrahedrondealloc(deadtet.tet); } deadtetlist->clear(); } /////////////////////////////////////////////////////////////////////////////// // // // deallocfaketets() Deleted fake tets at fronts. // // // // This routine is only called when the findrelocatepoint() routine fails. // // In other cases, the fake tets are removed automatically in carvecavity() // // or relocatepoint(). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::deallocfaketets(list* frontlist) { triface front, neightet; face checksh; bool infectflag; int i; for (i = 0; i < frontlist->len(); i++) { // Get a front f. front = * (triface *)(* frontlist)[i]; // Let f face inside C. (f is a face of tet adjacent to C). adjustedgering(front, CW); sym(front, neightet); tspivot(front, checksh); if (oppo(front) == (point) NULL) { if (b->verbose > 2) { printf(" Get fake tet (%d, %d, %d).\n", pointmark(org(front)), pointmark(dest(front)), pointmark(apex(front))); } if (neightet.tet != dummytet) { // The neightet may be infected. After dissolve it, the infect flag // will be lost. Save the flag and restore it later. infectflag = infected(neightet); dissolve(neightet); if (infectflag) { infect(neightet); } } if (checksh.sh != dummysh) { infectflag = sinfected(checksh); stdissolve(checksh); if (infectflag) { sinfect(checksh); } } // Dealloc the 'fake' tet. tetrahedrondealloc(front.tet); // If 'neightet' is a hull face, let 'dummytet' bond to it. It is // a 'dummytet' when this front was created from a new subface. // In such case, it should not be bounded. if (neightet.tet != dummytet) { dummytet[0] = encode(neightet); } } } } /////////////////////////////////////////////////////////////////////////////// // // // restorepolyhedron() Restore the tetrahedralization in a polyhedron. // // // // This routine is only called when the operation of suppressing a point is // // aborted (eg., findrelocatepoint() routine fails). The polyhedron has been // // remeshed by new tets. This routine restore the old tets in it. // // // // 'oldtetlist' contains the list of old tets. Each old tet t_o assumes that // // it still connects to a tet t_b of the mesh, however, t_b does not connect // // to t_o, this routine resets the connection such that t_b <--> t_o. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::restorepolyhedron(list* oldtetlist) { triface oldtet, neightet, neineitet; face checksh; point *ppt; int i, j; for (i = 0; i < oldtetlist->len(); i++) { // Get an old tet t_o. oldtet = * (triface *)(* oldtetlist)[i]; // Check the four sides of t_o. for (oldtet.loc = 0; oldtet.loc < 4; oldtet.loc++) { sym(oldtet, neightet); tspivot(oldtet, checksh); if (neightet.tet != dummytet) { assert(!isdead(&neightet)); // SELF_CHECK 2009-07-24 sym(neightet, neineitet); if (neineitet.tet != oldtet.tet) { // This face of t_o is a boundary of P. bond(neightet, oldtet); if (checksh.sh != dummysh) { tsbond(oldtet, checksh); } } } else { // t_o has a hull face. It should be the boundary of P. tsbond(oldtet, checksh); // Let dummytet[0] points to it. dummytet[0] = encode(oldtet); } } // Update the point-to-tet map. ppt = (point *) &(oldtet.tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(oldtet)); } } } /////////////////////////////////////////////////////////////////////////////// // // // suppressfacetpoint() Suppress a point inside a facet. // // // // The point p inside a facet F will be suppressed from F by either being // // deleted from the mesh or being relocated into the volume. // // // // 'supsh' is a subface f of F, and p = sapex(f); the other parameters are // // working lists which are empty at the beginning and the end. // // // // 'optflag' is used for mesh optimization. If it is set, after removing p, // // test the object function on each new tet, queue bad tets. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::suppressfacetpoint(face* supsh, list* frontlist, list* misfrontlist, list* ptlist, list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag) { list *oldtetlist[2], *newtetlist[2]; list *oldshlist, *newshlist; list *gluetetlist; list *glueshlist; triface oldtet, newtet, neightet; face oldsh, newsh; point suppt, newpt[2]; point *cons, *ppt; enum interresult dir; REAL norm[3]; bool success; int bakchecksubfaces; int shmark; int i, j; suppt = sapex(*supsh); if (b->verbose > 1) { printf(" Suppress point %d in facet.\n", pointmark(suppt)); } // Initialize working lists, variables. for (i = 0; i < 2; i++) { oldtetlist[i] = (list *) NULL; newtetlist[i] = (list *) NULL; newpt[i] = (point) NULL; } gluetetlist = new list(sizeof(triface), NULL, 256); glueshlist = new list(sizeof(face), NULL, 256); oldshlist = new list(sizeof(face), NULL, 256); newshlist = new list(sizeof(face), NULL, 256); success = true; // Assume p can be suppressed. bakchecksubfaces = checksubfaces; checksubfaces = 0; // Find subs of C(p). oldshlist->append(supsh); formstarpolygon(suppt, oldshlist, ptlist); // Get the edges of C(p). They form a closed polygon. for (i = 0; i < oldshlist->len(); i++) { oldsh = * (face *)(* oldshlist)[i]; cons = (point *) conlist->append(NULL); cons[0] = sorg(oldsh); cons[1] = sdest(oldsh); } // Re-triangulate the old C(p). shmark = shellmark(*supsh); triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque); // Get new subs of C(p), remove protected segments. retrievenewsubs(newshlist, true); // Substitute the old C(p) with the new C(p) replacepolygonsubs(oldshlist, newshlist); // Clear work lists. ptlist->clear(); conlist->clear(); flipque->clear(); viri->restart(); checksubfaces = bakchecksubfaces; // B(p) (tets with p as a vertex) has been separated into two parts // (B_0(p) and B_1(p)) by F. Process them individually. for (i = 0; i < 2 && success; i++) { if (i == 1) sesymself(*supsh); // Get a tet containing p. stpivot(*supsh, oldtet); // Is this part empty? if (oldtet.tet == dummytet) continue; // Allocate spaces for storing (old and new) B_i(p). oldtetlist[i] = new list(sizeof(triface), NULL, 256); newtetlist[i] = new list(sizeof(triface), NULL, 256); // Form old B_i(p) in oldtetlist[i]. assert(!isdead(&oldtet)); oldtetlist[i]->append(&oldtet); formstarpolyhedron(suppt, oldtetlist[i], ptlist, false); // Infect the tets in old B_i(p) (they're going to be delete). for (j = 0; j < oldtetlist[i]->len(); j++) { oldtet = * (triface *)(* (oldtetlist[i]))[j]; infect(oldtet); } // Preparation for re-tetrahedralzing old B_i(p). orientnewsubs(newshlist, supsh, norm); // Tetrahedralize old B_i(p). success = constrainedcavity(&oldtet, newshlist, oldtetlist[i], ptlist, frontlist, misfrontlist, newtetlist[i], gluetetlist, glueshlist, flipque); // If p is not suppressed, do relocation if 'noreloc' is not set. if (!success && !noreloc) { // Try to relocate p into the old B_i(p). makepoint(&(newpt[i])); // success = findrelocatepoint(suppt, newpt[i], norm, frontlist, // oldtetlist[i]); success = findrelocatepoint2(suppt, newpt[i], norm, frontlist, oldtetlist[i]); // Initialize newpt = suppt. // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j]; // success = smoothvolpoint(newpt[i], frontlist, true); if (success) { // p is relocated by newpt[i]. Now insert it. Don't do flip since // the new tets may get deleted again. relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL); setpointtype(newpt[i], FREEVOLVERTEX); relverts++; } else { // Fail to relocate p. Clean fake tets and quit this option. deallocfaketets(frontlist); pointdealloc(newpt[i]); newpt[i] = (point) NULL; assert(newtetlist[i]->len() == 0); } } if (!success && noreloc) { // Failed and no point relocation. Clean fake tets. deallocfaketets(frontlist); } // Clear work lists. ptlist->clear(); frontlist->clear(); misfrontlist->clear(); // Do not clear gluetetlist. gluetetlist->clear(); // Do not clear glueshlist. flipque->clear(); } if (success) { // p has been removed! (Still in the pool). setpointtype(suppt, UNUSEDVERTEX); unuverts++; // Delete old C(p). for (i = 0; i < oldshlist->len(); i++) { oldsh = * (face *)(* oldshlist)[i]; if (i == 0) { // Update the 'hullsize' if C(p) is on the hull. stpivot(oldsh, oldtet); if (oldtet.tet != dummytet) { sesymself(oldsh); stpivot(oldsh, oldtet); } if (oldtet.tet == dummytet) { // A boundary face. Update the 'hullsize'. j = oldshlist->len() - newshlist->len(); assert(j > 0); hullsize -= j; } } shellfacedealloc(subfaces, oldsh.sh); } // Delete old B_i(p). for (i = 0; i < 2; i++) { if (oldtetlist[i] != (list *) NULL) { // Delete tets of the old B_i(p). for (j = 0; j < oldtetlist[i]->len(); j++) { oldtet = * (triface *)(* (oldtetlist[i]))[j]; assert(!isdead(&oldtet)); tetrahedrondealloc(oldtet.tet); } } } if (optflag) { // Check for new bad-quality tets. for (i = 0; i < 2; i++) { if (newtetlist[i] != (list *) NULL) { for (j = 0; j < newtetlist[i]->len(); j++) { newtet = * (triface *)(* (newtetlist[i]))[j]; if (!isdead(&newtet)) checktet4opt(&newtet, true); } } } } // Insert outside new subfaces (if there are). 2009-07-08. for (i = 0; i < glueshlist->len(); i++) { newsh = * (face *)(* glueshlist)[i]; // Insert it into mesh (it may be already inserted). newtet.tet = NULL; // The mesh may be non-convex (set convexflag = 0). dir = scoutsubface(&newsh, &newtet, 0); if (dir != SHAREFACE) { assert(0); } } } else { // p is not suppressed. Recover the original state. unsupverts++; // Restore the old C(p). replacepolygonsubs(newshlist, oldshlist); // Delete subs of the new C(p) for (i = 0; i < newshlist->len(); i++) { newsh = * (face *)(* newshlist)[i]; shellfacedealloc(subfaces, newsh.sh); } // Delete new subfaces in glueshlist. 2009-07-07 for (i = 0; i < glueshlist->len(); i++) { newsh = * (face *)(* glueshlist)[i]; for (j = 0; j < 2; j++) { stpivot(newsh, oldtet); if (oldtet.tet != dummytet) { tsdissolve(oldtet); } sesymself(newsh); } shellfacedealloc(subfaces, newsh.sh); } // Restore old B_i(p). for (i = 0; i < 2; i++) { if (oldtetlist[i] != (list *) NULL) { // Uninfect tets of old B_i(p). for (j = 0; j < oldtetlist[i]->len(); j++) { oldtet = * (triface *)(* (oldtetlist[i]))[j]; assert(infected(oldtet)); uninfect(oldtet); } // Has it been re-meshed? // if (newtetlist[i]->len() > 0) { // Restore the old B_i(p). restorepolyhedron(oldtetlist[i]); // Delete tets of the new B_i(p); for (j = 0; j < newtetlist[i]->len(); j++) { newtet = * (triface *)(* (newtetlist[i]))[j]; // Some new tets may already be deleted (by carvecavity()). if (!isdead(&newtet)) { tetrahedrondealloc(newtet.tet); } } // } // Dealloc newpt[i] if it exists. if (newpt[i] != (point) NULL) { pointdealloc(newpt[i]); relverts--; } } } // Detach new subfaces attached to glue tets. 2009-07-10. for (i = 0; i < gluetetlist->len(); i++) { oldtet = * (triface *)(* gluetetlist)[i]; if (!isdead(&oldtet)) { // It contains a new subface which has already been deleted (in above). tspivot(oldtet, newsh); assert(isdead(&newsh)); tsdissolve(oldtet); sym(oldtet, neightet); if (neightet.tet != dummytet) { tsdissolve(neightet); } } } // Update the point-to-subface map. 2009-07-22. for (i = 0; i < oldshlist->len(); i++) { oldsh = * (face *)(* oldshlist)[i]; ppt = (point *) &(oldsh.sh[3]); for (j = 0; j < 3; j++) { setpoint2sh(ppt[j], sencode(oldsh)); } } } // Delete work lists. delete oldshlist; delete newshlist; for (i = 0; i < 2; i++) { if (oldtetlist[i] != (list *) NULL) { delete oldtetlist[i]; delete newtetlist[i]; } } delete gluetetlist; delete glueshlist; return success; } /////////////////////////////////////////////////////////////////////////////// // // // suppresssegpoint() Suppress a point on a segment. // // // // The point p on a segment S will be suppressed from S by either being // // deleted from the mesh or being relocated into the volume. // // // // 'supseg' is the segment S, and p = sdest(S); the other parameters are // // working lists which are empty at the beginning and the end. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::suppresssegpoint(face* supseg, list* spinshlist, list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist, list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag) { list **oldtetlist, **newtetlist; list **oldshlist, **newshlist; list *pnewshlist, *dnewshlist; list *gluetetlist; list *glueshlist; triface oldtet, newtet, neightet, spintet; face oldsh, newsh, *worksharray; face startsh, spinsh, segsh1, segsh2; face nsupseg, newseg, prevseg, nextseg; point suppt, *newpt; point pa, pb, pc, pd, *cons, *ppt; enum interresult dir; REAL pnorm[2][3], norm[3], len; bool success; int bakchecksubfaces; int shmark; int n, i, j, k; // Get the Steiner point p. assert(supseg->shver < 2); suppt = sdest(*supseg); // Find the segment ab split by p. senext(*supseg, nsupseg); spivotself(nsupseg); assert(nsupseg.sh != dummysh); nsupseg.shver = 0; if (sorg(nsupseg) != suppt) sesymself(nsupseg); assert(sorg(nsupseg) == suppt); pa = sorg(*supseg); pb = sdest(nsupseg); if (b->verbose > 1) { printf(" Remove point %d on segment (%d, %d).\n", pointmark(suppt), pointmark(pa), pointmark(pb)); } // Let startsh s containing p. spivot(*supseg, startsh); spinsh = startsh; do { // Adjust spinsh to be the edge [pa, suppt]. findedge(&spinsh, pa, suppt); // Save it in list. spinshlist->append(&spinsh); // Go to the next facet. spivotself(spinsh); if (spinsh.sh == dummysh) break; } while (spinsh.sh != startsh.sh); n = spinshlist->len(); if (n > 2) { // Order the subfaces to be counterclockwise around edge [pa, suppt]. worksharray = new face[n]; // Temporarily use it. for (i = 0; i < n; i++) { worksharray[i] = * (face *)(* spinshlist)[i]; sinfect(worksharray[i]); } spinshlist->clear(); // Clear the list for the re-ordering. for (i = 0; i < n; i++) { worksharray[i] = * (face *)(* spinshlist)[i]; if (sinfected(worksharray[i])) { // Collect subfaces at this segment. startsh = worksharray[i]; stpivot(startsh, neightet); if (neightet.tet == dummytet) { sesymself(startsh); stpivot(startsh, neightet); assert(neightet.tet != dummytet); } // Adjust neightet to be the edge [pa, suppt]. findedge(&neightet, pa, suppt); // Adjust neightet to be the boundary face (if there exists). spintet = neightet; while (1) { if (!fnextself(spintet)) { esymself(spintet); break; } if (apex(spintet) == apex(neightet)) break; } // Start from spintet, collect all subfaces at this segment. neightet = spintet; pc = org(spintet); pd = dest(spintet); // [pc, pd] is the rotating edge (axis). It may be either // [pa, suppt] or [suppt, pa]. while (1) { tspivot(spintet, spinsh); if (spinsh.sh != dummysh) { assert(sinfected(spinsh)); suninfect(spinsh); // Let spinsh be the same oriented edge as spintet. findedge(&spinsh, pc, pd); spinshlist->append(&spinsh); } if (!fnextself(spintet)) break; if (apex(spintet) == apex(neightet)) break; } } assert(!sinfected(worksharray[i])); } // i delete [] worksharray; } if (spinshlist->len() == 1) { // This case has not handled yet. // printf("Unhandled case: segment only belongs to one facet.\n"); spinshlist->clear(); unsupverts++; return false; } // Suppose ab is shared by n facets (n > 1), then there are n B(p) (tets // with p as a vertex). Some B(p) may be empty, eg, outside. // n = spinshlist->len(); oldtetlist = new list*[n]; newtetlist = new list*[n]; oldshlist = new list*[n]; newshlist = new list*[n]; newpt = new point[n]; for (i = 0; i < n; i++) { oldtetlist[i] = (list *) NULL; newtetlist[i] = (list *) NULL; oldshlist[i] = (list *) NULL; newshlist[i] = (list *) NULL; newpt[i] = (point) NULL; } gluetetlist = new list(sizeof(triface), NULL, 256); glueshlist = new list(sizeof(face), NULL, 256); // Create a new segment ab (result in newseg). makeshellface(subsegs, &newseg); setsorg(newseg, pa); setsdest(newseg, pb); // ab gets the same mark and segment type as ap. setshellmark(newseg, shellmark(*supseg)); setshelltype(newseg, shelltype(*supseg)); if (b->quality && varconstraint) { // Copy the areabound into the new subsegment. setareabound(newseg, areabound(*supseg)); } // Save the old connection at a. senext2(*supseg, prevseg); spivotself(prevseg); if (prevseg.sh != dummysh) { prevseg.shver = 0; if (sdest(prevseg) != pa) sesymself(prevseg); assert(sdest(prevseg) == pa); senextself(prevseg); senext2self(newseg); sbond(newseg, prevseg); newseg.shver = 0; } // Save the old connection at b. senext(nsupseg, nextseg); spivotself(nextseg); if (nextseg.sh != dummysh) { nextseg.shver = 0; if (sorg(nextseg) != pb) sesymself(nextseg); assert(sorg(nextseg) == pb); senext2self(nextseg); senextself(newseg); sbond(newseg, nextseg); newseg.shver = 0; } bakchecksubfaces = checksubfaces; checksubfaces = 0; // Re-triangulate C(p) (subs with p as a vertex) to remove p. for (i = 0; i < spinshlist->len(); i++) { spinsh = * (face *)(* spinshlist)[i]; // Allocate spaces for C_i(p). oldshlist[i] = new list(sizeof(face), NULL, 256); newshlist[i] = new list(sizeof(face), NULL, 256); // Get the subs of C_i(p). oldshlist[i]->append(&spinsh); formstarpolygon(suppt, oldshlist[i], ptlist); // Find the edges of C_i(p). It DOES NOT form a closed polygon. for (j = 0; j < oldshlist[i]->len(); j++) { oldsh = * (face *)(* (oldshlist[i]))[j]; cons = (point *) conlist->append(NULL); cons[0] = sorg(oldsh); cons[1] = sdest(oldsh); } // The C_i(p) isn't closed without ab. Add it to it. cons = (point *) conlist->append(NULL); cons[0] = pa; cons[1] = pb; // Re-triangulate C_i(p). shmark = shellmark(spinsh); triangulate(shmark, b->epsilon, ptlist, conlist, 0, NULL, viri, flipque); // Get new subs of C_i(p), remove protected segments. retrievenewsubs(newshlist[i], true); // Substitute old C_i(p) with the new C_i(p). !IT IS NOT COMPLETE! replacepolygonsubs(oldshlist[i], newshlist[i]); // Find the new subface s having edge ab. for (j = 0; j < newshlist[i]->len(); j++) { segsh1 = * (face *)(* (newshlist[i]))[j]; for (k = 0; k < 3; k++) { if (((sorg(segsh1) == pa) && (sdest(segsh1) == pb)) || ((sorg(segsh1) == pb) && (sdest(segsh1) == pa))) break; senextself(segsh1); } if (k < 3) break; // Found. } assert(j < newshlist[i]->len()); // ab must exist. // Bond s and ab together. The C_i(p) is completedly substituted. ssbond(segsh1, newseg); // Save s for forming the face ring of ab. newsegshlist->append(&segsh1); // Clear work lists. ptlist->clear(); conlist->clear(); flipque->clear(); viri->restart(); } // Form the face ring of ab. for (i = 0; i < newsegshlist->len(); i++) { segsh1 = * (face *)(* newsegshlist)[i]; if ((i + 1) == newsegshlist->len()) { segsh2 = * (face *)(* newsegshlist)[0]; } else { segsh2 = * (face *)(* newsegshlist)[i + 1]; } sbond1(segsh1, segsh2); } checksubfaces = bakchecksubfaces; // A work list for keeping subfaces from two facets. dnewshlist = new list(sizeof(face), NULL, 256); success = true; // Assume p is suppressable. // Suppress p in all B(p). B_i(p) is looped wrt the right-hand rule of ab. for (i = 0; i < spinshlist->len() && success; i++) { // Get an old subface s (ap) of a facet. spinsh = * (face *)(* spinshlist)[i]; // // Let the edge direction of s be a->b. Hence all subfaces follow // // the right-hand rule of ab. // if (sorg(spinsh) != pa) sesymself(spinsh); // spinsh has been directed. Do not change its orientation now. // Get a tet t of B_i(p). stpivot(spinsh, oldtet); // Is B_i(p) empty? if (oldtet.tet == dummytet) continue; // Allocate spaces for B_i(p). oldtetlist[i] = new list(sizeof(triface), NULL, 256); newtetlist[i] = new list(sizeof(triface), NULL, 256); // Find all tets of old B_i(p). oldtetlist[i]->append(&oldtet); formstarpolyhedron(suppt, oldtetlist[i], ptlist, false); // Infect tets of old B_i(p) (they're going to be deleted). for (j = 0; j < oldtetlist[i]->len(); j++) { oldtet = * (triface *)(* (oldtetlist[i]))[j]; infect(oldtet); } // Collect new subfaces (of two facets) bounded B_i(p). for (k = 0; k < 2; k++) { if ((i + k) < spinshlist->len()) { pnewshlist = newshlist[i + k]; segsh1 = * (face *)(* spinshlist)[i + k]; } else { pnewshlist = newshlist[0]; segsh1 = * (face *)(* spinshlist)[0]; } /*// Adjust the orientation of segsh1 to face to the inside of C. if (k == 0) { if (sorg(segsh1) != pa) sesymself(segsh1); assert(sorg(segsh1) == pa); } else { if (sdest(segsh1) != pa) sesymself(segsh1); assert(sdest(segsh1) == pa); }*/ if (k == 0) { // segsh1 has already been directed pointing to the inside of C. } else { // Reverse the direction of segsh1. sesymself(segsh1); } // its orientation now. // Preparation for re-tetrahedralzing old B_i(p). orientnewsubs(pnewshlist, &segsh1, pnorm[k]); for (j = 0; j < pnewshlist->len(); j++) { dnewshlist->append((face *)(* pnewshlist)[j]); } } // Tetrahedralize B_i(p). success = constrainedcavity(&oldtet, dnewshlist, oldtetlist[i], ptlist, frontlist, misfrontlist, newtetlist[i], gluetetlist, glueshlist, flipque); if (!success && !noreloc) { // C must be finished by re-locating the steiner point. makepoint(&(newpt[i])); for (j = 0; j < 3; j++) norm[j] = 0.5 * (pnorm[0][j] + pnorm[1][j]); // Normialize the normal. len = sqrt(norm[0] * norm[0] + norm[1] * norm[1] + norm[2] * norm[2]); assert(len != 0); for (j = 0; j < 3; j++) norm[j] /= len; // success = findrelocatepoint(suppt, newpt[i], norm, frontlist, // oldtetlist[i]); success = findrelocatepoint2(suppt, newpt[i], norm, frontlist, oldtetlist[i]); // success = findrelocatepoint3(suppt, pa, pb, newpt[i], norm, frontlist, // oldtetlist[i]); // for (j = 0; j < 3; j++) newpt[i][j] = suppt[j]; // success = smoothvolpoint(newpt[i], frontlist, true); if (success) { // p is relocated by newpt[i]. Now insert it. Don't do flip since // the new tets may get deleted again. if (relocatepoint(newpt[i], &oldtet, frontlist, newtetlist[i], NULL)) { setpointtype(newpt[i], FREEVOLVERTEX); relverts++; } else { // The faked tets are deleted in above route. pointdealloc(newpt[i]); newpt[i] = (point) NULL; newtetlist[i]->clear(); success = false; } } else { // Fail to relocate p. Clean fake tets and quit this option. deallocfaketets(frontlist); pointdealloc(newpt[i]); newpt[i] = (point) NULL; assert(newtetlist[i]->len() == 0); } } if (!success && noreloc) { // Failed and no point relocation. Clean fake tets. deallocfaketets(frontlist); } // Clear work lists. dnewshlist->clear(); ptlist->clear(); frontlist->clear(); misfrontlist->clear(); // Do not clear gluetetlist. // gluetetlist->clear(); // Do not clear glueshlist. flipque->clear(); } if (success) { // p has been suppressed. (Still in the pool). setpointtype(suppt, UNUSEDVERTEX); unuverts++; // Update the point-to-seg map. setpoint2seg(pa, sencode(newseg)); setpoint2seg(pb, sencode(newseg)); // Delete old segments ap, pb. shellfacedealloc(subsegs, supseg->sh); shellfacedealloc(subsegs, nsupseg.sh); // Delete subs of old C_i(p). for (i = 0; i < spinshlist->len(); i++) { for (j = 0; j < oldshlist[i]->len(); j++) { oldsh = * (face *)(* (oldshlist[i]))[j]; if (j == 0) { // Update 'hullsize' if C_i(p) is on the hull. stpivot(oldsh, oldtet); if (oldtet.tet != dummytet) { sesymself(oldsh); stpivot(oldsh, oldtet); } if (oldtet.tet == dummytet) { // Update 'hullsize'. k = oldshlist[i]->len() - newshlist[i]->len(); assert(k > 0); hullsize -= k; } } shellfacedealloc(subfaces, oldsh.sh); } } // Delete tets old B_i(p). for (i = 0; i < spinshlist->len(); i++) { // Delete them if it is not empty. if (oldtetlist[i] != (list *) NULL) { for (j = 0; j < oldtetlist[i]->len(); j++) { oldtet = * (triface *)(* (oldtetlist[i]))[j]; assert(!isdead(&oldtet)); tetrahedrondealloc(oldtet.tet); } } } if (optflag) { for (i = 0; i < spinshlist->len(); i++) { // Check for new bad-quality tets. if (newtetlist[i] != (list *) NULL) { for (j = 0; j < newtetlist[i]->len(); j++) { newtet = * (triface *)(* (newtetlist[i]))[j]; if (!isdead(&newtet)) checktet4opt(&newtet, true); } } } } // Insert outside new subfaces (if there are). 2009-07-08. for (i = 0; i < glueshlist->len(); i++) { newsh = * (face *)(* glueshlist)[i]; // Insert it into mesh (it may be already inserted). newtet.tet = NULL; // The mesh may be non-convex (set convexflag = 0). dir = scoutsubface(&newsh, &newtet, 0); if (dir != SHAREFACE) { assert(0); } } } else { // p is not suppressed. Recover the original state. unsupverts++; // Restore old connection at a. senext2(*supseg, prevseg); spivotself(prevseg); if (prevseg.sh != dummysh) { prevseg.shver = 0; if (sdest(prevseg) != pa) sesymself(prevseg); assert(sdest(prevseg) == pa); senextself(prevseg); senext2self(*supseg); sbond(*supseg, prevseg); senextself(*supseg); // Restore original state. assert(supseg->shver < 2); } // Restore old connection at b. senext(nsupseg, nextseg); spivotself(nextseg); if (nextseg.sh != dummysh) { nextseg.shver = 0; if (sorg(nextseg) != pb) sesymself(nextseg); assert(sorg(nextseg) == pb); senext2self(nextseg); senextself(nsupseg); sbond(nsupseg, nextseg); // nsupseg.shver = 0; senext2self(nsupseg); // Restore original state assert(nsupseg.shver < 2); } // Delete the new segment ab. shellfacedealloc(subsegs, newseg.sh); // Restore old C_i(p). for (i = 0; i < spinshlist->len(); i++) { replacepolygonsubs(newshlist[i], oldshlist[i]); // Delete subs of the new C_i(p) for (j = 0; j < newshlist[i]->len(); j++) { newsh = * (face *)(* (newshlist[i]))[j]; shellfacedealloc(subfaces, newsh.sh); } } // Delete new subfaces in glueshlist. 2009-07-07. for (i = 0; i < glueshlist->len(); i++) { newsh = * (face *)(* glueshlist)[i]; if (!isdead(&newsh)) { // Disconnect adjacent tets. for (j = 0; j < 2; j++) { stpivot(newsh, oldtet); if (oldtet.tet != dummytet) { tsdissolve(oldtet); } sesymself(newsh); } shellfacedealloc(subfaces, newsh.sh); } } // Restore old B_i(p). for (i = 0; i < spinshlist->len(); i++) { if (oldtetlist[i] != (list *) NULL) { // Uninfect tets of old B_i(p). for (j = 0; j < oldtetlist[i]->len(); j++) { oldtet = * (triface *)(* (oldtetlist[i]))[j]; assert(infected(oldtet)); uninfect(oldtet); } // Has it been re-meshed? // if (newtetlist[i]->len() > 0) { // Restore the old B_i(p). restorepolyhedron(oldtetlist[i]); // Delete tets of the new B_i(p); for (j = 0; j < newtetlist[i]->len(); j++) { newtet = * (triface *)(* (newtetlist[i]))[j]; // Some new tets may already be deleted (by carvecavity()). if (!isdead(&newtet)) { tetrahedrondealloc(newtet.tet); } } // } // Dealloc newpt[i] if it exists. if (newpt[i] != (point) NULL) { pointdealloc(newpt[i]); relverts--; } } } // Detach new subfaces attached to glue tets. 2009-07-10. for (i = 0; i < gluetetlist->len(); i++) { oldtet = * (triface *)(* gluetetlist)[i]; if (!isdead(&oldtet)) { // It contains a new subface which has already been deleted (in above). tspivot(oldtet, newsh); assert(isdead(&newsh)); tsdissolve(oldtet); sym(oldtet, neightet); if (neightet.tet != dummytet) { tsdissolve(neightet); } } } // Update the point-to-subface map. 2009-07-22. for (i = 0; i < spinshlist->len(); i++) { for (j = 0; j < oldshlist[i]->len(); j++) { oldsh = * (face *)(* oldshlist[i])[j]; ppt = (point *) &(oldsh.sh[3]); for (k = 0; k < 3; k++) { setpoint2sh(ppt[k], sencode(oldsh)); } } } } // Delete work lists. delete [] newpt; // BUG fixed. Thanks dmyan, June 23, 2007. delete dnewshlist; for (i = 0; i < spinshlist->len(); i++) { delete oldshlist[i]; delete newshlist[i]; } delete [] oldshlist; delete [] newshlist; for (i = 0; i < spinshlist->len(); i++) { if (oldtetlist[i] != (list *) NULL) { delete oldtetlist[i]; delete newtetlist[i]; } } delete [] oldtetlist; delete [] newtetlist; delete gluetetlist; delete glueshlist; // Clear work lists. newsegshlist->clear(); spinshlist->clear(); return success; } /////////////////////////////////////////////////////////////////////////////// // // // suppressvolpoint() Suppress a point inside mesh. // // // // The point p = org(suptet) is inside the mesh and will be suppressed from // // the mesh. Note that p may not be suppressed. // // // // 'optflag' is used for mesh optimization. If it is set, after removing p, // // test the object function on each new tet, queue bad tets. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::suppressvolpoint(triface* suptet, list* frontlist, list* misfrontlist, list* ptlist, queue* flipque, bool optflag) { list *myfrontlist, *mymisfrontlist, *myptlist; list *oldtetlist, *newtetlist; list *gluetetlist; list *glueshlist; list *newshlist; // a dummy list. queue *myflipque; triface oldtet, newtet; point suppt, conpt, *ppt; bool success; int j, k; // Allocate spaces for storing (old and new) B(p). oldtetlist = new list(sizeof(triface), NULL, 256); newtetlist = new list(sizeof(triface), NULL, 256); gluetetlist = new list(sizeof(triface), NULL, 256); glueshlist = new list(sizeof(face), NULL, 256); newshlist = new list(sizeof(face), NULL, 256); // Allocate work lists if user doesn't supply them. myfrontlist = mymisfrontlist = myptlist = (list *) NULL; myflipque = (queue *) NULL; if (frontlist == (list *) NULL) { myfrontlist = new list(sizeof(triface), NULL, 256); frontlist = myfrontlist; mymisfrontlist = new list(sizeof(triface), NULL, 256); misfrontlist = mymisfrontlist; myptlist = new list(sizeof(point *), NULL, 256); ptlist = myptlist; myflipque = new queue(sizeof(badface)); flipque = myflipque; } suppt = org(*suptet); oldtet = *suptet; success = true; // Assume p can be suppressed. if (b->verbose > 1) { printf(" Remove point %d in mesh.\n", pointmark(suppt)); } // Form old B(p) in oldtetlist. oldtetlist->append(&oldtet); formstarpolyhedron(suppt, oldtetlist, ptlist, false); // Infect the tets in old B(p) (they're going to be delete). for (j = 0; j < oldtetlist->len(); j++) { oldtet = * (triface *)(* oldtetlist)[j]; infect(oldtet); } // Tetrahedralize old B(p). success = constrainedcavity(&oldtet, newshlist, oldtetlist, ptlist, frontlist, misfrontlist, newtetlist, gluetetlist, glueshlist, flipque); if (!success) { // Unable to suppress p. deallocfaketets(frontlist); // Try to collapse an edge at p. conpt = (point) NULL; assert(newtetlist->len() == 0); if (findcollapseedge(suppt, &conpt, oldtetlist, ptlist)) { // Collapse the edge suppt->conpt. Re-use newtetlist. collapseedge(suppt, conpt, oldtetlist, newtetlist); // The oldtetlist contains newtetlist. if (optflag) { assert(newtetlist->len() == 0); for (j = 0; j < oldtetlist->len(); j++) { newtet = * (triface *)(* oldtetlist)[j]; newtetlist->append(&newtet); } } oldtetlist->clear(); // Do not delete them. collapverts++; success = true; } } if (success) { // p has been removed! (Still in the pool). setpointtype(suppt, UNUSEDVERTEX); unuverts++; suprelverts++; // Delete old B(p). for (j = 0; j < oldtetlist->len(); j++) { oldtet = * (triface *)(* oldtetlist)[j]; assert(!isdead(&oldtet)); tetrahedrondealloc(oldtet.tet); } if (optflag) { // Check for new bad tets. for (j = 0; j < newtetlist->len(); j++) { newtet = * (triface *)(* newtetlist)[j]; if (!isdead(&newtet)) checktet4opt(&newtet, true); } } } else { // p is not suppressed. Recover the original state. // Uninfect tets of old B(p). for (j = 0; j < oldtetlist->len(); j++) { oldtet = * (triface *)(* oldtetlist)[j]; assert(infected(oldtet)); uninfect(oldtet); // Update the point-to-tet map. ppt = (point *) &(oldtet.tet[4]); for (k = 0; k < 4; k++) { setpoint2tet(ppt[k], encode(oldtet)); } } } // Clear work lists. ptlist->clear(); frontlist->clear(); misfrontlist->clear(); gluetetlist->clear(); glueshlist->clear(); flipque->clear(); // Deallocate work lists. if (myfrontlist != (list *) NULL) { delete myfrontlist; delete mymisfrontlist; delete myptlist; delete myflipque; } delete oldtetlist; delete newtetlist; delete gluetetlist; delete glueshlist; delete newshlist; return success; } /////////////////////////////////////////////////////////////////////////////// // // // removesteiners2() Remove Steiner points. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::removesteiners2() { list *frontlist, *misfrontlist; list *spinshlist, *newsegshlist; list *ptlist, *conlist; memorypool *viri; queue *flipque; triface searchtet, checktet; face searchsh; face searchseg; point pa, pt; enum verttype vtype; bool remflag, success; //, optflag; int oldnum, rmstein; int unsupbdrycount; // Count the unsuppressed boundary Steiner points. int iter, i, j; if (!b->quiet) { printf("Removing Steiner points.\n"); } // Initialize work lists. frontlist = new list(sizeof(triface), NULL); misfrontlist = new list(sizeof(triface), NULL); spinshlist = new list(sizeof(face), NULL); newsegshlist = new list(sizeof(face), NULL); ptlist = new list(sizeof(point *), NULL); conlist = new list(sizeof(point *) * 2, NULL); flipque = new queue(sizeof(badface)); viri = new memorypool(sizeof(shellface *), 1024, POINTER, 0); caveshlist = new arraypool(sizeof(face), 10); caveshbdlist = new arraypool(sizeof(face), 10); oldnum = unuverts; relverts = suprelverts = collapverts = unsupverts; iter = 0; i = 0; do { // iter unsupbdrycount = 0; // Initialize the two arrays (global values). fixededgelist = new arraypool(sizeof(point) * 2, 8); elemfliplist = new arraypool(sizeof(elemflip), 8); do { // i rmstein = unuverts; points->traversalinit(); pa = pointtraverse(); while (pa != NULL) { j = pointmark(pa) - in->firstnumber; if (j >= in->numberofpoints) { // pa is not an input points. vtype = pointtype(pa); if ((vtype == FREESEGVERTEX) || (vtype == FREESUBVERTEX) || (vtype == FREEVOLVERTEX)) { i++; if (b->verbose > 1) { printf(" Removing %d-th Steiner point %d.\n", i, pointmark(pa)); } } if (vtype == FREESEGVERTEX) { remflag = false; // pa is not an input point. if (b->nobisect == 1) { point2segorg(pa, searchseg); sstpivot(&searchseg, &checktet); assert(checktet.tet != dummytet); pt = apex(checktet); do { if (!fnextself(checktet)) { // Meet a boundary face - p is on the hull. remflag = true; break; } } while (apex(checktet) != pt); } else { // '-YY'. Remove p whatever s is a hull face or not. remflag = true; } if (remflag) { point2segorg(pa, searchseg); sesymself(searchseg); // pa = sdest(); success = suppresssegpoint(&searchseg, spinshlist, newsegshlist, frontlist, misfrontlist, ptlist, conlist, viri, flipque, false, false); } } else if (vtype == FREESUBVERTEX) { remflag = false; // pa is not an input point. if (b->nobisect == 1) { // '-Y'. Remove p if s is a hull face. point2shorg(pa, searchsh); stpivot(searchsh, checktet); if (checktet.tet != dummytet) { sesymself(searchsh); stpivot(searchsh, checktet); } remflag = (checktet.tet == dummytet); } else { // '-YY'. Remove p whatever s is a hull face or not. remflag = true; } if (remflag) { point2shorg(pa, searchsh); senextself(searchsh); // pa = sapex(); success = suppressfacetpoint(&searchsh, frontlist, misfrontlist, ptlist, conlist, viri, flipque, false, false); } } else if (vtype == FREEVOLVERTEX) { // pa is not an input point. point2tetorg(pa, searchtet); success = suppressvolpoint(&searchtet, frontlist, misfrontlist, ptlist, flipque, false); } } // if (j >= in->numberofpoints) pa = pointtraverse(); } // Continue if any Steiner point has been removed. } while (unuverts > rmstein); delete fixededgelist; delete elemfliplist; fixededgelist = NULL; elemfliplist = NULL; if (b->optlevel > 0) { // b->optlevel is set by -s. // Improve the local mesh quality at relocated Steiner points. b_steinerflag = true; optimizemesh2(true); b_steinerflag = false; // Smooth the relocated vertices (also count unsupressed vertices). points->traversalinit(); pa = pointtraverse(); while (pa != NULL) { j = pointmark(pa) - in->firstnumber; if (j >= in->numberofpoints) { // pa is not an input point. vtype = pointtype(pa); if (vtype == FREEVOLVERTEX) { point2tetorg(pa, searchtet); frontlist->append(&searchtet); formstarpolyhedron(pa, frontlist, NULL, false); smoothpoint(pa, NULL, NULL, frontlist, false, NULL); frontlist->clear(); } else if (vtype == FREESEGVERTEX) { remflag = false; // pa is not an input point. if (b->nobisect == 1) { point2segorg(pa, searchseg); sstpivot(&searchseg, &checktet); assert(checktet.tet != dummytet); pt = apex(checktet); do { if (!fnextself(checktet)) { // Meet a boundary face - p is on the hull. remflag = true; break; } } while (apex(checktet) != pt); } else { // '-YY'. Remove p whatever s is a hull face or not. remflag = true; } if (remflag) { unsupbdrycount++; } } else if (vtype == FREESUBVERTEX) { remflag = false; // pa is not an input point. if (b->nobisect == 1) { // '-Y'. Remove p if s is a hull face. point2shorg(pa, searchsh); stpivot(searchsh, checktet); if (checktet.tet != dummytet) { sesymself(searchsh); stpivot(searchsh, checktet); } remflag = (checktet.tet == dummytet); } else { // '-YY'. Remove p whatever s is a hull face or not. remflag = true; } if (remflag) { unsupbdrycount++; } } } pa = pointtraverse(); } } if (unsupbdrycount == 0) { break; // No unsupressed boundary points left. } iter++; } while ((b->optlevel > 0) && (iter < b->optpasses)); // Comment: default b->optpasses is 3, it can be set by -ss option. if (b->verbose > 0) { printf(" %d points removed from boundary.\n", unuverts - oldnum); // if (relverts > 0) { printf(" %d points relocated (%d suppressed, %d collapsed).\n", relverts, suprelverts - collapverts, collapverts); if (unsupverts > 0) { printf(" %d points were unsuppressed.\n", unsupverts); } if (unsupbdrycount > 0) { printf(" !! %d points remain in the boundary.\n", unsupbdrycount); } printf(" %d points remain in the interior.\n", relverts-suprelverts); // } } /*// DEBUG Dump extremly bad tets. badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0); cosmaxdihed = cos(179.999 * PI / 180.0); cosmindihed = cos(0.1 * PI / 180.0); tallslivers(true); dumpbadtets(); delete badtetrahedrons; badtetrahedrons = NULL; // DEBUG END */ delete caveshlist; delete caveshbdlist; caveshlist = NULL; caveshbdlist = NULL; // Delete work lists. delete frontlist; delete misfrontlist; delete spinshlist; delete newsegshlist; delete ptlist; delete conlist; delete flipque; delete viri; } //// //// //// //// //// steiner_cxx ////////////////////////////////////////////////////////////// //// reconstruct_cxx ////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // transfernodes() Transfer nodes from 'io->pointlist' to 'this->points'. // // // // Initializing 'this->points'. Transferring all points from 'in->pointlist'// // into it. All points are indexed (start from in->firstnumber). Each point // // is initialized be UNUSEDVERTEX. The bounding box (xmin, xmax, ymin, ymax,// // zmin, zmax) and the diameter (longest) of the point set are calculated. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::transfernodes() { point pointloop; REAL x, y, z; int coordindex; int attribindex; int mtrindex; int i, j; // Read the points. coordindex = 0; attribindex = 0; mtrindex = 0; for (i = 0; i < in->numberofpoints; i++) { makepoint(&pointloop); // Read the point coordinates. x = pointloop[0] = in->pointlist[coordindex++]; y = pointloop[1] = in->pointlist[coordindex++]; z = pointloop[2] = in->pointlist[coordindex++]; // Read the point attributes. for (j = 0; j < in->numberofpointattributes; j++) { pointloop[3 + j] = in->pointattributelist[attribindex++]; } // Read the point metric tensor. for (j = 0; j < in->numberofpointmtrs; j++) { pointloop[pointmtrindex + j] = in->pointmtrlist[mtrindex++]; } // Determine the smallest and largests x, y and z coordinates. if (i == 0) { xmin = xmax = x; ymin = ymax = y; zmin = zmax = z; } else { xmin = (x < xmin) ? x : xmin; xmax = (x > xmax) ? x : xmax; ymin = (y < ymin) ? y : ymin; ymax = (y > ymax) ? y : ymax; zmin = (z < zmin) ? z : zmin; zmax = (z > zmax) ? z : zmax; } } // 'longest' is the largest possible edge length formed by input vertices. x = xmax - xmin; y = ymax - ymin; z = zmax - zmin; longest = sqrt(x * x + y * y + z * z); if (longest == 0.0) { printf("Error: The point set is trivial.\n"); terminatetetgen(3); } // Two identical points are distinguished by 'lengthlimit'. lengthlimit = longest * b->epsilon * 1e+2; } /////////////////////////////////////////////////////////////////////////////// // // // reconstructmesh() Reconstruct a tetrahedral mesh. // // // // The list of tetrahedra will be read from 'in->tetrahedronlist'. If 'in-> // // trifacelist' is not empty, boundary faces (faces with a non-zero marker) // // from this list will be inserted into the mesh. In addition, this routine // // automatically detects boundary faces (subfaces): all hull faces will be // // recognized as subfaces, internal faces between two tetrahedra which have // // different region attributes will also be recognized as subfaces. // // // // Subsegments will be identified after subfaces are reconstructed. Edges at // // the intersections of non-coplanar subfaces are recognized as subsegments. // // Edges between two coplanar subfaces with different boundary markers are // // also recognized as subsegments. // // // // The facet index of each subface will be set automatically after we have // // recovered subfaces and subsegments. That is, the set of subfaces, which // // are coplanar and have the same boundary marker will be recognized as a // // facet and has a unique index, stored as the facet marker in each subface // // of the set, the real boundary marker of each subface will be found in // // 'in->facetmarkerlist' by the index. Facet index will be used in Delaunay // // refinement for detecting two incident facets. // // // // Points which are not corners of tetrahedra will be inserted into the mesh.// // Return the number of faces on the hull after the reconstruction. // // // /////////////////////////////////////////////////////////////////////////////// long tetgenmesh::reconstructmesh() { tetrahedron **tetsperverlist; shellface **facesperverlist; triface tetloop, neightet, neineightet, spintet; face subloop, neighsh, neineighsh; face sface1, sface2; face checkseg, subseg; point *idx2verlist; point torg, tdest, tapex, toppo; point norg, napex; list *neighshlist, *markerlist; REAL sign, attrib, volume; REAL da1, da2; bool bondflag, insertsegflag; int *idx2tetlist; int *idx2facelist; int *worklist; int facetidx, marker; int iorg, idest, iapex, ioppo; int pivot, ipivot, isum; int maxbandwidth; int index, i, j, k; if (!b->quiet) { printf("Reconstructing mesh.\n"); } // Create a map from index to points. makeindex2pointmap(idx2verlist); // Create the tetrahedra. for (i = 0; i < in->numberoftetrahedra; i++) { // Create a new tetrahedron and set its four corners, make sure that // four corners form a positive orientation. maketetrahedron(&tetloop); index = i * in->numberofcorners; // Although there may be 10 nodes, we only read the first 4. iorg = in->tetrahedronlist[index] - in->firstnumber; idest = in->tetrahedronlist[index + 1] - in->firstnumber; iapex = in->tetrahedronlist[index + 2] - in->firstnumber; ioppo = in->tetrahedronlist[index + 3] - in->firstnumber; torg = idx2verlist[iorg]; tdest = idx2verlist[idest]; tapex = idx2verlist[iapex]; toppo = idx2verlist[ioppo]; sign = orient3d(torg, tdest, tapex, toppo); if (sign > 0.0) { norg = torg; torg = tdest; tdest = norg; } else if (sign == 0.0) { if (!b->quiet) { printf("Warning: Tet %d is degenerate.\n", i + in->firstnumber); } } setorg(tetloop, torg); setdest(tetloop, tdest); setapex(tetloop, tapex); setoppo(tetloop, toppo); // Temporarily set the vertices be type FREEVOLVERTEX, to indicate that // they belong to the mesh. These types may be changed later. setpointtype(torg, FREEVOLVERTEX); setpointtype(tdest, FREEVOLVERTEX); setpointtype(tapex, FREEVOLVERTEX); setpointtype(toppo, FREEVOLVERTEX); // Set element attributes if they exist. for (j = 0; j < in->numberoftetrahedronattributes; j++) { index = i * in->numberoftetrahedronattributes; attrib = in->tetrahedronattributelist[index + j]; setelemattribute(tetloop.tet, j, attrib); } // If -a switch is used (with no number follows) Set a volume // constraint if it exists. if (b->varvolume) { if (in->tetrahedronvolumelist != (REAL *) NULL) { volume = in->tetrahedronvolumelist[i]; } else { volume = -1.0; } setvolumebound(tetloop.tet, volume); } } // Set the connection between tetrahedra. hullsize = 0l; // Create a map from nodes to tetrahedra. maketetrahedronmap(idx2tetlist, tetsperverlist); // Initialize the worklist. worklist = new int[points->items]; for (i = 0; i < points->items; i++) worklist[i] = 0; maxbandwidth = 0; // Loop all tetrahedra, bond two tetrahedra if they share a common face. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Loop the four sides of the tetrahedron. for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { sym(tetloop, neightet); if (neightet.tet != dummytet) continue; // This side has finished. torg = org(tetloop); tdest = dest(tetloop); tapex = apex(tetloop); iorg = pointmark(torg) - in->firstnumber; idest = pointmark(tdest) - in->firstnumber; iapex = pointmark(tapex) - in->firstnumber; worklist[iorg] = 1; worklist[idest] = 1; worklist[iapex] = 1; // Pick the vertex which has the lowest degree. if ((idx2tetlist[iorg + 1] - idx2tetlist[iorg]) > (idx2tetlist[idest + 1] - idx2tetlist[idest])) { if ((idx2tetlist[idest + 1] - idx2tetlist[idest]) > (idx2tetlist[iapex + 1] - idx2tetlist[iapex])) { pivot = iapex; } else { pivot = idest; } } else { if ((idx2tetlist[iorg + 1] - idx2tetlist[iorg]) > (idx2tetlist[iapex + 1] - idx2tetlist[iapex])) { pivot = iapex; } else { pivot = iorg; } } if ((idx2tetlist[pivot + 1] - idx2tetlist[pivot]) > maxbandwidth) { maxbandwidth = idx2tetlist[pivot + 1] - idx2tetlist[pivot]; } bondflag = false; // Search its neighbor in the adjacent tets of the pivoted vertex. for (j = idx2tetlist[pivot]; j < idx2tetlist[pivot + 1] && !bondflag; j++) { // Quickly check if this tet contains the neighbor. isum = 0; for (k = 0; k < 4; k++) { norg = (point) tetsperverlist[j][4 + k]; ipivot = pointmark(norg) - in->firstnumber; isum += worklist[ipivot]; } if (isum != 3) continue; if (tetsperverlist[j] == tetloop.tet) continue; // Skip myself. // This tet contains its neighbor, find the face and bond them. neightet.tet = tetsperverlist[j]; for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { norg = oppo(neightet); ipivot = pointmark(norg) - in->firstnumber; if (worklist[ipivot] == 0) { // Find! Bond them together and break the loop. #ifdef SELF_CHECK sym(neightet, neineightet); assert(neineightet.tet == dummytet); #endif bond(tetloop, neightet); bondflag = true; break; } } } if (!bondflag) { hullsize++; // It's a hull face. // Bond this side to outer space. dummytet[0] = encode(tetloop); if ((in->pointmarkerlist != (int *) NULL) && !b->coarse) { // Set its three corners's markers be boundary (hull) vertices. if (in->pointmarkerlist[iorg] == 0) { in->pointmarkerlist[iorg] = 1; } if (in->pointmarkerlist[idest] == 0) { in->pointmarkerlist[idest] = 1; } if (in->pointmarkerlist[iapex] == 0) { in->pointmarkerlist[iapex] = 1; } } } worklist[iorg] = 0; worklist[idest] = 0; worklist[iapex] = 0; } tetloop.tet = tetrahedrontraverse(); } if (b->verbose) { printf(" Maximal vertex degree = %d.\n", maxbandwidth); } // Subfaces will be inserted into the mesh. It has two phases: // (1) Insert subfaces provided by user (in->trifacelist); // (2) Create subfaces for hull faces (if they're not subface yet) and // interior faces which separate two different materials. // Phase (1). Is there a list of user-provided subfaces? if (in->trifacelist != (int *) NULL) { // Recover subfaces from 'in->trifacelist'. for (i = 0; i < in->numberoftrifaces; i++) { index = i * 3; iorg = in->trifacelist[index] - in->firstnumber; idest = in->trifacelist[index + 1] - in->firstnumber; iapex = in->trifacelist[index + 2] - in->firstnumber; // Look for the location of this subface. worklist[iorg] = 1; worklist[idest] = 1; worklist[iapex] = 1; // Pick the vertex which has the lowest degree. if ((idx2tetlist[iorg + 1] - idx2tetlist[iorg]) > (idx2tetlist[idest + 1] - idx2tetlist[idest])) { if ((idx2tetlist[idest + 1] - idx2tetlist[idest]) > (idx2tetlist[iapex + 1] - idx2tetlist[iapex])) { pivot = iapex; } else { pivot = idest; } } else { if ((idx2tetlist[iorg + 1] - idx2tetlist[iorg]) > (idx2tetlist[iapex + 1] - idx2tetlist[iapex])) { pivot = iapex; } else { pivot = iorg; } } bondflag = false; // Search its neighbor in the adjacent tets of torg. for (j = idx2tetlist[pivot]; j < idx2tetlist[pivot + 1] && !bondflag; j++) { // Quickly check if this tet contains the neighbor. isum = 0; for (k = 0; k < 4; k++) { norg = (point) tetsperverlist[j][4 + k]; ipivot = pointmark(norg) - in->firstnumber; isum += worklist[ipivot]; } if (isum != 3) continue; neightet.tet = tetsperverlist[j]; for (neightet.loc = 0; neightet.loc < 4; neightet.loc++) { norg = oppo(neightet); ipivot = pointmark(norg) - in->firstnumber; if (worklist[ipivot] == 0) { bondflag = true; // Find! break; } } } if (bondflag) { // Create a new subface and insert it into the mesh. makeshellface(subfaces, &subloop); torg = idx2verlist[iorg]; tdest = idx2verlist[idest]; tapex = idx2verlist[iapex]; setsorg(subloop, torg); setsdest(subloop, tdest); setsapex(subloop, tapex); // Set the vertices be FREESUBVERTEX to indicate they belong to a // facet of the domain. They may be changed later. setpointtype(torg, FREESUBVERTEX); setpointtype(tdest, FREESUBVERTEX); setpointtype(tapex, FREESUBVERTEX); if (in->trifacemarkerlist != (int *) NULL) { setshellmark(subloop, in->trifacemarkerlist[i]); } adjustedgering(neightet, CCW); findedge(&subloop, org(neightet), dest(neightet)); tsbond(neightet, subloop); sym(neightet, neineightet); if (neineightet.tet != dummytet) { sesymself(subloop); tsbond(neineightet, subloop); } } else { if (!b->quiet) { printf("Warning: Subface %d is discarded.\n", i + in->firstnumber); } } worklist[iorg] = 0; worklist[idest] = 0; worklist[iapex] = 0; } } // Phase (2). Indentify subfaces from the mesh. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Loop the four sides of the tetrahedron. for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { tspivot(tetloop, subloop); if (subloop.sh != dummysh) continue; bondflag = false; sym(tetloop, neightet); if (neightet.tet == dummytet) { // It's a hull face. Insert a subface at here. bondflag = true; } else { // It's an interior face. Insert a subface if two tetrahedra have // different attributes (i.e., they belong to two regions). if (in->numberoftetrahedronattributes > 0) { if (elemattribute(neightet.tet, in->numberoftetrahedronattributes - 1) != elemattribute(tetloop.tet, in->numberoftetrahedronattributes - 1)) { bondflag = true; } } } if (bondflag) { adjustedgering(tetloop, CCW); makeshellface(subfaces, &subloop); torg = org(tetloop); tdest = dest(tetloop); tapex = apex(tetloop); setsorg(subloop, torg); setsdest(subloop, tdest); setsapex(subloop, tapex); // Set the vertices be FREESUBVERTEX to indicate they belong to a // facet of the domain. They may be changed later. setpointtype(torg, FREESUBVERTEX); setpointtype(tdest, FREESUBVERTEX); setpointtype(tapex, FREESUBVERTEX); tsbond(tetloop, subloop); if (neightet.tet != dummytet) { sesymself(subloop); tsbond(neightet, subloop); } } } tetloop.tet = tetrahedrontraverse(); } // Set the connection between subfaces. A subsegment may have more than // two subfaces sharing it, 'neighshlist' stores all subfaces sharing // one edge. neighshlist = new list(sizeof(face), NULL); // Create a map from nodes to subfaces. makesubfacemap(idx2facelist, facesperverlist); // Loop over the set of subfaces, setup the connection between subfaces. subfaces->traversalinit(); subloop.sh = shellfacetraverse(subfaces); while (subloop.sh != (shellface *) NULL) { for (i = 0; i < 3; i++) { spivot(subloop, neighsh); if (neighsh.sh == dummysh) { // This side is 'empty', operate on it. torg = sorg(subloop); tdest = sdest(subloop); tapex = sapex(subloop); neighshlist->append(&subloop); iorg = pointmark(torg) - in->firstnumber; // Search its neighbor in the adjacent list of torg. for (j = idx2facelist[iorg]; j < idx2facelist[iorg + 1]; j++) { neighsh.sh = facesperverlist[j]; if (neighsh.sh == subloop.sh) continue; neighsh.shver = 0; if (isfacehasedge(&neighsh, torg, tdest)) { findedge(&neighsh, torg, tdest); // Insert 'neighsh' into 'neighshlist'. if (neighshlist->len() < 2) { neighshlist->append(&neighsh); } else { for (index = 0; index < neighshlist->len() - 1; index++) { sface1 = * (face *)(* neighshlist)[index]; sface2 = * (face *)(* neighshlist)[index + 1]; da1 = facedihedral(torg, tdest, sapex(sface1), sapex(neighsh)); da2 = facedihedral(torg, tdest, sapex(sface1), sapex(sface2)); if (da1 < da2) { break; // Insert it after index. } } neighshlist->insert(index + 1, &neighsh); } } } // Bond the subfaces in 'neighshlist'. if (neighshlist->len() > 1) { neighsh = * (face *)(* neighshlist)[0]; for (j = 1; j <= neighshlist->len(); j++) { if (j < neighshlist->len()) { neineighsh = * (face *)(* neighshlist)[j]; } else { neineighsh = * (face *)(* neighshlist)[0]; } sbond1(neighsh, neineighsh); neighsh = neineighsh; } } else { // No neighbor subface be found, bond 'subloop' to itself. sdissolve(subloop); // sbond(subloop, subloop); } neighshlist->clear(); } senextself(subloop); } subloop.sh = shellfacetraverse(subfaces); } // Segments will be introudced. Each segment has a unique marker (1-based). marker = 1; subfaces->traversalinit(); subloop.sh = shellfacetraverse(subfaces); while (subloop.sh != (shellface *) NULL) { for (i = 0; i < 3; i++) { sspivot(subloop, subseg); if (subseg.sh == dummysh) { // This side has no subsegment bonded, check it. torg = sorg(subloop); tdest = sdest(subloop); tapex = sapex(subloop); spivot(subloop, neighsh); spivot(neighsh, neineighsh); insertsegflag = false; if (subloop.sh == neighsh.sh || subloop.sh != neineighsh.sh) { // This side is either self-bonded or more than two subfaces, // insert a subsegment at this side. insertsegflag = true; } else { // Only two subfaces case. #ifdef SELF_CHECK assert(subloop.sh != neighsh.sh); #endif napex = sapex(neighsh); sign = orient3d(torg, tdest, tapex, napex); if (iscoplanar(torg, tdest, tapex, napex, sign, b->epsilon)) { // Although they are coplanar, we still need to check if they // have the same boundary marker. insertsegflag = (shellmark(subloop) != shellmark(neighsh)); } else { // Non-coplanar. insertsegflag = true; } } if (insertsegflag) { // Create a subsegment at this side. makeshellface(subsegs, &subseg); setsorg(subseg, torg); setsdest(subseg, tdest); // The two vertices have been marked as FREESUBVERTEX. Now mark // them as NACUTEVERTEX. setpointtype(torg, NACUTEVERTEX); setpointtype(tdest, NACUTEVERTEX); setshellmark(subseg, marker); marker++; // Bond all subfaces to this subsegment. neighsh = subloop; do { ssbond(neighsh, subseg); spivotself(neighsh); if (neighsh.sh == dummysh) { break; // Only one facet case. } } while (neighsh.sh != subloop.sh); } } senextself(subloop); } subloop.sh = shellfacetraverse(subfaces); } // Remember the number of input segments. insegments = subsegs->items; // Find the acute vertices and set them be type ACUTEVERTEX. // Indentify facets and set the facet marker (1-based) for subfaces. markerlist = new list(sizeof(int), NULL, 256); subfaces->traversalinit(); subloop.sh = shellfacetraverse(subfaces); while (subloop.sh != (shellface *) NULL) { // Only operate on uninfected subface, after operating, infect it. if (!sinfected(subloop)) { // A new facet is found. marker = shellmark(subloop); markerlist->append(&marker); facetidx = markerlist->len(); // 'facetidx' starts from 1. setshellmark(subloop, facetidx); sinfect(subloop); neighshlist->append(&subloop); // Find out all subfaces of this facet (bounded by subsegments). for (i = 0; i < neighshlist->len(); i++) { neighsh = * (face *) (* neighshlist)[i]; for (j = 0; j < 3; j++) { sspivot(neighsh, subseg); if (subseg.sh == dummysh) { spivot(neighsh, neineighsh); if (!sinfected(neineighsh)) { // 'neineighsh' is in the same facet as 'subloop'. #ifdef SELF_CHECK assert(shellmark(neineighsh) == marker); #endif setshellmark(neineighsh, facetidx); sinfect(neineighsh); neighshlist->append(&neineighsh); } } senextself(neighsh); } } neighshlist->clear(); } subloop.sh = shellfacetraverse(subfaces); } // Uninfect all subfaces. subfaces->traversalinit(); subloop.sh = shellfacetraverse(subfaces); while (subloop.sh != (shellface *) NULL) { #ifdef SELF_CHECK assert(sinfected(subloop)); #endif suninfect(subloop); subloop.sh = shellfacetraverse(subfaces); } // Save the facet markers in 'in->facetmarkerlist'. in->numberoffacets = markerlist->len(); in->facetmarkerlist = new int[in->numberoffacets]; for (i = 0; i < in->numberoffacets; i++) { marker = * (int *) (* markerlist)[i]; in->facetmarkerlist[i] = marker; } // Initialize the 'facetabovepointlist'. facetabovepointarray = new point[in->numberoffacets + 1]; for (i = 0; i < in->numberoffacets + 1; i++) { facetabovepointarray[i] = (point) NULL; } // The mesh contains boundary now. checksubfaces = 1; // The mesh is nonconvex now. nonconvex = 1; /*// Is there periodic boundary confitions? if (checkpbcs) { tetgenio::pbcgroup *pg; pbcdata *pd; // Initialize the global array 'subpbcgrouptable'. createsubpbcgrouptable(); // Loop for each pbcgroup i. for (i = 0; i < in->numberofpbcgroups; i++) { pg = &(in->pbcgrouplist[i]); pd = &(subpbcgrouptable[i]); // Find all subfaces of pd, set each subface's group id be i. for (j = 0; j < 2; j++) { subfaces->traversalinit(); subloop.sh = shellfacetraverse(subfaces); while (subloop.sh != (shellface *) NULL) { facetidx = shellmark(subloop); marker = in->facetmarkerlist[facetidx - 1]; if (marker == pd->fmark[j]) { setshellpbcgroup(subloop, i); pd->ss[j] = subloop; } subloop.sh = shellfacetraverse(subfaces); } } if (pg->pointpairlist != (int *) NULL) { // Set the connections between pbc point pairs. for (j = 0; j < pg->numberofpointpairs; j++) { iorg = pg->pointpairlist[j * 2] - in->firstnumber; idest = pg->pointpairlist[j * 2 + 1] - in->firstnumber; torg = idx2verlist[iorg]; tdest = idx2verlist[idest]; setpoint2pbcpt(torg, tdest); setpoint2pbcpt(tdest, torg); } } } // Create the global array 'segpbcgrouptable'. createsegpbcgrouptable(); }*/ delete markerlist; delete neighshlist; delete [] worklist; delete [] idx2tetlist; delete [] tetsperverlist; delete [] idx2facelist; delete [] facesperverlist; delete [] idx2verlist; return hullsize; } /////////////////////////////////////////////////////////////////////////////// // // // insertconstrainedpoints() Insert a list of constrained points. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::insertconstrainedpoints(tetgenio *addio) { queue *flipqueue; triface searchtet; face checksh, checkseg; point newpoint; enum locateresult loc; REAL *attr; bool insertflag; int covertices, outvertices; int index; int i, j; if (!b->quiet) { printf("Insert additional points into mesh.\n"); } // Initialize 'flipqueue'. flipqueue = new queue(sizeof(badface)); recenttet.tet = dummytet; covertices = outvertices = 0; index = 0; for (i = 0; i < addio->numberofpoints; i++) { // Create a newpoint. makepoint(&newpoint); newpoint[0] = addio->pointlist[index++]; newpoint[1] = addio->pointlist[index++]; newpoint[2] = addio->pointlist[index++]; // Read the add point attributes if current points have attributes. if ((addio->numberofpointattributes > 0) && (in->numberofpointattributes > 0)) { attr = addio->pointattributelist + addio->numberofpointattributes * i; for (j = 0; j < in->numberofpointattributes; j++) { if (j < addio->numberofpointattributes) { newpoint[3 + j] = attr[j]; } } } // Find the location of the inserted point. searchtet = recenttet; loc = locate(newpoint, &searchtet); if (loc != ONVERTEX) { loc = adjustlocate(newpoint, &searchtet, loc, b->epsilon2); } if (loc == OUTSIDE) { loc = hullwalk(newpoint, &searchtet); if (loc == OUTSIDE) { // Perform a brute-force search. tetrahedrons->traversalinit(); searchtet.tet = tetrahedrontraverse(); while (searchtet.tet != (tetrahedron *) NULL) { loc = adjustlocate(newpoint, &searchtet, OUTSIDE, b->epsilon2); if (loc != OUTSIDE) break; searchtet.tet = tetrahedrontraverse(); } } } // Insert the point if it not lies outside or on a vertex. insertflag = true; switch (loc) { case INTETRAHEDRON: setpointtype(newpoint, FREEVOLVERTEX); splittetrahedron(newpoint, &searchtet, flipqueue); break; case ONFACE: tspivot(searchtet, checksh); if (checksh.sh != dummysh) { // It is a boundary face. Don't insert it if -Y option is used. if (b->nobisect) { insertflag = false; } else { setpointtype(newpoint, FREESUBVERTEX); setpoint2sh(newpoint, sencode(checksh)); } } else { setpointtype(newpoint, FREEVOLVERTEX); } if (insertflag) { splittetface(newpoint, &searchtet, flipqueue); } break; case ENCSEGMENT: case ONEDGE: tsspivot(&searchtet, &checkseg); if (checkseg.sh != dummysh) { if (b->nobisect) { insertflag = false; } else { setpointtype(newpoint, FREESEGVERTEX); setpoint2seg(newpoint, sencode(checkseg)); } } else { tspivot(searchtet, checksh); if (checksh.sh != dummysh) { if (b->nobisect) { insertflag = false; } else { setpointtype(newpoint, FREESUBVERTEX); setpoint2sh(newpoint, sencode(checksh)); } } else { setpointtype(newpoint, FREEVOLVERTEX); } } if (insertflag) { splittetedge(newpoint, &searchtet, flipqueue); } break; case ONVERTEX: insertflag = false; covertices++; break; case OUTSIDE: insertflag = false; outvertices++; break; } // Remember the tetrahedron for next point searching. recenttet = searchtet; if (!insertflag) { pointdealloc(newpoint); } else { lawson3d(flipqueue); } } if (b->verbose) { if (covertices > 0) { printf(" %d constrained points already exist.\n", covertices); } if (outvertices > 0) { printf(" %d constrained points lie outside the mesh.\n", outvertices); } printf(" %d constrained points have been inserted.\n", addio->numberofpoints - covertices - outvertices); } delete flipqueue; } /////////////////////////////////////////////////////////////////////////////// // // // p1interpolatebgm() Set pt size by p^1 interpolation in background mesh.// // // // On input, 'bgmtet' is a suggesting tet in background mesh for searching // // 'pt'. It returns the tet containing 'pt'. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::p1interpolatebgm(point pt, triface* bgmtet, long *scount) { point bgmpt[4]; enum locateresult loc; REAL vol, volpt[4], weights[4]; int i; loc = bgm->preciselocate(pt, bgmtet, bgm->tetrahedrons->items); if (loc == OUTSIDE) { loc = bgm->hullwalk(pt, bgmtet); if (loc == OUTSIDE) { // Perform a brute-force search. if (!b->quiet && b->verbose) { printf("Warning: Global point location.\n"); } if (scount) (*scount)++; bgm->tetrahedrons->traversalinit(); // in bgm bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm while (bgmtet->tet != (tetrahedron *) NULL) { loc = bgm->adjustlocate(pt, bgmtet, OUTSIDE, b->epsilon); if (loc != OUTSIDE) break; bgmtet->tet = bgm->tetrahedrontraverse(); // in bgm } } } if (loc != OUTSIDE) { // Let p remember t. setpoint2bgmtet(pt, encode(*bgmtet)); // in m // get the corners of t. for (i = 0; i < 4; i++) bgmpt[i] = (point) bgmtet->tet[4 + i]; // Calculate the weighted coordinates of p in t. vol = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], bgmpt[3]); volpt[0] = orient3d(pt, bgmpt[1], bgmpt[2], bgmpt[3]); volpt[1] = orient3d(bgmpt[0], pt, bgmpt[2], bgmpt[3]); volpt[2] = orient3d(bgmpt[0], bgmpt[1], pt, bgmpt[3]); volpt[3] = orient3d(bgmpt[0], bgmpt[1], bgmpt[2], pt); for (i = 0; i < 4; i++) weights[i] = fabs(volpt[i] / vol); // Interpolate the solution for p. for (i = 0; i < bgm->in->numberofpointmtrs; i++) { pt[pointmtrindex + i] = weights[0] * bgmpt[0][bgm->pointmtrindex + i] + weights[1] * bgmpt[1][bgm->pointmtrindex + i] + weights[2] * bgmpt[2][bgm->pointmtrindex + i] + weights[3] * bgmpt[3][bgm->pointmtrindex + i]; } } else { setpoint2bgmtet(pt, (tetrahedron) NULL); // in m } return loc != OUTSIDE; } /////////////////////////////////////////////////////////////////////////////// // // // interpolatesizemap() Interpolate the point sizes in the given size map.// // // // The size map is specified on each node of the background mesh. The points // // of current mesh get their sizes by interpolating. // // // // This function operation on two meshes simultaneously, the current mesh m, // // and the background mesh bgm. After this function, each point p in m will // // have a pointer to a tet of bgm. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::interpolatesizemap() { list *adjtetlist; triface tetloop, neightet, bgmtet; point searchpt; long scount; int *worklist; int sepcount; int i; if (b->verbose) { printf(" Interpolating size map.\n"); } worklist = new int[points->items + 1]; for (i = 0; i < points->items + 1; i++) worklist[i] = 0; sepcount = 0; scount = 0l; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { if (!infected(tetloop)) { // Find a new subdomain. adjtetlist = new list(sizeof(triface), NULL, 1024); infect(tetloop); // Search the four corners in background mesh. for (i = 0; i < 4; i++) { searchpt = (point) tetloop.tet[4 + i]; // Mark the point for avoiding multiple searchings. // assert(worklist[pointmark(searchpt)] == 0); worklist[pointmark(searchpt)] = 1; // Does it contain a pointer to bgm tet? bgm->decode(point2bgmtet(searchpt), bgmtet); if (bgm->isdead(&bgmtet)) { bgmtet = bgm->recenttet; } if (p1interpolatebgm(searchpt, &bgmtet, &scount)) { bgm->recenttet = bgmtet; } } // for (i = 0; i < 4; i++) // Collect all tets in this region. adjtetlist->append(&tetloop); // Collect the tets in the subdomain. for (i = 0; i < adjtetlist->len(); i++) { tetloop = * (triface *)(* adjtetlist)[i]; for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { sym(tetloop, neightet); if ((neightet.tet != dummytet) && !infected(neightet)) { // Only need to search for the opposite point. searchpt = oppo(neightet); if (worklist[pointmark(searchpt)] == 0) { worklist[pointmark(searchpt)] = 1; decode(point2bgmtet(searchpt), bgmtet); if (bgm->isdead(&bgmtet)) { bgmtet = bgm->recenttet; } if (p1interpolatebgm(searchpt, &bgmtet, &scount)) { bgm->recenttet = bgmtet; } } infect(neightet); adjtetlist->append(&neightet); } } } // Increase the number of separated domains. sepcount++; delete adjtetlist; } // if (!infect()) tetloop.tet = tetrahedrontraverse(); } // Unmark all tets. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { assert(infected(tetloop)); uninfect(tetloop); tetloop.tet = tetrahedrontraverse(); } delete [] worklist; #ifdef SELF_CHECK if (b->verbose && scount > 0l) { printf(" %ld brute-force searches.\n", scount); } if (b->verbose && sepcount > 0) { printf(" %d separate domains.\n", sepcount); } #endif } /////////////////////////////////////////////////////////////////////////////// // // // duplicatebgmesh() Duplicate current mesh to background mesh. // // // // Current mesh 'this' is copied into 'this->bgm'.Both meshes share the same // // input tetgenio object, 'this->in', same tetgenbehavior object 'this->b'. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::duplicatebgmesh() { triface tetloop, btetloop; triface symtet, bsymtet; face bhullsh, bneighsh; point *idx2bplist, *tetptbaklist; point ploop, bploop; int idx, i; if (!b->quiet) { printf("Duplicating background mesh.\n"); } // The background mesh itself has no background mesh. // assert(bgm->bgm == (tetgenmesh *) NULL); // The space for metric tensor should be allocated. // assert(bgm->sizeoftensor > 0); // Copy point list. idx2bplist = new point[points->items + 1]; idx = in->firstnumber; points->traversalinit(); ploop = pointtraverse(); while (ploop != (point) NULL) { bgm->makepoint(&bploop); // Copy coordinates, attributes. for (i = 0; i < 3 + in->numberofpointattributes; i++) { bploop[i] = ploop[i]; } // Transfer the metric tensor. for (i = 0; i < bgm->sizeoftensor; i++) { bploop[bgm->pointmtrindex + i] = ploop[pointmtrindex + i]; // Metric tensor should have a positive value. if (bploop[bgm->pointmtrindex + i] <= 0.0) { printf("Error: Point %d has non-positive size %g (-m option).\n", bgm->pointmark(bploop), bploop[bgm->pointmtrindex + i]); terminatetetgen(3); } } // Remember the point for searching. idx2bplist[idx++] = bploop; ploop = pointtraverse(); } // Copy tetrahedra list. tetptbaklist = new point[tetrahedrons->items + 1]; idx = in->firstnumber; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { bgm->maketetrahedron(&btetloop); // Set the four corners. for (i = 0; i < 4; i++) { ploop = (point) tetloop.tet[4 + i]; bploop = idx2bplist[pointmark(ploop)]; btetloop.tet[4 + i] = (tetrahedron) bploop; } // Remember the tet for setting neighbor connections. tetptbaklist[idx++] = (point) tetloop.tet[4]; tetloop.tet[4] = (tetrahedron) btetloop.tet; tetloop.tet = tetrahedrontraverse(); } // Set the connections between background tetrahedra. Create background // hull subfaces. Create the map of point-to-bgmtet. idx = in->firstnumber; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Get the corresponding background tet. btetloop.tet = (tetrahedron *) tetloop.tet[4]; // Set the four neighbors. for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { btetloop.loc = tetloop.loc; sym(tetloop, symtet); if ((symtet.tet != dummytet) && (symtet.tet > tetloop.tet)) { // Operate on the un-connected interior face. bsymtet.tet = (tetrahedron *) symtet.tet[4]; // The saved bgm tet. bsymtet.loc = symtet.loc; bgm->bond(btetloop, bsymtet); } else if (symtet.tet == dummytet) { // Create a subface in background mesh. bgm->makeshellface(bgm->subfaces, &bhullsh); bgm->adjustedgering(btetloop, CCW); // face to inside. bgm->setsorg(bhullsh, bgm->org(btetloop)); bgm->setsdest(bhullsh, bgm->dest(btetloop)); bgm->setsapex(bhullsh, bgm->apex(btetloop)); bgm->tsbond(btetloop, bhullsh); // Remember a hull face for point location. bgm->dummytet[0] = bgm->encode(btetloop); } } // Restore the backup tet point. tetloop.tet[4] = (tetrahedron) tetptbaklist[idx++]; // Make the point-to-bgmtet map for size interpolation. btetloop.loc = 0; for (i = 0; i < 4; i++) { ploop = (point) tetloop.tet[4 + i]; setpoint2bgmtet(ploop, bgm->encode(btetloop)); } // Go to the next tet, btet. tetloop.tet = tetrahedrontraverse(); } // Connect bgm hull subfaces. Note: all hull subfaces form a 2-manifold. bgm->subfaces->traversalinit(); bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces); while (bhullsh.sh != (shellface *) NULL) { bhullsh.shver = 0; bgm->stpivot(bhullsh, btetloop); assert(btetloop.tet != bgm->dummytet); bgm->adjustedgering(btetloop, CCW); for (i = 0; i < 3; i++) { bgm->spivot(bhullsh, bneighsh); if (bneighsh.sh == bgm->dummysh) { // This side is open, operate on it. bsymtet = btetloop; while (bgm->fnextself(bsymtet)); bgm->tspivot(bsymtet, bneighsh); bgm->findedge(&bneighsh, bgm->sdest(bhullsh), bgm->sorg(bhullsh)); bgm->sbond(bhullsh, bneighsh); } bgm->enextself(btetloop); bgm->senextself(bhullsh); } bhullsh.sh = bgm->shellfacetraverse(bgm->subfaces); } delete [] tetptbaklist; delete [] idx2bplist; } //// //// //// //// //// reconstruct_cxx ////////////////////////////////////////////////////////// //// refine_cxx /////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // marksharpsegments() Mark sharp segments. // // // // A segment s is called sharp if it is in one of the two cases: // // (1) There is a segment s' intersecting with s. The internal angle (*) // // between s and s' is acute. // // (2) There are two facets f1 and f2 intersecting at s. The internal // // dihedral angle (*) between f1 and f2 is acute. // // This routine finds the sharp segments and marked them as type SHARP. // // // // The minimum angle between segments (minfaceang) and the minimum dihedral // // angle between facets (minfacetdihed) are calulcated. // // // // (*) The internal angle (or dihedral) bewteen two features means the angle // // inside the mesh domain. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::marksharpsegments(REAL sharpangle) { triface adjtet; face startsh, spinsh, neighsh; face segloop, prevseg, nextseg; point eorg, edest; REAL ang, smallang; bool issharp; int sharpsegcount; if (b->verbose > 0) { printf(" Marking sharp segments.\n"); } smallang = sharpangle * PI / 180.; sharpsegcount = 0; eorg = edest = (point) NULL; // To avoid compiler warnings. // A segment s may have been split into many subsegments. Operate the one // which contains the origin of s. Then mark the rest of subsegments. subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { segloop.shver = 0; senext2(segloop, prevseg); spivotself(prevseg); if (prevseg.sh == dummysh) { // Operate on this seg s. issharp = false; spivot(segloop, startsh); if (startsh.sh != dummysh) { // First check if two facets form an acute dihedral angle at s. eorg = sorg(segloop); edest = sdest(segloop); spinsh = startsh; do { if (sorg(spinsh) != eorg) { sesymself(spinsh); } // Only do test when the spinsh is faceing inward. stpivot(spinsh, adjtet); if (adjtet.tet != dummytet) { // Get the subface on the adjacent facet. spivot(spinsh, neighsh); // Do not calculate if it is self-bonded. if ((neighsh.sh != dummysh) && (neighsh.sh != spinsh.sh)) { // Calculate the dihedral angle between the two subfaces. ang = facedihedral(eorg, edest, sapex(spinsh), sapex(neighsh)); // Only do check if a sharp angle has not been found. if (!issharp) issharp = (ang < smallang); // Remember the smallest facet dihedral angle. minfacetdihed = minfacetdihed < ang ? minfacetdihed : ang; } } // Go to the next facet. spivotself(spinsh); if (spinsh.sh == dummysh) break; // A single subface case. } while (spinsh.sh != startsh.sh); // if (!issharp) { // Second check if s forms an acute angle with another seg. spinsh = startsh; do { if (sorg(spinsh) != eorg) { sesymself(spinsh); } // Calculate the angle between s and s' of this facet. neighsh = spinsh; // Rotate edges around 'eorg' until meeting another seg s'. Such // seg (s') must exist since the facet is segment-bounded. // The sum of the angles of faces at 'eorg' gives the internal // angle between the two segments. ang = 0.0; do { ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL); senext2self(neighsh); sspivot(neighsh, nextseg); if (nextseg.sh != dummysh) break; // Go to the next coplanar subface. spivotself(neighsh); assert(neighsh.sh != dummysh); if (sorg(neighsh) != eorg) { sesymself(neighsh); } } while (true); // Only do check if a sharp angle has not been found. if (!issharp) issharp = (ang < smallang); // Remember the smallest input face angle. minfaceang = minfaceang < ang ? minfaceang : ang; // Go to the next facet. spivotself(spinsh); if (spinsh.sh == dummysh) break; // A single subface case. } while (spinsh.sh != startsh.sh); // } } if (issharp) { setshelltype(segloop, SHARP); // Set the type for all subsegments at forwards. edest = sdest(segloop); senext(segloop, nextseg); spivotself(nextseg); while (nextseg.sh != dummysh) { setshelltype(nextseg, SHARP); // Adjust the direction of nextseg. nextseg.shver = 0; if (sorg(nextseg) != edest) { sesymself(nextseg); } assert(sorg(nextseg) == edest); edest = sdest(nextseg); // Go the next connected subsegment at edest. senextself(nextseg); spivotself(nextseg); } sharpsegcount++; } } segloop.sh = shellfacetraverse(subsegs); } // So far we have marked all segments which have an acute dihedral angle // or whose ORIGINs have an acute angle. In the un-marked subsegments, // there are possible ones whose DESTINATIONs have an acute angle. subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { // Only operate if s is non-sharp and contains the dest. segloop.shver = 0; senext(segloop, nextseg); spivotself(nextseg); // if ((nextseg.sh == dummysh) && (shelltype(segloop) != SHARP)) { if (nextseg.sh == dummysh) { // issharp = false; issharp = (shelltype(segloop) == SHARP); spivot(segloop, startsh); if (startsh.sh != dummysh) { // Check if s forms an acute angle with another seg. eorg = sdest(segloop); spinsh = startsh; do { if (sorg(spinsh) != eorg) { sesymself(spinsh); } // Calculate the angle between s and s' of this facet. neighsh = spinsh; ang = 0.0; do { ang += interiorangle(eorg, sdest(neighsh), sapex(neighsh), NULL); senext2self(neighsh); sspivot(neighsh, nextseg); if (nextseg.sh != dummysh) break; // Go to the next coplanar subface. spivotself(neighsh); assert(neighsh.sh != dummysh); if (sorg(neighsh) != eorg) { sesymself(neighsh); } } while (true); // Only do check if a sharp angle has not been found. if (!issharp) issharp = (ang < smallang); // Remember the smallest input face angle. minfaceang = minfaceang < ang ? minfaceang : ang; // Go to the next facet. spivotself(spinsh); if (spinsh.sh == dummysh) break; // A single subface case. } while (spinsh.sh != startsh.sh); } if (issharp) { setshelltype(segloop, SHARP); // Set the type for all subsegments at backwards. eorg = sorg(segloop); senext2(segloop, prevseg); spivotself(prevseg); while (prevseg.sh != dummysh) { setshelltype(prevseg, SHARP); // Adjust the direction of prevseg. prevseg.shver = 0; if (sdest(prevseg) != eorg) { sesymself(prevseg); } assert(sdest(prevseg) == eorg); eorg = sorg(prevseg); // Go to the next connected subsegment at eorg. senext2self(prevseg); spivotself(prevseg); } sharpsegcount++; } } segloop.sh = shellfacetraverse(subsegs); } if ((b->verbose > 0) && (sharpsegcount > 0)) { printf(" %d sharp segments.\n", sharpsegcount); } } /////////////////////////////////////////////////////////////////////////////// // // // decidefeaturepointsizes() Decide the sizes for all feature points. // // // // A feature point is a point on a sharp segment. Every feature point p will // // be assigned a positive size which is the radius of the protecting ball. // // // // The size of a feature point may be specified by one of the following ways:// // (1) directly specifying on an input vertex (by using .mtr file); // // (2) imposing a fixed maximal volume constraint ('-a__' option); // // (3) imposing a maximal volume constraint in a region ('-a' option); // // (4) imposing a maximal area constraint on a facet (in .var file); // // (5) imposing a maximal length constraint on a segment (in .var file); // // (6) combining (1) - (5). // // (7) automatically deriving a size if none of (1) - (6) is available. // // In case (7),the size of p is set to be the smallest edge length among all // // edges connecting at p. The final size of p is the minimum of (1) - (7). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::decidefeaturepointsizes() { list *tetlist, *verlist; shellface **segsperverlist; triface starttet; face shloop; face checkseg, prevseg, nextseg, testseg; point ploop, adjpt, e1, e2; REAL lfs_0, len, vol, maxlen, varlen; bool isfeature; int *idx2seglist; int featurecount; int idx, i, j; if (b->verbose > 0) { printf(" Deciding feature-point sizes.\n"); } // Constructing a map from vertices to segments. makesegmentmap(idx2seglist, segsperverlist); // Initialize working lists. tetlist = new list(sizeof(triface), NULL, 256); verlist = new list(sizeof(point *), NULL, 256); if (b->fixedvolume) { // A fixed volume constraint is imposed. This gives an upper bound of // the maximal radius of the protect ball of a vertex. maxlen = pow(6.0 * b->maxvolume, 1.0/3.0); } // First only assign a size of p if p is not a Steiner point. The size of // a Steiner point will be interpolated later from the endpoints of the // segment on which it lies. featurecount = 0; points->traversalinit(); ploop = pointtraverse(); while (ploop != (point) NULL) { if (pointtype(ploop) != FREESEGVERTEX) { // Is p a feature point? isfeature = false; idx = pointmark(ploop) - in->firstnumber; for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) { checkseg.sh = segsperverlist[i]; isfeature = (shelltype(checkseg) == SHARP); } // Decide the size of p if it is on a sharp segment. if (isfeature) { // Find a tet containing p; sstpivot(&checkseg, &starttet); // Form star(p). tetlist->append(&starttet); formstarpolyhedron(ploop, tetlist, verlist, true); // Decide the size for p if no input size is given on input. if (ploop[pointmtrindex] == 0.0) { // Calculate lfs_0(p). lfs_0 = longest; for (i = 0; i < verlist->len(); i++) { adjpt = * (point *)(* verlist)[i]; if (pointtype(adjpt) == FREESEGVERTEX) { // A Steiner point q. Find the seg it lies on. sdecode(point2seg(adjpt), checkseg); assert(checkseg.sh != dummysh); checkseg.shver = 0; // Find the origin of this seg. prevseg = checkseg; e1 = sorg(prevseg); do { senext2(prevseg, testseg); spivotself(testseg); if (testseg.sh == dummysh) break; // Go to the previous subseg. prevseg = testseg; // Adjust the direction of the previous subsegment. prevseg.shver = 0; if (sdest(prevseg) != e1) { sesymself(prevseg); } assert(sdest(prevseg) == e1); e1 = sorg(prevseg); } while (true); // Find the dest of this seg. nextseg = checkseg; e2 = sdest(nextseg); do { senext(nextseg, testseg); spivotself(testseg); if (testseg.sh == dummysh) break; // Go to the next subseg. nextseg = testseg; // Adjust the direction of the nextseg. nextseg.shver = 0; if (sorg(nextseg) != e2) { sesymself(nextseg); } assert(sorg(nextseg) == e2); e2 = sdest(nextseg); } while (true); // e1 = sorg(prevseg); // e2 = sdest(nextseg); // Check if p is the origin or the dest of this seg. if (ploop == e1) { // Set q to be the dest of this seg. adjpt = e2; } else if (ploop == e2) { // Set q to be the org of this seg. adjpt = e1; } } len = distance(ploop, adjpt); if (lfs_0 > len) lfs_0 = len; } ploop[pointmtrindex] = lfs_0; } if (b->fixedvolume) { // A fixed volume constraint is imposed. Adjust H(p) <= maxlen. if (ploop[pointmtrindex] > maxlen) { ploop[pointmtrindex] = maxlen; } } if (b->varvolume) { // Variant volume constraints are imposed. Adjust H(p) <= varlen. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; vol = volumebound(starttet.tet); if (vol > 0.0) { varlen = pow(6 * vol, 1.0/3.0); if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } } } } // Clear working lists. tetlist->clear(); verlist->clear(); featurecount++; } else { // NO feature point, set the size of p be zero. ploop[pointmtrindex] = 0.0; } } // if (pointtype(ploop) != FREESEGVERTEX) { ploop = pointtraverse(); } if (b->verbose > 1) { printf(" %d feature points.\n", featurecount); } if (!b->refine) { // Second only assign sizes for all Steiner points. A Steiner point p // inserted on a sharp segment s is assigned a size by interpolating // the sizes of the original endpoints of s. featurecount = 0; points->traversalinit(); ploop = pointtraverse(); while (ploop != (point) NULL) { if (pointtype(ploop) == FREESEGVERTEX) { if (ploop[pointmtrindex] == 0.0) { sdecode(point2seg(ploop), checkseg); assert(checkseg.sh != dummysh); if (shelltype(checkseg) == SHARP) { checkseg.shver = 0; // Find the origin of this seg. prevseg = checkseg; e1 = sorg(prevseg); do { senext2(prevseg, testseg); spivotself(testseg); if (testseg.sh == dummysh) break; prevseg = testseg; // Go the previous subseg. // Adjust the direction of this subsegmnt. prevseg.shver = 0; if (sdest(prevseg) != e1) { sesymself(prevseg); } assert(sdest(prevseg) == e1); e1 = sorg(prevseg); } while (true); // Find the dest of this seg. nextseg = checkseg; e2 = sdest(nextseg); do { senext(nextseg, testseg); spivotself(testseg); if (testseg.sh == dummysh) break; nextseg = testseg; // Go the next subseg. // Adjust the direction of this subsegment. nextseg.shver = 0; if (sorg(nextseg) != e2) { sesymself(nextseg); } assert(sorg(nextseg) == e2); e2 = sdest(nextseg); } while (true); // e1 = sorg(prevseg); // e2 = sdest(nextseg); len = distance(e1, e2); lfs_0 = distance(e1, ploop); // The following assert() happens when -Y option is used. if (b->nobisect == 0) { assert(lfs_0 < len); } ploop[pointmtrindex] = e1[pointmtrindex] + (lfs_0 / len) * (e2[pointmtrindex] - e1[pointmtrindex]); featurecount++; } else { // NO feature point, set the size of p be zero. ploop[pointmtrindex] = 0.0; } // if (shelltype(checkseg) == SHARP) } // if (ploop[pointmtrindex] == 0.0) } // if (pointtype(ploop) != FREESEGVERTEX) ploop = pointtraverse(); } if ((b->verbose > 1) && (featurecount > 0)) { printf(" %d Steiner feature points.\n", featurecount); } } if (varconstraint) { // A .var file exists. Adjust feature sizes. if (in->facetconstraintlist) { // Have facet area constrains. subfaces->traversalinit(); shloop.sh = shellfacetraverse(subfaces); while (shloop.sh != (shellface *) NULL) { varlen = areabound(shloop); if (varlen > 0.0) { // Check if the three corners are feature points. varlen = sqrt(varlen); for (j = 0; j < 3; j++) { ploop = (point) shloop.sh[3 + j]; isfeature = false; idx = pointmark(ploop) - in->firstnumber; for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) { checkseg.sh = segsperverlist[i]; isfeature = (shelltype(checkseg) == SHARP); } if (isfeature) { assert(ploop[pointmtrindex] > 0.0); if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } } } // for (j = 0; j < 3; j++) } shloop.sh = shellfacetraverse(subfaces); } } if (in->segmentconstraintlist) { // Have facet area constrains. subsegs->traversalinit(); shloop.sh = shellfacetraverse(subsegs); while (shloop.sh != (shellface *) NULL) { varlen = areabound(shloop); if (varlen > 0.0) { // Check if the two endpoints are feature points. for (j = 0; j < 2; j++) { ploop = (point) shloop.sh[3 + j]; isfeature = false; idx = pointmark(ploop) - in->firstnumber; for (i = idx2seglist[idx]; i < idx2seglist[idx + 1] && !isfeature; i++) { checkseg.sh = segsperverlist[i]; isfeature = (shelltype(checkseg) == SHARP); } if (isfeature) { assert(ploop[pointmtrindex] > 0.0); if (ploop[pointmtrindex] > varlen) { ploop[pointmtrindex] = varlen; } } } // for (j = 0; j < 2; j++) } shloop.sh = shellfacetraverse(subsegs); } } } // if (varconstraint) delete [] segsperverlist; delete [] idx2seglist; delete tetlist; delete verlist; } /////////////////////////////////////////////////////////////////////////////// // // // enqueueencsub() Add an encroached subface into the queue. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::enqueueencsub(face* testsub, point encpt, int quenumber, REAL* cent) { badface *encsub; int i; if (!smarktested(*testsub)) { if (!shell2badface(*testsub)) { encsub = (badface *) badsubfaces->alloc(); encsub->ss = *testsub; encsub->forg = sorg(*testsub); encsub->fdest = sdest(*testsub); encsub->fapex = sapex(*testsub); encsub->foppo = (point) encpt; for (i = 0; i < 3; i++) encsub->cent[i] = cent[i]; encsub->nextitem = (badface *) NULL; // Set the pointer of 'encsubseg' into 'testsub'. It has two purposes: // (1) We can regonize it is encroached; (2) It is uniquely queued. setshell2badface(encsub->ss, encsub); // Add the subface to the end of a queue (quenumber = 2, high priority). *subquetail[quenumber] = encsub; // Maintain a pointer to the NULL pointer at the end of the queue. subquetail[quenumber] = &encsub->nextitem; if (b->verbose > 2) { printf(" Queuing subface (%d, %d, %d) [%d].\n", pointmark(encsub->forg), pointmark(encsub->fdest), pointmark(encsub->fapex), quenumber); } } } else { if (b->verbose > 2) { printf(" Ignore a encroached subface (%d, %d, %d).\n", pointmark(sorg(*testsub)), pointmark(sdest(*testsub)), pointmark(sapex(*testsub))); } } } /////////////////////////////////////////////////////////////////////////////// // // // dequeueencsub() Remove an enc-subface from the front of the queue. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::badface* tetgenmesh::dequeueencsub(int* pquenumber) { badface *result; int quenumber; // Look for a nonempty queue. for (quenumber = 2; quenumber >= 0; quenumber--) { result = subquefront[quenumber]; if (result != (badface *) NULL) { // Remove the badface from the queue. subquefront[quenumber] = result->nextitem; // Maintain a pointer to the NULL pointer at the end of the queue. if (subquefront[quenumber] == (badface *) NULL) { subquetail[quenumber] = &subquefront[quenumber]; } *pquenumber = quenumber; return result; } } return (badface *) NULL; } /////////////////////////////////////////////////////////////////////////////// // // // enqueuebadtet() Add a tetrahedron into the queue. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::enqueuebadtet(triface* testtet, REAL ratio2, REAL* cent) { badface *newbadtet; int queuenumber; int i; // Allocate space for the bad tetrahedron. newbadtet = (badface *) badtetrahedrons->alloc(); newbadtet->tt = *testtet; newbadtet->key = ratio2; if (cent != NULL) { for (i = 0; i < 3; i++) newbadtet->cent[i] = cent[i]; } else { for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0; } newbadtet->forg = org(*testtet); newbadtet->fdest = dest(*testtet); newbadtet->fapex = apex(*testtet); newbadtet->foppo = oppo(*testtet); newbadtet->nextitem = (badface *) NULL; // Determine the appropriate queue to put the bad tetrahedron into. if (ratio2 > b->goodratio) { // queuenumber = (int) ((ratio2 - b->goodratio) / 0.5); queuenumber = (int) (64.0 - 64.0 / ratio2); // 'queuenumber' may overflow (negative) caused by a very large ratio. if ((queuenumber > 63) || (queuenumber < 0)) { queuenumber = 63; } } else { // It's not a bad ratio; put the tet in the lowest-priority queue. queuenumber = 0; } // Are we inserting into an empty queue? if (tetquefront[queuenumber] == (badface *) NULL) { // Yes. Will this become the highest-priority queue? if (queuenumber > firstnonemptyq) { // Yes, this is the highest-priority queue. nextnonemptyq[queuenumber] = firstnonemptyq; firstnonemptyq = queuenumber; } else { // No. Find the queue with next higher priority. i = queuenumber + 1; while (tetquefront[i] == (badface *) NULL) { i++; } // Mark the newly nonempty queue as following a higher-priority queue. nextnonemptyq[queuenumber] = nextnonemptyq[i]; nextnonemptyq[i] = queuenumber; } // Put the bad tetrahedron at the beginning of the (empty) queue. tetquefront[queuenumber] = newbadtet; } else { // Add the bad tetrahedron to the end of an already nonempty queue. tetquetail[queuenumber]->nextitem = newbadtet; } // Maintain a pointer to the last tetrahedron of the queue. tetquetail[queuenumber] = newbadtet; if (b->verbose > 2) { printf(" Queueing bad tet: (%d, %d, %d, %d), ratio %g, qnum %d.\n", pointmark(newbadtet->forg), pointmark(newbadtet->fdest), pointmark(newbadtet->fapex), pointmark(newbadtet->foppo), sqrt(ratio2), queuenumber); } } /////////////////////////////////////////////////////////////////////////////// // // // dequeuebadtet() Remove a tetrahedron from the front of the queue. // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh::badface* tetgenmesh::topbadtetra() { // Keep a record of which queue was accessed in case dequeuebadtetra() // is called later. recentq = firstnonemptyq; // If no queues are nonempty, return NULL. if (firstnonemptyq < 0) { return (badface *) NULL; } else { // Return the first tetrahedron of the highest-priority queue. return tetquefront[firstnonemptyq]; } } void tetgenmesh::dequeuebadtet() { badface *deadbadtet; int i; // If queues were empty last time topbadtetra() was called, do nothing. if (recentq >= 0) { // Find the tetrahedron last returned by topbadtetra(). deadbadtet = tetquefront[recentq]; // Remove the tetrahedron from the queue. tetquefront[recentq] = deadbadtet->nextitem; // If this queue is now empty, update the list of nonempty queues. if (deadbadtet == tetquetail[recentq]) { // Was this the highest-priority queue? if (firstnonemptyq == recentq) { // Yes; find the queue with next lower priority. firstnonemptyq = nextnonemptyq[firstnonemptyq]; } else { // No; find the queue with next higher priority. i = recentq + 1; while (tetquefront[i] == (badface *) NULL) { i++; } nextnonemptyq[i] = nextnonemptyq[recentq]; } } // Return the bad tetrahedron to the pool. badfacedealloc(badtetrahedrons, deadbadtet); } } /////////////////////////////////////////////////////////////////////////////// // // // checkseg4encroach() Check a subsegment to see if it is encroached. // // // // A segment s is encroached if there is a vertex lies inside or on its dia- // // metral circumsphere, i.e., s faces an angle theta > 90 degrees. // // // // If 'testpt' (p) != NULL, only test if 'testseg' (s) is encroached by it, // // else, check all apexes of faces around s. Return TRUE if s is encroached. // // If and 'enqflag' is TRUE, add it into 'badsubsegs' if s is encroached. // // // // If 'prefpt' != NULL, it returns the reference point (defined in my paper) // // if it exists. This point is will be used to split s. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::checkseg4encroach(face* testseg, point testpt, point* prefpt, bool enqflag) { badface *encsubseg; triface starttet, spintet; point eorg, edest, eapex, encpt; REAL cent[3], radius, dist, diff; REAL maxradius; bool enq; int hitbdry; enq = false; eorg = sorg(*testseg); edest = sdest(*testseg); cent[0] = 0.5 * (eorg[0] + edest[0]); cent[1] = 0.5 * (eorg[1] + edest[1]); cent[2] = 0.5 * (eorg[2] + edest[2]); radius = distance(cent, eorg); if (varconstraint && (areabound(*testseg) > 0.0)) { enq = (2.0 * radius) > areabound(*testseg); } if (!enq) { maxradius = 0.0; if (testpt == (point) NULL) { // Check if it is encroached by traversing all faces containing it. sstpivot(testseg, &starttet); eapex = apex(starttet); spintet = starttet; hitbdry = 0; do { dist = distance(cent, apex(spintet)); diff = dist - radius; if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. if (diff <= 0.0) { // s is encroached. enq = true; if (prefpt != (point *) NULL) { // Find the reference point. encpt = apex(spintet); circumsphere(eorg, edest, encpt, NULL, NULL, &dist); if (dist > maxradius) { // Rememebr this point. *prefpt = encpt; maxradius = dist; } } else { break; } } if (!fnextself(spintet)) { hitbdry++; if (hitbdry < 2) { esym(starttet, spintet); if (!fnextself(spintet)) { hitbdry++; } } } } while (apex(spintet) != eapex && (hitbdry < 2)); } else { // Only check if 'testseg' is encroached by 'testpt'. dist = distance(cent, testpt); diff = dist - radius; if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. enq = (diff <= 0.0); } } if (enq && enqflag) { // This segment is encroached and should be repaired. if (!smarktested(*testseg)) { if (!shell2badface(*testseg)) { // Is it not queued yet? if (b->verbose > 2) { printf(" Queuing encroaching subsegment (%d, %d).\n", pointmark(eorg), pointmark(edest)); } encsubseg = (badface *) badsubsegs->alloc(); encsubseg->ss = *testseg; encsubseg->forg = eorg; encsubseg->fdest = edest; encsubseg->foppo = (point) NULL; // Not used. // Set the pointer of 'encsubseg' into 'testseg'. It has two purposes: // (1) We can regonize it is encroached; (2) It is uniquely queued. setshell2badface(encsubseg->ss, encsubseg); } } else { // This segment has been rejected for splitting. Do not queue it. if (b->verbose > 2) { printf(" Ignore a rejected encroaching subsegment (%d, %d).\n", pointmark(eorg), pointmark(edest)); } } } return enq; } /////////////////////////////////////////////////////////////////////////////// // // // checksub4encroach() Check a subface to see if it is encroached. // // // // A subface f is encroached if there is a vertex inside or on its diametral // // circumsphere. // // // // If 'testpt (p) != NULL', test if 'testsub' (f) is encroached by it, else, // // test if f is encroached by one of the two opposites of the adjacent tets. // // Return TRUE if f is encroached and queue it if 'enqflag' is set. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::checksub4encroach(face* testsub, point testpt, bool enqflag) { triface abuttet; point pa, pb, pc, encpt; REAL A[4][4], rhs[4], D; REAL cent[3], area; REAL radius, dist, diff; bool enq; int indx[4]; int quenumber; enq = false; radius = 0.0; encpt = (point) NULL; pa = sorg(*testsub); pb = sdest(*testsub); pc = sapex(*testsub); // Compute the coefficient matrix A (3x3). A[0][0] = pb[0] - pa[0]; A[0][1] = pb[1] - pa[1]; A[0][2] = pb[2] - pa[2]; // vector V1 (pa->pb) A[1][0] = pc[0] - pa[0]; A[1][1] = pc[1] - pa[1]; A[1][2] = pc[2] - pa[2]; // vector V2 (pa->pc) cross(A[0], A[1], A[2]); // vector V3 (V1 X V2) if (varconstraint && (areabound(*testsub) > 0.0)) { // Check if the subface has too big area. area = 0.5 * sqrt(dot(A[2], A[2])); enq = area > areabound(*testsub); if (enq) { quenumber = 2; // A queue of subfaces having too big area. } } // Compute the right hand side vector b (3x1). rhs[0] = 0.5 * dot(A[0], A[0]); rhs[1] = 0.5 * dot(A[1], A[1]); rhs[2] = 0.0; // Solve the 3 by 3 equations use LU decomposition with partial pivoting // and backward and forward substitute.. if (lu_decmp(A, 3, indx, &D, 0)) { lu_solve(A, 3, indx, rhs, 0); cent[0] = pa[0] + rhs[0]; cent[1] = pa[1] + rhs[1]; cent[2] = pa[2] + rhs[2]; radius = sqrt(rhs[0] * rhs[0] + rhs[1] * rhs[1] + rhs[2] * rhs[2]); } if (!enq) { // Check if the subface is encroached. if (testpt == (point) NULL) { stpivot(*testsub, abuttet); if (abuttet.tet != dummytet) { dist = distance(cent, oppo(abuttet)); diff = dist - radius; if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. enq = (diff <= 0.0); if (enq) encpt = oppo(abuttet); } if (!enq) { sesymself(*testsub); stpivot(*testsub, abuttet); if (abuttet.tet != dummytet) { dist = distance(cent, oppo(abuttet)); diff = dist - radius; if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. enq = (diff <= 0.0); if (enq) encpt = oppo(abuttet); } } } else { dist = distance(cent, testpt); diff = dist - radius; if (fabs(diff) / radius <= b->epsilon) diff = 0.0; // Rounding. enq = (diff <= 0.0); } if (enq) { quenumber = 0; // A queue of encroached subfaces. } } if (enq && enqflag) { enqueueencsub(testsub, encpt, quenumber, cent); } return enq; } /////////////////////////////////////////////////////////////////////////////// // // // checktet4badqual() Test a tetrahedron for quality measures. // // // // Tests a tetrahedron to see if it satisfies the minimum ratio condition // // and the maximum volume condition. Tetrahedra that aren't upto spec are // // added to the bad tetrahedron queue. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::checktet4badqual(triface* testtet, bool enqflag) { point pa, pb, pc, pd, pe1, pe2; REAL vda[3], vdb[3], vdc[3]; REAL vab[3], vbc[3], vca[3]; REAL N[4][3], A[4][4], rhs[4], D; REAL elen[6], circumcent[3]; REAL bicent[3], offcent[3]; REAL volume, L, cosd; REAL radius2, smlen2, ratio2; REAL dist, sdist, split; bool enq; int indx[4]; int sidx, i, j; pa = (point) testtet->tet[4]; pb = (point) testtet->tet[5]; pc = (point) testtet->tet[6]; pd = (point) testtet->tet[7]; // Get the edge vectors vda: d->a, vdb: d->b, vdc: d->c. // Set the matrix A = [vda, vdb, vdc]^T. for (i = 0; i < 3; i++) A[0][i] = vda[i] = pa[i] - pd[i]; for (i = 0; i < 3; i++) A[1][i] = vdb[i] = pb[i] - pd[i]; for (i = 0; i < 3; i++) A[2][i] = vdc[i] = pc[i] - pd[i]; // Get the rest edge vectors for (i = 0; i < 3; i++) vab[i] = pb[i] - pa[i]; for (i = 0; i < 3; i++) vbc[i] = pc[i] - pb[i]; for (i = 0; i < 3; i++) vca[i] = pa[i] - pc[i]; // Lu-decompose the matrix A. lu_decmp(A, 3, indx, &D, 0); // Get the volume of abcd. volume = (A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; if (volume < 0.0) volume = -volume; // Check the radiu-edge ratio of the tet. rhs[0] = 0.5 * dot(vda, vda); rhs[1] = 0.5 * dot(vdb, vdb); rhs[2] = 0.5 * dot(vdc, vdc); lu_solve(A, 3, indx, rhs, 0); // Get the circumcenter. for (i = 0; i < 3; i++) circumcent[i] = pd[i] + rhs[i]; // Get the square of the circumradius. radius2 = dot(rhs, rhs); // Find the square of the shortest edge length. elen[0] = dot(vda, vda); elen[1] = dot(vdb, vdb); elen[2] = dot(vdc, vdc); elen[3] = dot(vab, vab); elen[4] = dot(vbc, vbc); elen[5] = dot(vca, vca); smlen2 = elen[0]; sidx = 0; for (i = 1; i < 6; i++) { if (smlen2 > elen[i]) { smlen2 = elen[i]; sidx = i; } } // Calculate the square of radius-edge ratio. ratio2 = radius2 / smlen2; // Check whether the ratio is smaller than permitted. enq = ratio2 > b->goodratio; if (!enq) { // abcd has good ratio. // ratio2 = 0.0; // if (b->offcenter) { // Test if it is a sliver. // Compute the 4 face normals (N[0], ..., N[3]). for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) rhs[i] = 0.0; rhs[j] = 1.0; // Positive means the inside direction lu_solve(A, 3, indx, rhs, 0); for (i = 0; i < 3; i++) N[j][i] = rhs[i]; } // Get the fourth normal by summing up the first three. for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; // Normalized the normals. for (i = 0; i < 4; i++) { L = sqrt(dot(N[i], N[i])); if (L > 0.0) { for (j = 0; j < 3; j++) N[i][j] /= L; } } // N[0] is the normal of face bcd. Test the dihedral angles at edge // cd, bd, and bc to see if they are too small or too big. for (i = 1; i < 4 && !enq; i++) { cosd = -dot(N[0], N[i]); // Edge cd, bd, bc. enq = cosd > cosmindihed; } if (!enq) { for (i = 2; i < 4 && !enq; i++) { cosd = -dot(N[1], N[i]); // Edge ad, ac enq = cosd > cosmindihed; } if (!enq) { cosd = -dot(N[2], N[3]); // Edge ab enq = cosd > cosmindihed; } } // } } else if (b->offcenter) { // abcd has bad-quality. Use off-center instead of circumcenter. switch (sidx) { case 0: // edge da. pe1 = pd; pe2 = pa; break; case 1: // edge db. pe1 = pd; pe2 = pb; break; case 2: // edge dc. pe1 = pd; pe2 = pc; break; case 3: // edge ab. pe1 = pa; pe2 = pb; break; case 4: // edge bc. pe1 = pb; pe2 = pc; break; case 5: // edge ca. pe1 = pc; pe2 = pa; break; default: pe1 = pe2 = (point) NULL; // Avoid a compile warning. } // The shortest edge is e1->e2. for (i = 0; i < 3; i++) bicent[i] = 0.5 * (pe1[i] + pe2[i]); dist = distance(bicent, circumcent); // sdist = sqrt(smlen2) * sin(PI / 3.0); // A icoso-triangle. // The following formulae is from sdist = b->alpha3 * (b->minratio+sqrt(b->goodratio-0.25))* sqrt(smlen2); split = sdist / dist; if (split > 1.0) split = 1.0; // Get the off-center. for (i = 0; i < 3; i++) { offcent[i] = bicent[i] + split * (circumcent[i] - bicent[i]); } } if (!enq && (b->varvolume || b->fixedvolume)) { // Check if the tet has too big volume. enq = b->fixedvolume && (volume > b->maxvolume); if (!enq && b->varvolume) { enq = (volume > volumebound(testtet->tet)) && (volumebound(testtet->tet) > 0.0); } } if (!enq) { // Check if the user-defined sizing function is satisfied. if (b->metric) { if (in->tetunsuitable != NULL) { // Execute the user-defined meshing sizing evaluation. pa = (point) testtet->tet[4]; pb = (point) testtet->tet[5]; pc = (point) testtet->tet[6]; pd = (point) testtet->tet[7]; enq = (*(in->tetunsuitable))(pa, pb, pc, pd, elen, volume); } else { // assert(b->alpha1 > 0.0); sdist = sqrt(radius2) / b->alpha1; for (i = 0; i < 4; i++) { pa = (point) testtet->tet[4 + i]; // Get the indicated size of p. dist = pa[pointmtrindex]; // dist = b->alpha1 * pa[pointmtrindex]; enq = ((dist < sdist) && (dist > 0.0)); if (enq) break; // It is bad wrt. a node constraint. // *** Experiment ! Stop test if c is inside H(a). // if ((dist > 0.0) && (dist > sdist)) break; } } // *** Experiment ! // enq = (i == 4); // Does c lies outside all sparse-ball? } // if (b->metric) } if (enq && enqflag) { if (b->offcenter && (ratio2 > b->goodratio)) { for (i = 0; i < 3; i++) circumcent[i] = offcent[i]; } enqueuebadtet(testtet, ratio2, circumcent); } return enq; } /////////////////////////////////////////////////////////////////////////////// // // // acceptsegpt() Check if a segment point can be inserted or not. // // // // Segment(ab) is indicated to be split by a point p (\in ab). This routine // // decides whether p can be inserted or not. // // // // p can not be inserted either the '-Y' option is used and ab is a hull // // segment or '-YY' option is used. // // // // p can be inserted if it is in one of the following cases: // // (1) if L = |a - b| is too long wrt the edge constraint; or // // (2) if |x - p| > \alpha_2 H(x) for x = a, b; or // // (3) if 'refpt' != NULL. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::acceptsegpt(point segpt, point refpt, face* splitseg) { point p[2]; REAL L, lfs; int i, j; // This segment must have not been checked (and rejected) yet. assert(!smarktested(*splitseg)); if (b->nobisect == 1) { // '-Y'. It can not be split if it is on the hull. triface spintet; point pc; sstpivot(splitseg, &spintet); assert(spintet.tet != dummytet); pc = apex(spintet); do { if (!fnextself(spintet)) { // Meet a boundary face - s is on the hull. return false; } } while (pc != apex(spintet)); } else if (b->nobisect > 1) { // '-YY'. Do not split it. return false; } p[0] = sorg(*splitseg); p[1] = sdest(*splitseg); if (varconstraint && (areabound(*splitseg) > 0)) { lfs = areabound(*splitseg); L = distance(p[0], p[1]); if (L > lfs) { return true; // case (1) } } j = 0; // Use j to count the number of inside balls. for (i = 0; i < 2; i++) { // Check if p is inside the protect ball of q. if (p[i][pointmtrindex] > 0.0) { lfs = b->alpha2 * p[i][pointmtrindex]; L = distance(p[i], segpt); if (L < lfs) j++; // p is inside ball. } } if (j == 0) return true; // case (3). // If 'refpt' != NULL, force p to be inserted. if (refpt != (point) NULL) { cdtenforcesegpts++; return true; } // Do not split it. rejsegpts++; return false; } /////////////////////////////////////////////////////////////////////////////// // // // acceptfacpt() Check if a facet point can be inserted or not. // // // // 'subceillist' is CBC(p). 'verlist' (V) is empty on input, it returns the // // set of vertices of CBC(p). // // // // p can not be inserted either the '-Y' option is used and the facet is on // // the hull or '-YY' option is used. // // // // p can be inserted if |p - v| > \alpha_2 H(v), for all v \in V. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::acceptfacpt(point facpt, list* subceillist, list* verlist) { face *testsh; point p[2], ploop; REAL L, lfs; int idx, i, j; if (b->nobisect == 1) { // '-Y'. p can not be inserted if CBC(p) is on the hull. triface testtet; testsh = (face *)(* subceillist)[0]; stpivot(*testsh, testtet); if (testtet.tet != dummytet) { sesymself(*testsh); stpivot(*testsh, testtet); } if (testtet.tet == dummytet) return false; } else if (b->nobisect > 1) { // '-YY'. Do not split s. return false; } // Collect the vertices of CBC(p), save them in V. for (i = 0; i < subceillist->len(); i++) { testsh = (face *)(* subceillist)[i]; p[0] = sorg(*testsh); p[1] = sdest(*testsh); for (j = 0; j < 2; j++) { idx = pointmark(p[j]); if (idx >= 0) { setpointmark(p[j], -idx - 1); verlist->append(&(p[j])); } } } j = 0; // Use j to count the number of inside balls. for (i = 0; i < verlist->len(); i++) { ploop = * (point *)(* verlist)[i]; // Uninfect q. idx = pointmark(ploop); setpointmark(ploop, -(idx + 1)); // Check if p is inside the protect ball of q. if (ploop[pointmtrindex] > 0.0) { lfs = b->alpha2 * ploop[pointmtrindex]; L = distance(ploop, facpt); if (L < lfs) j++; // p is inside ball. } } verlist->clear(); if (j == 0) return true; // case (3). rejsubpts++; return false; } /////////////////////////////////////////////////////////////////////////////// // // // acceptvolpt() Check if a volume point can be inserted or not. // // // // 'ceillist' is B(p). 'verlist' (V) is empty on input, it returns the set // // of vertices of B(p). // // // // p can be split if |p - v| > \alpha_2 H(v), for all v \in V. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::acceptvolpt(point volpt, list* ceillist, list* verlist) { triface* testtet; point p[3], ploop; REAL L, lfs; int idx, i, j; // Collect the vertices of CBC(p), save them in V. for (i = 0; i < ceillist->len(); i++) { testtet = (triface *)(* ceillist)[i]; p[0] = org(*testtet); p[1] = dest(*testtet); p[2] = apex(*testtet); for (j = 0; j < 3; j++) { idx = pointmark(p[j]); if (idx >= 0) { setpointmark(p[j], -idx - 1); verlist->append(&(p[j])); } } } j = 0; // Use j to counte the number of inside balls. for (i = 0; i < verlist->len(); i++) { ploop = * (point *)(* verlist)[i]; // Uninfect q. idx = pointmark(ploop); setpointmark(ploop, -(idx + 1)); // Check if p is inside the protect ball of q. if (ploop[pointmtrindex] > 0.0) { lfs = b->alpha2 * ploop[pointmtrindex]; L = distance(ploop, volpt); if (L < lfs) j++; // p is inside the protect ball. } } verlist->clear(); if (j == 0) return true; // case (2). rejtetpts++; return false; } /////////////////////////////////////////////////////////////////////////////// // // // getsplitpoint() Get the inserting point in a segment. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::getsplitpoint(point e1, point e2, point refpt, point newpt) { point ei, ej; REAL split, L, d1, d2; bool acutea, acuteb; int i; if (refpt != (point) NULL) { // Use the CDT rules to split the segment. acutea = (pointtype(e1) == ACUTEVERTEX); acuteb = (pointtype(e2) == ACUTEVERTEX); if (acutea ^ acuteb) { // Only one endpoint is acute. Use rule-2 or rule-3. ei = acutea ? e1 : e2; ej = acutea ? e2 : e1; L = distance(ei, ej); // Apply rule-2. d1 = distance(ei, refpt); split = d1 / L; for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]); // Check if rule-3 is needed. d2 = distance(refpt, newpt); if (d2 > (L - d1)) { // Apply rule-3. if ((d1 - d2) > (0.5 * d1)) { split = (d1 - d2) / L; } else { split = 0.5 * d1 / L; } for (i = 0; i < 3; i++) newpt[i] = ei[i] + split * (ej[i] - ei[i]); if (b->verbose > 1) { printf(" Found by rule-3:"); } r3count++; } else { if (b->verbose > 1) { printf(" Found by rule-2:"); } r2count++; } if (b->verbose > 1) { printf(" center %d, split = %.12g.\n", pointmark(ei), split); } } else { // Both endpoints are acute or not. Split it at the middle. for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]); } } else { // Split the segment at its midpoint. for (i = 0; i < 3; i++) newpt[i] = 0.5 * (e1[i] + e2[i]); } } /////////////////////////////////////////////////////////////////////////////// // // // setnewpointsize() Set the size for a new point. // // // // The size of the new point p is interpolated either from a background mesh // // (b->bgmesh) or from the two input endpoints. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::setnewpointsize(point newpt, point e1, point e2) { if (b->metric) { // Interpolate the point size in a background mesh. triface bgmtet; // Get a tet in background mesh for locating p. decode(point2bgmtet(e1), bgmtet); p1interpolatebgm(newpt, &bgmtet, NULL); } else { if (e2 != (point) NULL) { // Interpolate the size between the two endpoints. REAL split, l, d; l = distance(e1, e2); d = distance(e1, newpt); split = d / l; #ifdef SELF_CHECK // Check if e1 and e2 are endpoints of a sharp segment. assert(e1[pointmtrindex] > 0.0); assert(e2[pointmtrindex] > 0.0); #endif newpt[pointmtrindex] = (1.0 - split) * e1[pointmtrindex] + split * e2[pointmtrindex]; } } } /////////////////////////////////////////////////////////////////////////////// // // // splitencseg() Split an enc-seg and recover the Delaunayness by flips. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::splitencseg(point newpt, face* splitseg, list* tetlist, list* sublist, list* verlist, queue* flipque, bool chkencsub, bool chkbadtet, bool optflag) { list *mytetlist; queue *myflipque; triface starttet; face startsh, spinsh, checksh; int i; if (optflag) { mytetlist = new list(sizeof(triface), NULL, 1024); myflipque = new queue(sizeof(badface)); tetlist = mytetlist; flipque = myflipque; } // Use the base orientation (important in this routine). splitseg->shver = 0; // Insert p, this should always success. sstpivot(splitseg, &starttet); if (splittetedge(newpt, &starttet, flipque)) { // Remove locally non-Delaunay faces by flipping. lawson3d(flipque); } else { if (optflag) { delete mytetlist; delete myflipque; } return false; } if (!optflag) { // Check the two new subsegs to see if they're encroached (not by p). for (i = 0; i < 2; i++) { //if (!shell2badface(*splitseg)) { checkseg4encroach(splitseg, NULL, NULL, true); //} if (i == 1) break; // Two new segs have been checked. senextself(*splitseg); spivotself(*splitseg); #ifdef SELF_CHECK assert(splitseg->sh != (shellface *) NULL); #endif splitseg->shver = 0; } // Check the new subfaces to see if they're encroached (not by p). if (chkencsub) { spivot(*splitseg, startsh); spinsh = startsh; do { sublist->append(&spinsh); formstarpolygon(newpt, sublist, verlist); for (i = 0; i < sublist->len(); i++) { checksh = * (face *)(* sublist)[i]; //if (!shell2badface(checksh)) { checksub4encroach(&checksh, NULL, true); //} } sublist->clear(); if (verlist) verlist->clear(); spivotself(spinsh); if (spinsh.sh == dummysh) { break; // There's only one facet having this segment. } } while (spinsh.sh != startsh.sh); } } // if (!optflag) // Collect the new tets connecting at p. sstpivot(splitseg, &starttet); tetlist->append(&starttet); formstarpolyhedron(newpt, tetlist, verlist, true); if (!optflag) { // Check if p encroaches adjacent segments. tallencsegs(newpt, 1, &tetlist); if (chkencsub) { // Check if p encroaches adjacent subfaces. tallencsubs(newpt, 1, &tetlist); } if (chkbadtet) { // Check if there are new bad quality tets at p. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; checktet4badqual(&starttet, true); } } tetlist->clear(); } else { // Check if new tets are non-optimal. for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; checktet4opt(&starttet, true); } delete mytetlist; delete myflipque; } return true; } /////////////////////////////////////////////////////////////////////////////// // // // tallencsegs() Check for encroached segments and save them in list. // // // // If 'testpt' (p) != NULL, only check if segments are encroached by p, else,// // check all the nearby mesh vertices. // // // // If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the // // segments which are on B_i(p)s, else, check the entire list of segments // // (in the pool 'this->subsegs'). // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::tallencsegs(point testpt, int n, list **ceillists) { list *ceillist; triface ceiltet; face checkseg; int enccount; // long oldencnum; int i, j, k; // Remember the current number of encroached segments. // oldencnum = badsubsegs->items; // Count the number of encroached segments. enccount = 0; if (ceillists != (list **) NULL) { for (k = 0; k < n; k++) { ceillist = ceillists[k]; // Check the segments on B_i(p). for (i = 0; i < ceillist->len(); i++) { ceiltet = * (triface *)(* ceillist)[i]; ceiltet.ver = 0; for (j = 0; j < 3; j++) { tsspivot(&ceiltet, &checkseg); if (checkseg.sh != dummysh) { // Found a segment. Test it if it isn't in enc-list. // if (!shell2badface(checkseg)) { if (checkseg4encroach(&checkseg, testpt, NULL, true)) { enccount++; } // } } enextself(ceiltet); } } } } else { // Check the entire list of segments. subsegs->traversalinit(); checkseg.sh = shellfacetraverse(subsegs); while (checkseg.sh != (shellface *) NULL) { // Test it if it isn't in enc-list. // if (!shell2badface(checkseg)) { if (checkseg4encroach(&checkseg, testpt, NULL, true)) { enccount++; } // } checkseg.sh = shellfacetraverse(subsegs); } } // return (badsubsegs->items > oldencnum); return enccount > 0; } /////////////////////////////////////////////////////////////////////////////// // // // tallencsubs() Find all encroached subfaces and save them in list. // // // // If 'testpt' (p) != NULL, only check if subfaces are encroached by p, else,// // check the adjacent vertices of subfaces. // // // // If 'ceillists' (B_i(p)) != NULL, there are 'n' B_i(p)s, only check the // // subfaces which are on B_i(p)s, else, check the entire list of subfaces // // (in the pool 'this->subfaces'). // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::tallencsubs(point testpt, int n, list** ceillists) { list *ceillist; triface ceiltet; face checksh; int enccount; //long oldencnum; int i, k; // Remember the current number of encroached segments. // oldencnum = badsubfaces->items; enccount = 0; // Count the number encroached subfaces. if (ceillists != (list **) NULL) { for (k = 0; k < n; k++) { ceillist = ceillists[k]; // Check the subfaces on B_i(p). for (i = 0; i < ceillist->len(); i++) { ceiltet = * (triface *)(* ceillist)[i]; tspivot(ceiltet, checksh); if (checksh.sh != dummysh) { // Found a subface. Test it if it isn't in enc-list. //if (!shell2badface(checksh)) { if (checksub4encroach(&checksh, testpt, true)) { enccount++; } //} } } } } else { // Check the entire list of subfaces. subfaces->traversalinit(); checksh.sh = shellfacetraverse(subfaces); while (checksh.sh != (shellface *) NULL) { // Test it if it isn't in enc-list. // if (!shell2badface(checksh)) { if (checksub4encroach(&checksh, testpt, true)) { enccount++; } // } checksh.sh = shellfacetraverse(subfaces); } } //return (badsubfaces->items > oldencnum); return enccount > 0; } /////////////////////////////////////////////////////////////////////////////// // // // tallbadtetrahedrons() Queue all the bad-quality tetrahedra in the mesh.// // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::tallbadtetrahedrons() { triface tetloop; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { checktet4badqual(&tetloop, true); tetloop.tet = tetrahedrontraverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // repairencsegs() Repair (split) all the encroached segments. // // // // Each encroached segment is repaired by splitting it - inserting a vertex // // at or near its midpoint. Newly inserted vertices may encroach upon other // // subsegments, these are also repaired. // // // // 'chkencsub' and 'chkbadtet' are two flags that specify whether one should // // take note of new encroaced subfaces and bad quality tets that result from // // inserting vertices to repair encroached subsegments. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::repairencsegs(bool chkencsub, bool chkbadtet) { list **tetlists, **ceillists; list **sublists, **subceillists; list *tetlist, *sublist; queue *flipque; badface *encloop; face splitseg; point newpt, refpt; point e1, e2; int nmax, n; n = 0; nmax = 128; if (!b->fliprepair) { tetlists = new list*[nmax]; ceillists = new list*[nmax]; sublists = new list*[nmax]; subceillists = new list*[nmax]; } else { tetlist = new list(sizeof(triface), NULL, 1024); sublist = new list(sizeof(face), NULL, 256); flipque = new queue(sizeof(badface)); } // Loop until the pool 'badsubsegs' is empty. Note that steinerleft == -1 // if an unlimited number of Steiner points is allowed. while ((badsubsegs->items > 0) && (steinerleft != 0)) { badsubsegs->traversalinit(); encloop = badfacetraverse(badsubsegs); while ((encloop != (badface *) NULL) && (steinerleft != 0)) { // Get an encroached subsegment s. splitseg = encloop->ss; // Clear the in-queue flag in s. setshell2badface(splitseg, NULL); if ((sorg(splitseg) == encloop->forg) && (sdest(splitseg) == encloop->fdest)) { if (b->verbose > 1) { printf(" Get an enc-seg (%d, %d)\n", pointmark(encloop->forg), pointmark(encloop->fdest)); } refpt = (point) NULL; if (b->conformdel) { // Look for a reference point. checkseg4encroach(&splitseg, NULL, &refpt, false); } // Create the new point p (at the middle of s). makepoint(&newpt); getsplitpoint(encloop->forg, encloop->fdest, refpt, newpt); setpointtype(newpt, FREESEGVERTEX); setpoint2seg(newpt, sencode(splitseg)); // Decide whether p can be inserted or not. if (acceptsegpt(newpt, refpt, &splitseg)) { // Save the endpoints of the seg for size interpolation. e1 = sorg(splitseg); if (shelltype(splitseg) == SHARP) { e2 = sdest(splitseg); } else { e2 = (point) NULL; // No need to do size interoplation. } if (!b->fliprepair) { // Form BC(p), B(p), CBC(p)s, and C(p)s. formbowatcavity(newpt, &splitseg, NULL, &n, &nmax, sublists, subceillists, tetlists, ceillists); // Validate/update BC(p), B(p), CBC(p)s, and C(p)s. if (trimbowatcavity(newpt, &splitseg, n, sublists, subceillists, tetlists, ceillists, -1.0)) { bowatinsertsite(newpt, &splitseg, n, sublists, subceillists, tetlists, ceillists, NULL, flipque, true, chkencsub, chkbadtet); setnewpointsize(newpt, e1, e2); if (steinerleft > 0) steinerleft--; } else { // p did not insert for invalid B(p). pointdealloc(newpt); } // Free the memory allocated in formbowatcavity(). releasebowatcavity(&splitseg, n, sublists, subceillists, tetlists, ceillists); } else { if (splitencseg(newpt, &splitseg, tetlist, sublist, NULL, flipque, chkencsub, chkbadtet, false)) { setnewpointsize(newpt, e1, e2); if (steinerleft > 0) steinerleft--; } else { // Fail to split the segment. It MUST be caused by a very flat // tet connected at the splitting segment. We do not handle // this case yet. Hopefully, the later repairs will remove // the flat tet and hence the segment can be split later. pointdealloc(newpt); } } } else { // This segment can not be split for not meeting the rules in // acceptsegpt(). Mark it to avoid re-checking it later. smarktest(splitseg); // p did not accept for insertion. pointdealloc(newpt); } // if (checkseg4splitting(newpt, &splitseg)) } // if ((encloop->forg == pa) && (encloop->fdest == pb)) badfacedealloc(badsubsegs, encloop); // Remove this entry from list. encloop = badfacetraverse(badsubsegs); // Get the next enc-segment. } // while ((encloop != (badface *) NULL) && (steinerleft != 0)) } // while ((badsubsegs->items > 0) && (steinerleft != 0)) if (!b->fliprepair) { delete [] tetlists; delete [] ceillists; delete [] sublists; delete [] subceillists; } else { delete tetlist; delete sublist; delete flipque; } } /////////////////////////////////////////////////////////////////////////////// // // // repairencsubs() Repair (split) all the encroached subfaces. // // // // Each encroached subface is repaired by splitting it - inserting a vertex // // at or near its circumcenter. Newly inserted vertices may encroach upon // // other subfaces, these are also repaired. // // // // 'chkbadtet' is a flag that specifies whether one should take note of new // // bad quality tets that result from inserted vertices. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::repairencsubs(bool chkbadtet) { list *tetlists[2], *ceillists[2]; list *sublist, *subceillist; list *verlist; badface *encloop; face splitsub, symsplitsub; point newpt, e1; enum locateresult loc; REAL normal[3], len; bool reject; long oldptnum, oldencsegnum; int quenumber, n, i; n = 0; sublist = (list *) NULL; subceillist = (list *) NULL; verlist = new list(sizeof(point *), NULL, 256); // Loop until the pool 'badsubfaces' is empty. Note that steinerleft == -1 // if an unlimited number of Steiner points is allowed. while ((badsubfaces->items > 0) && (steinerleft != 0)) { // Get an encroached subface f. encloop = dequeueencsub(&quenumber); splitsub = encloop->ss; // Clear the in-queue flag of f. setshell2badface(splitsub, NULL); // f may not be the same one when it was determined to be encroached. if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) && (sdest(splitsub) == encloop->fdest) && (sapex(splitsub) == encloop->fapex)) { if (b->verbose > 1) { printf(" Dequeuing ensub (%d, %d, %d) [%d].\n", pointmark(encloop->forg), pointmark(encloop->fdest), pointmark(encloop->fapex), quenumber); } // Create a new point p at the circumcenter of f. makepoint(&newpt); for (i = 0; i < 3; i++) newpt[i] = encloop->cent[i]; setpointtype(newpt, FREESUBVERTEX); setpoint2sh(newpt, sencode(splitsub)); // Set the abovepoint of f for point location. abovepoint = facetabovepointarray[shellmark(splitsub)]; if (abovepoint == (point) NULL) { // getfacetabovepoint(&splitsub); // Calculate an abovepoint in dummypoint. facenormal2(encloop->forg, encloop->fdest, encloop->fapex, normal, 1); len = sqrt(DOT(normal, normal)); normal[0] /= len; normal[1] /= len; normal[2] /= len; len = DIST(encloop->forg, encloop->fdest); len += DIST(encloop->fdest, encloop->fapex); len += DIST(encloop->fapex, encloop->forg); len /= 3.0; dummypoint[0] = encloop->forg[0] + len * normal[0]; dummypoint[1] = encloop->forg[1] + len * normal[1]; dummypoint[2] = encloop->forg[2] + len * normal[2]; abovepoint = dummypoint; } // Locate p, start from f, stop at segment (1), use a tolerance to // detect ONVERTEX or OUTSIDE case. Update f on return. loc = locatesub(newpt, &splitsub, 1, b->epsilon * 1e+2); if ((loc != ONVERTEX) && (loc != OUTSIDE)) { // Form BC(p), B(p), CBC(p) and C(p). formbowatcavity(newpt, NULL, &splitsub, &n, NULL, &sublist, &subceillist, tetlists, ceillists); // Check for encroached subsegments (on B(p)). oldencsegnum = badsubsegs->items; reject = tallencsegs(newpt, 2, ceillists); if (reject && (oldencsegnum == badsubsegs->items)) { // 'newpt' encroaches upon some subsegments. But none of them can // be split. So this subface can't be split as well. Mark it to // avoid re-checking it later. smarktest(encloop->ss); } // Execute point accept rule if p does not encroach upon any segment. if (!reject) { reject = !acceptfacpt(newpt, subceillist, verlist); if (reject) { // 'newpt' lies in some protecting balls. This subface can't be // split. Mark it to avoid re-checking it later. smarktest(encloop->ss); } } if (!reject) { // Validate/update cavity. reject = !trimbowatcavity(newpt, NULL, n, &sublist, &subceillist, tetlists, ceillists, -1.0); } if (!reject) { // CBC(p) should include s, so that s can be removed after CBC(p) // is remeshed. However, if there are locally non-Delaunay faces // and encroached subsegments, s may not be collected in CBC(p). // p should not be inserted in such case. reject = !sinfected(encloop->ss); } if (!reject) { // Save a point for size interpolation. e1 = sorg(splitsub); bowatinsertsite(newpt, NULL, n, &sublist, &subceillist, tetlists, ceillists, NULL, NULL, true, true, chkbadtet); setnewpointsize(newpt, e1, NULL); if (steinerleft > 0) steinerleft--; } else { // p is rejected for the one of the following reasons: // (1) BC(p) is not valid. // (2) s does not in CBC(p). // (3) p encroaches upon some segments (queued); or // (4) p is rejected by point accepting rule, or // (5) due to the rejection of symp (the PBC). pointdealloc(newpt); } // if (!reject) // Release the cavity and free the memory. releasebowatcavity(NULL,n,&sublist,&subceillist,tetlists,ceillists); if (reject) { // Are there queued encroached subsegments. if (badsubsegs->items > 0) { // Repair enc-subsegments. oldptnum = points->items; repairencsegs(true, chkbadtet); /*if (points->items > oldptnum) { // Some enc-subsegments got split. Try to repair f later. splitsub = encloop->ss; if (!isdead(&splitsub)) { if (!shell2badface(splitsub)) { checksub4encroach(&splitsub, NULL, true); } } }*/ } } } else { // Don't insert p for one of the following reasons: // (1) Locate on an existing vertex; or // (2) locate outside the domain. // Case (1) should not be possible. If such vertex v exists, it is // the circumcenter of f, ie., f is non-Delaunay. Either f was got // split before by v, but survived after v was inserted, or the // same for a f' which is nearly co-circular with f. Whatsoever, // there are encroached segs by v, but the routine tallencsegs() // did not find them out. if (loc == ONVERTEX) { printf("Internal error in repairencsubs():\n"); printf(" During repairing encroached subface (%d, %d, %d)\n", pointmark(encloop->forg), pointmark(encloop->fdest), pointmark(encloop->fapex)); printf(" New point %d is coincident with an existing vertex %d\n", pointmark(newpt), pointmark(sorg(splitsub))); terminatetetgen(2); } assert(loc == OUTSIDE); // The circumcenter lies outside of the facet. Mark it to avoid // rechecking it later. smarktest(encloop->ss); // Case (2) can happen when thers is a segment s which is close to f // and is non-conforming Delaunay. The circumcenter of f encroaches // upon s, but the circumcenter of s is rejected for insertion. pointdealloc(newpt); } // if ((loc != ONVERTEX) && (loc != OUTSIDE)) } /*else { if (!isdead(&splitsub)) { // The subface has been changed, re-check it. checksub4encroach(&splitsub, NULL, true); } } // if (!isdead(&splitsub) && (sorg(splitsub) == encloop->forg) && */ // Remove this entry from list. badfacedealloc(badsubfaces, encloop); } // while ((badsubfaces->items > 0) && (steinerleft != 0)) delete verlist; } /////////////////////////////////////////////////////////////////////////////// // // // repairbadtets() Repair all bad-quality tetrahedra. // // // // All bad-quality tets are stored in pool 'badtetrahedrons'. Each bad tet // // is repaired by inserting a point at or near its circumcenter. However, if // // this point encroaches any subsegment or subface, it is not inserted. Ins- // // tead the encroached segment and subface are split. Newly inserted points // // may create other bad-quality tets, these are also repaired. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::repairbadtets() { list *tetlist, *ceillist; list *verlist; arraypool *histtetarray; badface *badtet; triface starttet; point newpt, e1; enum locateresult loc; bool reject; long oldptnum; int i; tetlist = new list(sizeof(triface), NULL, 1024); ceillist = new list(sizeof(triface), NULL, 1024); verlist = new list(sizeof(point *), NULL, 256); histtetarray = new arraypool(sizeof(triface), 8); // Loop until pool 'badtetrahedrons' is empty. Note that steinerleft == -1 // if an unlimited number of Steiner points is allowed. while ((badtetrahedrons->items > 0) && (steinerleft != 0)) { // Get a bad-quality tet t. badtet = topbadtetra(); // Make sure that the tet is still the same one when it was tested. // Subsequent transformations may have made it a different tet. if ((badtet != (badface *) NULL) && !isdead(&badtet->tt) && org(badtet->tt) == badtet->forg && dest(badtet->tt) == badtet->fdest && apex(badtet->tt) == badtet->fapex && oppo(badtet->tt) == badtet->foppo) { if (b->verbose > 1) { printf(" Dequeuing btet (%d, %d, %d, %d).\n", pointmark(badtet->forg), pointmark(badtet->fdest), pointmark(badtet->fapex), pointmark(badtet->foppo)); } // Create the new point p (at the circumcenter of t). makepoint(&newpt); for (i = 0; i < 3; i++) newpt[i] = badtet->cent[i]; setpointtype(newpt, FREEVOLVERTEX); // Locate p. starttet = badtet->tt; //loc = preciselocate(newpt, &starttet, tetrahedrons->items); loc = locate2(newpt, &starttet, histtetarray); if (b->verbose > 1) { printf(" loc = %d.\n", (int) loc); } if ((loc != ONVERTEX) && (loc != OUTSIDE)) { // For BC(p) and B(p). infect(starttet); tetlist->append(&starttet); formbowatcavityquad(newpt, tetlist, ceillist); // Check for encroached subsegments. reject = tallencsegs(newpt, 1, &ceillist); if (!reject) { // Check for encroached subfaces. reject = tallencsubs(newpt, 1, &ceillist); } // Execute point accepting rule if p does not encroach upon any // subsegment and subface. if (!reject) { reject = !acceptvolpt(newpt, ceillist, verlist); } if (!reject) { reject = !trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, -1.0); } if (!reject) { // BC(p) should include t, so that t can be removed after BC(p) is // remeshed. However, if there are locally non-Delaunay faces // and encroached subsegments/subfaces, t may not be collected // in BC(p). p should not be inserted in such case. reject = !infected(badtet->tt); if (reject) outbowatcircumcount++; } if (!reject) { // Save a point for size interpolation. e1 = org(starttet); // Insert p. bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, NULL, NULL, false, false, true); setnewpointsize(newpt, e1, NULL); if (steinerleft > 0) steinerleft--; } else { // p is rejected for one of the following reasons: // (1) BC(p) is not valid. // (2) t does not in BC(p). // (3) p encroaches upon some segments; // (4) p encroaches upon some subfaces; // (5) p is rejected by the point accepting rule. pointdealloc(newpt); // Uninfect tets of BC(p). for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; uninfect(starttet); } } tetlist->clear(); ceillist->clear(); // Split encroached subsegments/subfaces if there are. if (reject) { oldptnum = points->items; if (badsubsegs->items > 0) { repairencsegs(true, true); } if (badsubfaces->items > 0) { repairencsubs(true); } if (points->items > oldptnum) { // Some encroaching subsegments/subfaces got split. Re-queue the // tet if it is still alive. starttet = badtet->tt; if (!isdead(&starttet)) { checktet4badqual(&starttet, true); } } } } else { // Do not insert p. The reason may be one of: // (1) p is coincident (ONVERTEX) with an existing vertex; or // (2) p is outside (OUTSIDE) the mesh. // Case (1) should not be possible. If such vertex v exists, it is // the circumcenter of t, ie., t is non-Delaunay. Either t was got // split before by v, but survived after v was inserted, or the // same for a t' which is nearly co-spherical with t. Whatsoever, // there are encroached segments or subfaces by v but the routines // tallencsegs() or tallencsubs() did not find them out. if (loc == ONVERTEX) { printf("Internal error in repairbadtets():\n"); printf(" During repairing bad tet (%d, %d, %d, %d)\n", pointmark(badtet->forg), pointmark(badtet->fdest), pointmark(badtet->fapex), pointmark(badtet->foppo)); printf(" New point %d is coincident with an existing vertex %d\n", pointmark(newpt), pointmark(org(starttet))); terminatetetgen(2); } // Case (2) can happen when there is a segment s (or subface f) which // is close to f and is non-conforming Delaunay. The circumcenter // of t encroaches upon s (or f), but the circumcenter of s (or f) // is rejected for insertion. pointdealloc(newpt); } // if ((loc != ONVERTEX) && (loc != OUTSIDE)) } // if (!isdead(&badtet->tt) && org(badtet->tt) == badtet->forg && // Remove the tet from the queue. dequeuebadtet(); } // while ((badtetrahedrons->items > 0) && (steinerleft != 0)) delete tetlist; delete ceillist; delete verlist; delete histtetarray; } /////////////////////////////////////////////////////////////////////////////// // // // enforcequality() Refine the mesh. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::enforcequality() { long total, vertcount; int i; if (!b->quiet) { printf("Adding Steiner points to enforce quality.\n"); } total = vertcount = 0l; if (b->conformdel) { r2count = r3count = 0l; } // If both '-D' and '-r' options are used. if (b->conformdel && b->refine) { markacutevertices(65.0); } // If '-m' is not used. if (!b->metric) { // Find and mark all sharp segments. marksharpsegments(65.0); // Decide the sizes for feature points. decidefeaturepointsizes(); } // Initialize the pool of encroached subsegments. badsubsegs = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); // Looking for encroached subsegments. tallencsegs(NULL, 0, NULL); if (b->verbose && badsubsegs->items > 0) { printf(" Splitting encroached subsegments.\n"); } vertcount = points->items; // Fix encroached segments without noting any enc subfaces. repairencsegs(false, false); if (b->verbose > 0) { printf(" %ld split points.\n", points->items - vertcount); } total += points->items - vertcount; // Initialize the pool of encroached subfaces. badsubfaces = new memorypool(sizeof(badface), SUBPERBLOCK, POINTER, 0); // Initialize the priority queues of badfaces. for (i = 0; i < 3; i++) subquefront[i] = (badface *) NULL; for (i = 0; i < 3; i++) subquetail[i] = &subquefront[i]; // Looking for encroached subfaces. tallencsubs(NULL, 0, NULL); if (b->verbose && badsubfaces->items > 0) { printf(" Splitting encroached subfaces.\n"); } vertcount = points->items; // Fix encroached subfaces without noting bad tetrahedra. repairencsubs(false); if (b->verbose > 0) { printf(" %ld split points.\n", points->items - vertcount); } total += points->items - vertcount; // At this point, the mesh should be conforming Delaunay if no input // angle is smaller than 90 degree. // Next, fix bad quality tetrahedra. if ((b->minratio > 0.0) || b->varvolume || b->fixedvolume) { // Initialize the pool of bad tets badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0); // Initialize the priority queues of bad tets. for (i = 0; i < 64; i++) tetquefront[i] = (badface *) NULL; firstnonemptyq = -1; recentq = -1; // Looking for bad quality tets. cosmaxdihed = cos(b->maxdihedral * PI / 180.0); cosmindihed = cos(b->mindihedral * PI / 180.0); tallbadtetrahedrons(); if (b->verbose && badtetrahedrons->items > 0) { printf(" Splitting bad tetrahedra.\n"); } vertcount = points->items; repairbadtets(); if (b->verbose > 0) { printf(" %ld refinement points.\n", points->items - vertcount); } total += points->items - vertcount; delete badtetrahedrons; } if (b->verbose > 0) { printf(" Totally added %ld points.\n", total); } delete badsubfaces; delete badsubsegs; } //// //// //// //// //// refine_cxx /////////////////////////////////////////////////////////////// //// optimize_cxx ///////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // checktet4ill() Check a tet to see if it is illegal. // // // // A tet is "illegal" if it spans on one input facet. Save the tet in queue // // if it is illegal and the flag 'enqflag' is set. // // // // Note: Such case can happen when the input facet has non-coplanar vertices // // and the Delaunay tetrahedralization of the vertices may creat such tets. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::checktet4ill(triface* testtet, bool enqflag) { badface *newbadtet; triface checktet; face checksh1, checksh2; face checkseg; bool illflag; int i; illflag = false; for (testtet->loc = 0; testtet->loc < 4; testtet->loc++) { tspivot(*testtet, checksh1); if (checksh1.sh != dummysh) { testtet->ver = 0; findedge(&checksh1, org(*testtet), dest(*testtet)); for (i = 0; i < 3; i++) { fnext(*testtet, checktet); tspivot(checktet, checksh2); if (checksh2.sh != dummysh) { // Two subfaces share this edge. sspivot(checksh1, checkseg); if (checkseg.sh == dummysh) { // The four corners of the tet are on one facet. Illegal! Try to // flip the opposite edge of the current one. enextfnextself(*testtet); enextself(*testtet); illflag = true; break; } } enextself(*testtet); senextself(checksh1); } } if (illflag) break; } if (illflag && enqflag) { // Allocate space for the bad tetrahedron. newbadtet = (badface *) badtetrahedrons->alloc(); newbadtet->tt = *testtet; newbadtet->key = -1.0; // = 180 degree. for (i = 0; i < 3; i++) newbadtet->cent[i] = 0.0; newbadtet->forg = org(*testtet); newbadtet->fdest = dest(*testtet); newbadtet->fapex = apex(*testtet); newbadtet->foppo = oppo(*testtet); newbadtet->nextitem = (badface *) NULL; if (b->verbose > 2) { printf(" Queueing illtet: (%d, %d, %d, %d).\n", pointmark(newbadtet->forg), pointmark(newbadtet->fdest), pointmark(newbadtet->fapex), pointmark(newbadtet->foppo)); } } return illflag; } /////////////////////////////////////////////////////////////////////////////// // // // checktet4opt() Check a tet to see if it needs to be optimized. // // // // A tet t needs to be optimized if it fails to certain quality measures. // // The only quality measure currently used is the maximal dihedral angle at // // edges. The desired maximal dihedral angle is 'b->maxdihedal' (set by the // // '-qqq' option. // // // // A tet may have one, two, or three big dihedral angles. Examples: Let the // // tet t = abcd, and its four corners are nearly co-planar. Then t has one // // big dihedral angle if d is very close to the edge ab; t has three big // // dihedral angles if d's projection on the face abc is also inside abc, i.e.// // the shape of t likes a hat; finally, t has two big dihedral angles if d's // // projection onto abc is outside abc. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::checktet4opt(triface* testtet, bool enqflag) { badface *newbadtet; point pa, pb, pc, pd; REAL N[4][3], len; REAL cosd; int count; int i, j; pa = (point) testtet->tet[4]; pb = (point) testtet->tet[5]; pc = (point) testtet->tet[6]; pd = (point) testtet->tet[7]; // Compute the 4 face normals: N[0] cbd, N[1] acd, N[2] bad, N[3] abc. tetallnormal(pa, pb, pc, pd, N, NULL); // Normalize the normals. for (i = 0; i < 4; i++) { len = sqrt(dot(N[i], N[i])); if (len != 0.0) { for (j = 0; j < 3; j++) N[i][j] /= len; } } count = 0; // Find all large dihedral angles. for (i = 0; i < 6; i++) { // Locate the edge i and calculate the dihedral angle at the edge. testtet->loc = 0; testtet->ver = 0; switch (i) { case 0: // edge ab cosd = -dot(N[2], N[3]); break; case 1: // edge cd enextfnextself(*testtet); enextself(*testtet); cosd = -dot(N[0], N[1]); break; case 2: // edge bd enextfnextself(*testtet); enext2self(*testtet); cosd = -dot(N[0], N[2]); break; case 3: // edge bc enextself(*testtet); cosd = -dot(N[0], N[3]); break; case 4: // edge ad enext2fnextself(*testtet); enextself(*testtet); cosd = -dot(N[1], N[2]); break; case 5: // edge ac enext2self(*testtet); cosd = -dot(N[1], N[3]); break; } if (cosd < cosmaxdihed) { // A bigger dihedral angle. count++; if (enqflag) { // Allocate space for the bad tetrahedron. newbadtet = (badface *) badtetrahedrons->alloc(); newbadtet->tt = *testtet; newbadtet->key = cosd; for (j = 0; j < 3; j++) newbadtet->cent[j] = 0.0; newbadtet->forg = org(*testtet); newbadtet->fdest = dest(*testtet); newbadtet->fapex = apex(*testtet); newbadtet->foppo = oppo(*testtet); newbadtet->nextitem = (badface *) NULL; if (b->verbose > 2) { printf(" Queueing tet: (%d, %d, %d, %d), dihed %g (degree).\n", pointmark(newbadtet->forg), pointmark(newbadtet->fdest), pointmark(newbadtet->fapex), pointmark(newbadtet->foppo), acos(cosd) * 180.0 / PI); } } } } return count > 0; } /////////////////////////////////////////////////////////////////////////////// // // // removeedge() Remove an edge // // // // 'remedge' is a tet (abcd) having the edge ab wanted to be removed. Local // // reconnecting operations are used to remove edge ab. The following opera- // // tion will be tryed. // // // // If ab is on the hull, and abc and abd are both hull faces. Then ab can be // // removed by stripping abcd from the mesh. However, if ab is a segemnt, do // // the operation only if 'b->optlevel' > 1 and 'b->nobisect == 0'. // // // // If ab is an internal edge, there are n tets contains it. Then ab can be // // removed if there exists another m tets which can replace the n tets with- // // out changing the boundary of the n tets. // // // // If 'optflag' is set. The value 'remedge->key' means cos(theta), where // // 'theta' is the maximal dishedral angle at ab. In this case, even if the // // n-to-m flip exists, it will not be performed if the maximum dihedral of // // the new tets is larger than 'theta'. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::removeedge(badface* remedge, bool optflag) { triface abcd, badc; // Tet configuration at edge ab. triface baccasing, abdcasing; triface abtetlist[21]; // Old configuration at ab, save maximum 20 tets. triface bftetlist[21]; // Old configuration at bf, save maximum 20 tets. triface newtetlist[90]; // New configuration after removing ab. face checksh; //enum fliptype fty; REAL key; bool remflag, subflag; int n, n1, m, i, j, k; triface newtet; point *ppt; // First try to strip abcd from the mesh. This needs to check either ab // or cd is on the hull. Try to strip it whichever is true. abcd = remedge->tt; adjustedgering(abcd, CCW); k = 0; do { sym(abcd, baccasing); // Is the tet on the hull? if (baccasing.tet == dummytet) { fnext(abcd, badc); sym(badc, abdcasing); if (abdcasing.tet == dummytet) { // Strip the tet from the mesh -> ab is removed as well. if (removetetbypeeloff(&abcd, newtetlist)) { if (b->verbose > 1) { printf(" Stripped tet from the mesh.\n"); } optcount[0]++; opt_tet_peels++; // edge is removed. Test new tets for further optimization. for (i = 0; i < 2; i++) { if (optflag) { checktet4opt(&(newtetlist[i]), true); } else { checktet4ill(&(newtetlist[i]), true); } } // Update the point-to-tet map for (i = 0; i < 2; i++) { newtet = newtetlist[i]; ppt = (point *) &(newtet.tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(newtet)); } } return true; } } } // Check if the oppsite edge cd is on the hull. enext2fnextself(abcd); enext2self(abcd); esymself(abcd); // --> cdab k++; } while (k < 2); // Get the tets configuration at ab. Collect maximum 10 tets. subflag = false; abcd = remedge->tt; adjustedgering(abcd, CW); n = 0; abtetlist[n] = abcd; do { // Is the list full? if (n == 20) break; // Stop if a subface appears. tspivot(abtetlist[n], checksh); if (checksh.sh != dummysh) { // ab is either a segment or a facet edge. The latter case is not // handled yet! An edge flip is needed. subflag = true; break; // return false; } // Get the next tet at ab. fnext(abtetlist[n], abtetlist[n + 1]); n++; } while (apex(abtetlist[n]) != apex(abcd)); remflag = false; key = remedge->key; if (subflag && optflag) { /*abcd = remedge->tt; adjustedgering(abcd, CCW); // Try to flip face cda or cdb to improve quality. for (j = 0; j < 2; j++) { if (j == 0) { enext2fnext(abcd, abtetlist[0]); // Goto cda. } else { enextfnext(abcd, abtetlist[0]); // Goto cdb. } fty = categorizeface(abtetlist[0]); if (fty == T23) { // A 2-to-3 flip is possible. sym(abtetlist[0], abtetlist[1]); assert(abtetlist[1].tet != dummytet); n = 2; m = 3; remflag = removefacebyflip23(&key, abtetlist, newtetlist, NULL); } else if (fty == T22) { // A 2-to-2 or 4-to-4 flip is possible. n = 2; newtetlist[0] = abtetlist[0]; adjustedgering(newtetlist[0], CW); fnext(newtetlist[0], newtetlist[1]); assert(newtetlist[1].tet != dummytet); // May it is 4-to-4 flip. if (fnext(newtetlist[1], newtetlist[2])) { fnext(newtetlist[2], newtetlist[3]); assert(newtetlist[3].tet != dummytet); n = 4; } m = n; remflag = removeedgebyflip22(&key, n, newtetlist, NULL); } // Has quality been improved? if (remflag) { if (b->verbose > 1) { printf(" Done flip %d-to-%d. Qual: %g -> %g.\n", n, m, acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0); } // Delete the old tets. Note, flip22() does not create new tets. if (m == 3) { for (i = 0; i < n; i++) { tetrahedrondealloc(abtetlist[i].tet); } } for (i = 0; i < m; i++) { checktet4opt(&(newtetlist[i]), true); } // Update the point-to-tet map for (i = 0; i < m; i++) { newtet = newtetlist[i]; ppt = (point *) &(newtet.tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(newtet)); } } optcount[1]++; opt_face_flips++; return true; } } // j */ // Faces are not flipable. Return. return false; } // 2 < n < 20. if (n == 3) { // There are three tets at ab. Try to do a flip32 at ab. remflag = removeedgebyflip32(&key, abtetlist, newtetlist, NULL); } else if ((n > 3) && (n <= b->maxflipedgelinksize)) { // Four tets case. Try to do edge transformation. remflag = removeedgebytranNM(&key,n,abtetlist,newtetlist,NULL,NULL,NULL); } else { if (b->verbose > 1) { printf(" !! Unhandled case: n = %d.\n", n); } } if (remflag) { optcount[n]++; // Delete the old tets. for (i = 0; i < n; i++) { tetrahedrondealloc(abtetlist[i].tet); } m = (n - 2) * 2; // The numebr of new tets. if (b->verbose > 1) { printf(" Done flip %d-to-%d. ", n, m); if (optflag) { printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0); } printf("\n"); } } if (!remflag && (key == remedge->key) && (n <= b->maxflipedgelinksize)) { // Try to do a combination of flips. n1 = 0; remflag = removeedgebycombNM(&key, n, abtetlist, &n1, bftetlist, newtetlist, NULL); if (remflag) { optcount[9]++; // Delete the old tets. for (i = 0; i < n; i++) { tetrahedrondealloc(abtetlist[i].tet); } for (i = 0; i < n1; i++) { if (!isdead(&(bftetlist[i]))) { tetrahedrondealloc(bftetlist[i].tet); } } m = ((n1 - 2) * 2 - 1) + (n - 3) * 2; // The number of new tets. if (b->verbose > 1) { printf(" Done flip %d-to-%d (n-1=%d, n1=%d). ", n+n1-2, m, n-1,n1); if (optflag) { printf("Qual: %g -> %g.", acos(remedge->key) / PI * 180.0, acos(key) / PI * 180.0); } printf("\n"); } } } if (remflag) { // edge is removed. Test new tets for further optimization. for (i = 0; i < m; i++) { if (optflag) { checktet4opt(&(newtetlist[i]), true); } else { checktet4ill(&(newtetlist[i]), true); } } // Update the point-to-tet map for (i = 0; i < m; i++) { newtet = newtetlist[i]; ppt = (point *) &(newtet.tet[4]); for (j = 0; j < 4; j++) { setpoint2tet(ppt[j], encode(newtet)); } } opt_edge_flips++; } return remflag; } /////////////////////////////////////////////////////////////////////////////// // // // smoothpoint() Smooth a volume/segment point. // // // // 'smthpt' (p) is inside the polyhedron (C) bounded by faces in 'starlist'. // // This routine moves p inside C until an object function is maximized. // // // // Default, the CCW edge ring of the faces on C points to p. If 'invtori' is // // TRUE, the orientation is inversed. // // // // If 'key' != NULL, it contains an object value to be improved. Current it // // means the cosine of the largest dihedral angle. In such case, the point // // is smoothed only if the final configuration improves the object value, it // // is returned by the 'key'. // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::smoothpoint(point smthpt, point e1, point e2, list *starlist, bool invtori, REAL *key) { triface starttet; point pa, pb, pc; REAL fcent[3], startpt[3], nextpt[3], bestpt[3]; REAL iniTmax, oldTmax, newTmax; REAL ori, aspT, aspTmax, imprate; REAL cosd, maxcosd; bool segflag, randflag; //, subflag; int numdirs; int iter, i, j; // Is p a segment vertex? segflag = (e1 != (point) NULL); // Decide the number of moving directions. numdirs = segflag ? 2 : starlist->len(); randflag = numdirs > 10; if (randflag) { numdirs = 10; // Maximum 10 directions. } // Calculate the initial object value (the largest aspect ratio). for (i = 0; i < starlist->len(); i++) { starttet = * (triface *)(* starlist)[i]; adjustedgering(starttet, !invtori ? CCW : CW); pa = org(starttet); pb = dest(starttet); pc = apex(starttet); aspT = tetaspectratio(pa, pb, pc, smthpt); if (i == 0) { aspTmax = aspT; } else { aspTmax = aspT > aspTmax ? aspT : aspTmax; } } iniTmax = aspTmax; if (b->verbose > 1) { printf(" Smooth %s point %d (%g, %g, %g).\n", segflag ? "seg" : "vol", pointmark(smthpt), smthpt[0], smthpt[1], smthpt[2]); printf(" Initial max L/h = %g.\n", iniTmax); } for (i = 0; i < 3; i++) { bestpt[i] = startpt[i] = smthpt[i]; } // Do iteration until the new aspTmax does not decrease. newTmax = iniTmax; iter = 0; while (true) { // Find the best next location. oldTmax = newTmax; for (i = 0; i < numdirs; i++) { // Calculate the moved point (saved in 'nextpt'). if (!segflag) { if (randflag) { // Randomly pick a direction. j = (int) randomnation(starlist->len()); } else { j = i; } starttet = * (triface *)(* starlist)[j]; adjustedgering(starttet, !invtori ? CCW : CW); pa = org(starttet); pb = dest(starttet); pc = apex(starttet); for (j = 0; j < 3; j++) { fcent[j] = (pa[j] + pb[j] + pc[j]) / 3.0; } } else { for (j = 0; j < 3; j++) { fcent[j] = (i == 0 ? e1[j] : e2[j]); } } for (j = 0; j < 3; j++) { nextpt[j] = startpt[j] + 0.01 * (fcent[j] - startpt[j]); } // Get the largest object value for the new location. for (j = 0; j < starlist->len(); j++) { starttet = * (triface *)(* starlist)[j]; adjustedgering(starttet, !invtori ? CCW : CW); pa = org(starttet); pb = dest(starttet); pc = apex(starttet); ori = orient3d(pa, pb, pc, nextpt); if (ori < 0.0) { aspT = tetaspectratio(pa, pb, pc, nextpt); if (j == 0) { aspTmax = aspT; } else { aspTmax = aspT > aspTmax ? aspT : aspTmax; } } else { // An invalid new tet. Discard this point. aspTmax = newTmax; } // if (ori < 0.0) // Stop looping when the object value is bigger than before. if (aspTmax >= newTmax) break; } // for (j = 0; j < starlist->len(); j++) if (aspTmax < newTmax) { // Save the improved object value and the location. newTmax = aspTmax; for (j = 0; j < 3; j++) bestpt[j] = nextpt[j]; } } // for (i = 0; i < starlist->len(); i++) // Does the object value improved much? imprate = fabs(oldTmax - newTmax) / oldTmax; if (imprate < 1e-3) break; // Yes, move p to the new location and continue. for (j = 0; j < 3; j++) startpt[j] = bestpt[j]; iter++; } // while (true) if (iter > 0) { // The point is moved. if (key) { // Check if the quality is improved by the smoothed point. maxcosd = 0.0; // = cos(90). for (j = 0; j < starlist->len(); j++) { starttet = * (triface *)(* starlist)[j]; adjustedgering(starttet, !invtori ? CCW : CW); pa = org(starttet); pb = dest(starttet); pc = apex(starttet); tetalldihedral(pa, pb, pc, startpt, NULL, &cosd, NULL); if (cosd < *key) { // This quality will not be improved. Stop. iter = 0; break; } else { // Remeber the worst quality value (of the new configuration). maxcosd = maxcosd < cosd ? maxcosd : cosd; } } if (iter > 0) *key = maxcosd; } } if (iter > 0) { if (segflag) smoothsegverts++; for (i = 0; i < 3; i++) smthpt[i] = startpt[i]; if (b->verbose > 1) { printf(" Move to new location (%g, %g, %g).\n", smthpt[0], smthpt[1], smthpt[2]); printf(" Final max L/h = %g. (%d iterations)\n", newTmax, iter); if (key) { printf(" Max. dihed = %g (degree).\n", acos(*key) / PI * 180.0); } } return true; } else { if (b->verbose > 1) { printf(" Not smoothed.\n"); } return false; } } /////////////////////////////////////////////////////////////////////////////// // // // smoothsliver() Remove a sliver by smoothing a vertex of it. // // // // The 'slivtet' represents a sliver abcd, and ab is the current edge which // // has a large dihedral angle (close to 180 degree). // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::smoothsliver(badface* remedge, list *starlist) { triface checktet; point smthpt; bool smthed; int idx, i, j; // Find a Steiner volume point and smooth it. smthed = false; for (i = 0; i < 4 && !smthed; i++) { smthpt = (point) remedge->tt.tet[4 + i]; // Is it a volume point? if (pointtype(smthpt) == FREEVOLVERTEX) { // Is it a Steiner point? idx = pointmark(smthpt) - in->firstnumber; if (!(idx < in->numberofpoints)) { // Smooth a Steiner volume point. starlist->append(&(remedge->tt.tet)); formstarpolyhedron(smthpt, starlist, NULL, false); smthed = smoothpoint(smthpt,NULL,NULL,starlist,false,&remedge->key); // If it is smoothed. Queue new bad tets. if (smthed) { for (j = 0; j < starlist->len(); j++) { checktet = * (triface *)(* starlist)[j]; checktet4opt(&checktet, true); } } starlist->clear(); } } } /* Omit to smooth segment points. This may cause infinite loop. if (smthed) { return true; } face abseg, nextseg, prevseg; point pt[2]; // Check if ab is a segment. tsspivot(slivtet, &abseg); if (abseg.sh == dummysh) { // ab is not a segment. Check if a or b is a Steiner segment point. for (i = 0; i < 2 && !smthed; i++) { smthpt = (i == 0 ? org(*slivtet) : dest(*slivtet)); if (pointtype(smthpt) == FREESEGVERTEX) { // Is it a Steiner point? idx = pointmark(smthpt) - in->firstnumber; if (!(idx < in->numberofpoints)) { // Smooth a Steiner segment point. Get the segment. sdecode(point2sh(smthpt), nextseg); locateseg(smthpt, &nextseg); assert(sorg(nextseg) == smthpt); pt[0] = sdest(nextseg); senext2(nextseg, prevseg); spivotself(prevseg); prevseg.shver = 0; if (sorg(prevseg) == smthpt) sesymself(prevseg); assert(sdest(prevseg) == smthpt); pt[1] = sorg(prevseg); starlist->append(slivtet); formstarpolyhedron(smthpt, starlist, NULL, true); smthed = smoothpoint(smthpt, pt[0], pt[1], starlist, false); // If it is smoothed. Check if the tet is still a sliver. if (smthed) checktet4opt(slivtet, true); starlist->clear(); } } } } */ return smthed; } /////////////////////////////////////////////////////////////////////////////// // // // splitsliver() Remove a sliver by inserting a point. // // // // The 'remedge->tt' represents a sliver abcd, ab is the current edge which // // has a large dihedral angle (close to 180 degree). // // // /////////////////////////////////////////////////////////////////////////////// bool tetgenmesh::splitsliver(badface *remedge, list *tetlist, list *ceillist) { triface starttet; face checkseg; point newpt, pt[4]; bool remflag; int i; // Let 'remedge->tt' be the edge [a, b]. starttet = remedge->tt; // Go to the opposite edge [c, d]. adjustedgering(starttet, CCW); enextfnextself(starttet); enextself(starttet); // Check if cd is a segment. tsspivot(&starttet, &checkseg); if (b->nobisect == 0) { if (checkseg.sh != dummysh) { // cd is a segment. The seg will be split. checkseg.shver = 0; pt[0] = sorg(checkseg); pt[1] = sdest(checkseg); makepoint(&newpt); getsplitpoint(pt[0], pt[1], NULL, newpt); setpointtype(newpt, FREESEGVERTEX); setpoint2seg(newpt, sencode(checkseg)); // Insert p, this should always success. sstpivot(&checkseg, &starttet); splittetedge(newpt, &starttet, NULL); // Collect the new tets connecting at p. sstpivot(&checkseg, &starttet); ceillist->append(&starttet); formstarpolyhedron(newpt, ceillist, NULL, true); setnewpointsize(newpt, pt[0], NULL); if (steinerleft > 0) steinerleft--; // Smooth p. smoothpoint(newpt, pt[0], pt[1], ceillist, false, NULL); // Queue new slivers. for (i = 0; i < ceillist->len(); i++) { starttet = * (triface *)(* ceillist)[i]; checktet4opt(&starttet, true); } ceillist->clear(); return true; } } // Create the new point p (at the circumcenter of t). makepoint(&newpt); /*// Get the four corners. for (i = 0; i < 4; i++) { pt[i] = (point) starttet.tet[4 + i]; } for (i = 0; i < 3; i++) { newpt[i] = 0.25 * (pt[0][i] + pt[1][i] + pt[2][i] + pt[3][i]); }*/ pt[0] = org(starttet); pt[1] = dest(starttet); for (i = 0; i < 3; i++) { newpt[i] = 0.5 * (pt[0][i] + pt[1][i]); } setpointtype(newpt, FREEVOLVERTEX); // Form the Bowyer-Watson cavity of p. remflag = false; infect(starttet); tetlist->append(&starttet); formbowatcavityquad(newpt, tetlist, ceillist); if (trimbowatcavity(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, -1.0)) { // Smooth p. if (smoothpoint( newpt, NULL, NULL, ceillist, false, &remedge->key)) { // Insert p. bowatinsertsite(newpt, NULL, 1, NULL, NULL, &tetlist, &ceillist, NULL, NULL, false, false, false); setnewpointsize(newpt, pt[0], NULL); if (steinerleft > 0) steinerleft--; // Queue new slivers. for (i = 0; i < ceillist->len(); i++) { starttet = * (triface *)(* ceillist)[i]; checktet4opt(&starttet, true); } remflag = true; } // if (smoothpoint) } // if (trimbowatcavity) if (!remflag) { // p is rejected for BC(p) is not valid. pointdealloc(newpt); // Uninfect tets of BC(p). for (i = 0; i < tetlist->len(); i++) { starttet = * (triface *)(* tetlist)[i]; uninfect(starttet); } } tetlist->clear(); ceillist->clear(); return remflag; } /////////////////////////////////////////////////////////////////////////////// // // // tallslivers() Queue all the slivers in the mesh. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::tallslivers(bool optflag) { triface tetloop; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { if (optflag) { checktet4opt(&tetloop, true); } else { checktet4ill(&tetloop, true); } tetloop.tet = tetrahedrontraverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // optimizemesh() Improving the mesh quality. // // // // Available mesh optimizing operations are: (1) multiple edge flips (3-to-2,// // 4-to-4, 5-to-6, etc), (2) free vertex deletion, (3) new vertex insertion. // // (1) is mandatory, while (2) and (3) are optionally. // // // // The variable 'b->optlevel' (set after '-s') determines the use of these // // operations. If it is: 0, do no optimization; 1, only do (1) operation; 2, // // do (1) and (2) operations; 3, do all operations. Deault, b->optlvel = 2. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::optimizemesh2(bool optflag) { list *splittetlist, *tetlist, *ceillist; badface *remtet, *newbadtet; REAL maxdihed, objdihed, cosobjdihed; long oldflipcount, newflipcount; long oldpointcount; int slivercount; int optpasscount; int iter, i; // Cosines of the six dihedral angles of the tet [a, b, c, d]. // From cosdd[0] to cosdd[5]: ab, bc, ca, ad, bd, cd. REAL cosdd[6]; //int j; if (!b->quiet) { if (optflag) { if (b_steinerflag) { // This routine is called from removesteiners2(); } else { printf("Optimizing mesh.\n"); } } else { printf("Repairing mesh.\n"); } } if (optflag) { if (b_steinerflag) { // This routine is called from removesteiners2(); cosmaxdihed = cos(179.0 * PI / 180.0); cosmindihed = cos(1.0 * PI / 180.0); // The radian of the maximum dihedral angle. maxdihed = 179.0 / 180.0 * PI; } else { cosmaxdihed = cos(b->maxdihedral * PI / 180.0); cosmindihed = cos(b->mindihedral * PI / 180.0); // The radian of the maximum dihedral angle. maxdihed = b->maxdihedral / 180.0 * PI; // A sliver has an angle large than 'objdihed' will be split. objdihed = b->maxdihedral + 5.0; if (objdihed < 175.0) objdihed = 175.0; objdihed = objdihed / 180.0 * PI; cosobjdihed = cos(objdihed); } } // Initialize the pool of bad tets. badtetrahedrons = new memorypool(sizeof(badface), ELEPERBLOCK, POINTER, 0); // Looking for non-optimal tets. tallslivers(optflag); oldpointcount = points->items; opt_tet_peels = opt_face_flips = opt_edge_flips = 0l; oldflipcount = newflipcount = 0l; smoothsegverts = 0l; optpasscount = 0; // Start the mesh optimization iteration. do { if (optflag && (b->verbose)) { printf(" level = %d.\n", b->optlevel); } // Improve the mesh quality by flips. iter = 0; do { oldflipcount = newflipcount; // Loop in the list of bad tets. badtetrahedrons->traversalinit(); remtet = badfacetraverse(badtetrahedrons); while (remtet != (badface *) NULL) { if (!isdead(&remtet->tt) && (org(remtet->tt) == remtet->forg) && (dest(remtet->tt) == remtet->fdest) && (apex(remtet->tt) == remtet->fapex) && (oppo(remtet->tt) == remtet->foppo)) { if (b->verbose > 1) { printf(" Repair tet (%d, %d, %d, %d) %g (degree).\n", pointmark(remtet->forg), pointmark(remtet->fdest), pointmark(remtet->fapex), pointmark(remtet->foppo), acos(remtet->key) / PI * 180.0); } if (removeedge(remtet, optflag)) { // Remove the badtet from the list. badfacedealloc(badtetrahedrons, remtet); } } else { // Remove the badtet from the list. badfacedealloc(badtetrahedrons, remtet); } remtet = badfacetraverse(badtetrahedrons); } iter++; if (iter > 10) break; // Stop at 10th iterations. // Count the total number of flips. newflipcount = opt_tet_peels + opt_face_flips + opt_edge_flips; // Continue if there are bad tets and new flips. } while ((badtetrahedrons->items > 0) && (newflipcount > oldflipcount)); if (b_steinerflag) { // This routine was called from removesteiner2(). Do not repair // the bad tets by splitting. badtetrahedrons->restart(); } if ((badtetrahedrons->items > 0l) && optflag && (b->optlevel > 2)) { // Get a list of slivers and try to split them. splittetlist = new list(sizeof(badface), NULL, 256); tetlist = new list(sizeof(triface), NULL, 256); ceillist = new list(sizeof(triface), NULL, 256); // Form a list of slivers to be split and clean the pool. badtetrahedrons->traversalinit(); remtet = badfacetraverse(badtetrahedrons); while (remtet != (badface *) NULL) { splittetlist->append(remtet); remtet = badfacetraverse(badtetrahedrons); } // Clean the pool of bad tets. badtetrahedrons->restart(); slivercount = 0; for (i = 0; i < splittetlist->len(); i++) { remtet = (badface *)(* splittetlist)[i]; if (!isdead(&remtet->tt) && org(remtet->tt) == remtet->forg && dest(remtet->tt) == remtet->fdest && apex(remtet->tt) == remtet->fapex && oppo(remtet->tt) == remtet->foppo) { // Calculate the six dihedral angles of this tet. adjustedgering(remtet->tt, CCW); remtet->forg = org(remtet->tt); remtet->fdest = dest(remtet->tt); remtet->fapex = apex(remtet->tt); remtet->foppo = oppo(remtet->tt); tetalldihedral(remtet->forg, remtet->fdest, remtet->fapex, remtet->foppo, cosdd, NULL, NULL); // Is it a large angle? if (cosdd[0] < cosobjdihed) { slivercount++; remtet->key = cosdd[0]; if (b->verbose > 1) { printf(" Split tet (%d, %d, %d, %d) %g (degree).\n", pointmark(remtet->forg), pointmark(remtet->fdest), pointmark(remtet->fapex), pointmark(remtet->foppo), acos(remtet->key) / PI * 180.0); } /*if (b->verbose && ((acos(cosdd[0]) / PI * 180) > 179)) { // For DEBUG only. printf(" p:draw_tet(%d, %d, %d, %d) -- %d (", pointmark(remtet->forg), pointmark(remtet->fdest), pointmark(remtet->fapex), pointmark(remtet->foppo), slivercount); // Print the 6 dihedral angles. for (j = 0; j < 5; j++) { printf("%4.1f, ", acos(cosdd[j]) / PI * 180.0); } printf("%4.1f)\n", acos(cosdd[5]) / PI * 180.0); }*/ // Queue this tet. newbadtet = (badface *) badtetrahedrons->alloc(); *newbadtet = *remtet; // Try to remove this tet. if (!smoothsliver(remtet, tetlist)) { splitsliver(remtet, tetlist, ceillist); } } } } // i delete splittetlist; delete tetlist; delete ceillist; } optpasscount++; } while ((badtetrahedrons->items > 0) && (optpasscount < b->optpasses)); if (b->verbose) { if (opt_tet_peels > 0l) { printf(" %ld tet removals.\n", opt_tet_peels); } if (opt_face_flips > 0l) { printf(" %ld face flips.\n", opt_face_flips); } if (opt_edge_flips > 0l) { printf(" %ld edge flips.\n", opt_edge_flips); } if ((points->items - oldpointcount) > 0l) { printf(" %ld point insertions", points->items - oldpointcount); if (smoothsegverts > 0) { printf(" (%d on segment)", smoothsegverts); } printf("\n"); } } delete badtetrahedrons; badtetrahedrons = (memorypool *) NULL; } //// //// //// //// //// optimize_cxx ///////////////////////////////////////////////////////////// //// output_cxx /////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // jettisonnodes() Jettison unused or duplicated vertices. // // // // Unused points are those input points which are outside the mesh domain or // // have no connection (isolated) to the mesh. Duplicated points exist for // // example if the input PLC is read from a .stl mesh file (marked during the // // Delaunay tetrahedralization step. This routine remove these points from // // points list. All existing points are reindexed. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::jettisonnodes() { point pointloop; bool jetflag; int oldidx, newidx; int remcount; if (!b->quiet) { printf("Jettisoning redundants points.\n"); } points->traversalinit(); pointloop = pointtraverse(); oldidx = newidx = 0; // in->firstnumber; remcount = 0; while (pointloop != (point) NULL) { jetflag = (pointtype(pointloop) == DUPLICATEDVERTEX) || (pointtype(pointloop) == UNUSEDVERTEX); if (jetflag) { // It is a duplicated point, delete it. pointdealloc(pointloop); remcount++; } else { // Re-index it. setpointmark(pointloop, newidx + in->firstnumber); if (in->pointmarkerlist != (int *) NULL) { if (oldidx < in->numberofpoints) { // Re-index the point marker as well. in->pointmarkerlist[newidx] = in->pointmarkerlist[oldidx]; } } newidx++; } oldidx++; if (oldidx == in->numberofpoints) { // Update the numbe of input points (Because some were removed). in->numberofpoints -= remcount; // Remember this number for output original input nodes. jettisoninverts = remcount; } pointloop = pointtraverse(); } if (b->verbose) { printf(" %d duplicated vertices have been removed.\n", dupverts); printf(" %d unused vertices have been removed.\n", unuverts); } dupverts = 0; unuverts = 0; // The following line ensures that dead items in the pool of nodes cannot // be allocated for the new created nodes. This ensures that the input // nodes will occur earlier in the output files, and have lower indices. points->deaditemstack = (void *) NULL; } /////////////////////////////////////////////////////////////////////////////// // // // highorder() Create extra nodes for quadratic subparametric elements. // // // // 'highordertable' is an array (size = numberoftetrahedra * 6) for storing // // high-order nodes of each tetrahedron. This routine is used only when -o2 // // switch is used. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::highorder() { triface tetloop, worktet; triface spintet, adjtet; point torg, tdest, tapex; point *extralist, *adjextralist; point newpoint; int hitbdry, ptmark; int i, j; if (!b->quiet) { printf("Adding vertices for second-order tetrahedra.\n"); } // Initialize the 'highordertable'. highordertable = new point[tetrahedrons->items * 6]; if (highordertable == (point *) NULL) { terminatetetgen(1); } // The following line ensures that dead items in the pool of nodes cannot // be allocated for the extra nodes associated with high order elements. // This ensures that the primary nodes (at the corners of elements) will // occur earlier in the output files, and have lower indices, than the // extra nodes. points->deaditemstack = (void *) NULL; // Assign an entry for each tetrahedron to find its extra nodes. At the // mean while, initialize all extra nodes be NULL. i = 0; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { tetloop.tet[highorderindex] = (tetrahedron) &highordertable[i]; for (j = 0; j < 6; j++) { highordertable[i + j] = (point) NULL; } i += 6; tetloop.tet = tetrahedrontraverse(); } // To create a unique node on each edge. Loop over all tetrahedra, and // look at the six edges of each tetrahedron. If the extra node in // the tetrahedron corresponding to this edge is NULL, create a node // for this edge, at the same time, set the new node into the extra // node lists of all other tetrahedra sharing this edge. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Get the list of extra nodes. extralist = (point *) tetloop.tet[highorderindex]; worktet.tet = tetloop.tet; for (i = 0; i < 6; i++) { if (extralist[i] == (point) NULL) { // Operate on this edge. worktet.loc = edge2locver[i][0]; worktet.ver = edge2locver[i][1]; // Create a new node on this edge. torg = org(worktet); tdest = dest(worktet); // Create a new node in the middle of the edge. newpoint = (point) points->alloc(); // Interpolate its attributes. for (j = 0; j < 3 + in->numberofpointattributes; j++) { newpoint[j] = 0.5 * (torg[j] + tdest[j]); } ptmark = (int) points->items - (in->firstnumber == 1 ? 0 : 1); setpointmark(newpoint, ptmark); // Add this node to its extra node list. extralist[i] = newpoint; // Set 'newpoint' into extra node lists of other tetrahedra // sharing this edge. tapex = apex(worktet); spintet = worktet; hitbdry = 0; while (hitbdry < 2) { if (fnextself(spintet)) { // Get the extra node list of 'spintet'. adjextralist = (point *) spintet.tet[highorderindex]; // Find the index of its extra node list. j = locver2edge[spintet.loc][spintet.ver]; // Only set 'newpoint' into 'adjextralist' if it is a NULL. // Because two faces can belong to the same tetrahedron. if (adjextralist[j] == (point) NULL) { adjextralist[j] = newpoint; } if (apex(spintet) == tapex) { break; } } else { hitbdry++; if (hitbdry < 2) { esym(worktet, spintet); } } } } } tetloop.tet = tetrahedrontraverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // numberedges() Count the number of edges, save in "meshedges". // // // // This routine is called when '-p' or '-r', and '-E' options are used. The // // total number of edges depends on the genus of the input surface mesh. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::numberedges() { triface tetloop, worktet, spintet; int hitbdry, i; if (!b->plc && !b->refine) { // Using the Euler formula (V-E+F-T=1) to get the total number of edges. long faces = (4l * tetrahedrons->items + hullsize) / 2l; meshedges = points->items + faces - tetrahedrons->items - 1l; return; } meshedges = 0l; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Count the number of Voronoi faces. Look at the six edges of each // tetrahedron. Count the edge only if the tetrahedron's pointer is // smaller than those of all other tetrahedra that share the edge. worktet.tet = tetloop.tet; for (i = 0; i < 6; i++) { worktet.loc = edge2locver[i][0]; worktet.ver = edge2locver[i][1]; adjustedgering(worktet, CW); spintet = worktet; hitbdry = 0; while (hitbdry < 2) { if (fnextself(spintet)) { if (apex(spintet) == apex(worktet)) break; if (spintet.tet < worktet.tet) break; } else { hitbdry++; if (hitbdry < 2) { esym(worktet, spintet); fnextself(spintet); // In the same tet. } } } // Count this edge if no adjacent tets are smaller than this tet. if (spintet.tet >= worktet.tet) { meshedges++; } } tetloop.tet = tetrahedrontraverse(); } } /////////////////////////////////////////////////////////////////////////////// // // // outnodes() Output the points to a .node file or a tetgenio structure. // // // // Note: each point has already been numbered on input (the first index is // // 'in->firstnumber'). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outnodes(tetgenio* out) { FILE *outfile; char outnodefilename[FILENAMESIZE]; shellface subptr; triface adjtet; face subloop; point pointloop; point *extralist, ep[3]; int nextras, bmark, shmark, marker; int coordindex, attribindex; int pointnumber, firstindex; int index, i; if (out == (tetgenio *) NULL) { strcpy(outnodefilename, b->outfilename); strcat(outnodefilename, ".node"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outnodefilename); } else { printf("Writing nodes.\n"); } } nextras = in->numberofpointattributes; bmark = !b->nobound && in->pointmarkerlist; // Avoid compile warnings. outfile = (FILE *) NULL; marker = coordindex = 0; if (out == (tetgenio *) NULL) { outfile = fopen(outnodefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outnodefilename); terminatetetgen(3); } // Number of points, number of dimensions, number of point attributes, // and number of boundary markers (zero or one). fprintf(outfile, "%ld %d %d %d\n", points->items, 3, nextras, bmark); } else { // Allocate space for 'pointlist'; out->pointlist = new REAL[points->items * 3]; if (out->pointlist == (REAL *) NULL) { terminatetetgen(1); } // Allocate space for 'pointattributelist' if necessary; if (nextras > 0) { out->pointattributelist = new REAL[points->items * nextras]; if (out->pointattributelist == (REAL *) NULL) { terminatetetgen(1); } } // Allocate space for 'pointmarkerlist' if necessary; if (bmark) { out->pointmarkerlist = new int[points->items]; if (out->pointmarkerlist == (int *) NULL) { terminatetetgen(1); } } out->numberofpoints = points->items; out->numberofpointattributes = nextras; coordindex = 0; attribindex = 0; } if (bmark && (b->plc || b->refine)) { // Initialize the point2tet field of each point. points->traversalinit(); pointloop = pointtraverse(); while (pointloop != (point) NULL) { setpoint2tet(pointloop, (tetrahedron) NULL); pointloop = pointtraverse(); } // Make a map point-to-subface. Hence a boundary point will get the // facet marker from that facet where it lies on. subfaces->traversalinit(); subloop.sh = shellfacetraverse(subfaces); while (subloop.sh != (shellface *) NULL) { subloop.shver = 0; // Check all three points of the subface. for (i = 0; i < 3; i++) { pointloop = (point) subloop.sh[3 + i]; setpoint2tet(pointloop, (tetrahedron) sencode(subloop)); } if (b->order == 2) { // '-o2' switch. Set markers for quadratic nodes of this subface. stpivot(subloop, adjtet); if (adjtet.tet == dummytet) { sesymself(subloop); stpivot(subloop, adjtet); } assert(adjtet.tet != dummytet); extralist = (point *) adjtet.tet[highorderindex]; switch (adjtet.loc) { case 0: ep[0] = extralist[0]; ep[1] = extralist[1]; ep[2] = extralist[2]; break; case 1: ep[0] = extralist[0]; ep[1] = extralist[4]; ep[2] = extralist[3]; break; case 2: ep[0] = extralist[1]; ep[1] = extralist[5]; ep[2] = extralist[4]; break; case 3: ep[0] = extralist[2]; ep[1] = extralist[3]; ep[2] = extralist[5]; break; default: break; } for (i = 0; i < 3; i++) { setpoint2tet(ep[i], (tetrahedron) sencode(subloop)); } } subloop.sh = shellfacetraverse(subfaces); } } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; points->traversalinit(); pointloop = pointtraverse(); pointnumber = firstindex; // in->firstnumber; index = 0; while (pointloop != (point) NULL) { if (bmark) { // Default the vertex has a zero marker. marker = 0; // Is it an input vertex? if (index < in->numberofpoints) { // Input point's marker is directly copied to output. marker = in->pointmarkerlist[index]; } // Is it a boundary vertex has marker zero? if ((marker == 0) && (b->plc || b->refine)) { subptr = (shellface) point2tet(pointloop); if (subptr != (shellface) NULL) { // Default a boundary vertex has marker 1. marker = 1; if (in->facetmarkerlist != (int *) NULL) { // The vertex gets the marker from the facet it lies on. sdecode(subptr, subloop); shmark = shellmark(subloop); marker = in->facetmarkerlist[shmark - 1]; } } } } if (out == (tetgenio *) NULL) { // Point number, x, y and z coordinates. fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, pointloop[0], pointloop[1], pointloop[2]); for (i = 0; i < nextras; i++) { // Write an attribute. fprintf(outfile, " %.17g", pointloop[3 + i]); } if (bmark) { // Write the boundary marker. fprintf(outfile, " %d", marker); } fprintf(outfile, "\n"); } else { // X, y, and z coordinates. out->pointlist[coordindex++] = pointloop[0]; out->pointlist[coordindex++] = pointloop[1]; out->pointlist[coordindex++] = pointloop[2]; // Point attributes. for (i = 0; i < nextras; i++) { // Output an attribute. out->pointattributelist[attribindex++] = pointloop[3 + i]; } if (bmark) { // Output the boundary marker. out->pointmarkerlist[index] = marker; } } pointloop = pointtraverse(); pointnumber++; index++; } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outmetrics() Output the metric to a file (*.mtr) or a tetgenio obj. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outmetrics(tetgenio* out) { FILE *outfile; char outmtrfilename[FILENAMESIZE]; list *tetlist, *ptlist; triface tetloop; point ptloop, neipt; REAL lave, len; // lmin, lmax, int mtrindex; int i; if (out == (tetgenio *) NULL) { strcpy(outmtrfilename, b->outfilename); strcat(outmtrfilename, ".mtr"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outmtrfilename); } else { printf("Writing metrics.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; mtrindex = 0; if (out == (tetgenio *) NULL) { outfile = fopen(outmtrfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outmtrfilename); terminatetetgen(3); } // Number of points, number of point metrices, // fprintf(outfile, "%ld %d\n", points->items, sizeoftensor + 3); fprintf(outfile, "%ld %d\n", points->items, 1); } else { // Allocate space for 'pointmtrlist' if necessary; // out->pointmtrlist = new REAL[points->items * (sizeoftensor + 3)]; out->pointmtrlist = new REAL[points->items]; if (out->pointmtrlist == (REAL *) NULL) { terminatetetgen(1); } out->numberofpointmtrs = 1; // (sizeoftensor + 3); mtrindex = 0; } // Initialize the point2tet field of each point. points->traversalinit(); ptloop = pointtraverse(); while (ptloop != (point) NULL) { setpoint2tet(ptloop, (tetrahedron) NULL); ptloop = pointtraverse(); } // Create the point-to-tet map. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { for (i = 0; i < 4; i++) { ptloop = (point) tetloop.tet[4 + i]; setpoint2tet(ptloop, encode(tetloop)); } tetloop.tet = tetrahedrontraverse(); } tetlist = new list(sizeof(triface), NULL, 256); ptlist = new list(sizeof(point *), NULL, 256); points->traversalinit(); ptloop = pointtraverse(); while (ptloop != (point) NULL) { decode(point2tet(ptloop), tetloop); if (!isdead(&tetloop)) { // Form the star of p. tetlist->append(&tetloop); formstarpolyhedron(ptloop, tetlist, ptlist, true); // lmin = longest; // lmax = 0.0; lave = 0.0; for (i = 0; i < ptlist->len(); i++) { neipt = * (point *)(* ptlist)[i]; len = distance(ptloop, neipt); // lmin = lmin < len ? lmin : len; // lmax = lmax > len ? lmax : len; lave += len; } lave /= ptlist->len(); } if (out == (tetgenio *) NULL) { // for (i = 0; i < sizeoftensor; i++) { // fprintf(outfile, "%-16.8e ", ptloop[pointmtrindex + i]); // } if (ptlist->len() > 0) { // fprintf(outfile, "%-16.8e %-16.8e %-16.8e", lmin, lmax, lave); fprintf(outfile, "%-16.8e ", lave); } else { fprintf(outfile, "0.0 "); // fprintf(outfile, "0.0 0.0 0.0"); } fprintf(outfile, "\n"); } else { // for (i = 0; i < sizeoftensor; i++) { // out->pointmtrlist[mtrindex++] = ptloop[pointmtrindex + i]; // } if (ptlist->len() > 0) { // out->pointmtrlist[mtrindex++] = lmin; // out->pointmtrlist[mtrindex++] = lmax; out->pointmtrlist[mtrindex++] = lave; } else { // out->pointmtrlist[mtrindex++] = 0.0; // out->pointmtrlist[mtrindex++] = 0.0; out->pointmtrlist[mtrindex++] = 0.0; } } tetlist->clear(); ptlist->clear(); ptloop = pointtraverse(); } delete tetlist; delete ptlist; if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outelements() Output the tetrahedra to an .ele file or a tetgenio // // structure. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outelements(tetgenio* out) { FILE *outfile; char outelefilename[FILENAMESIZE]; tetrahedron* tptr; triface worktet, spintet; int *tlist; REAL *talist; int firstindex, shift; int pointindex; int attribindex; point p1, p2, p3, p4; point *extralist; int elementnumber; int eextras; int hitbdry, i; if (out == (tetgenio *) NULL) { strcpy(outelefilename, b->outfilename); strcat(outelefilename, ".ele"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outelefilename); } else { printf("Writing elements.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; tlist = (int *) NULL; talist = (double *) NULL; pointindex = attribindex = 0; eextras = in->numberoftetrahedronattributes; if (out == (tetgenio *) NULL) { outfile = fopen(outelefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outelefilename); terminatetetgen(3); } // Number of tetras, points per tetra, attributes per tetra. fprintf(outfile, "%ld %d %d\n", tetrahedrons->items, b->order == 1 ? 4 : 10, eextras); } else { // Allocate memory for output tetrahedra. out->tetrahedronlist = new int[tetrahedrons->items * (b->order == 1 ? 4 : 10)]; if (out->tetrahedronlist == (int *) NULL) { terminatetetgen(1); } // Allocate memory for output tetrahedron attributes if necessary. if (eextras > 0) { out->tetrahedronattributelist = new REAL[tetrahedrons->items * eextras]; if (out->tetrahedronattributelist == (REAL *) NULL) { terminatetetgen(1); } } out->numberoftetrahedra = tetrahedrons->items; out->numberofcorners = b->order == 1 ? 4 : 10; out->numberoftetrahedronattributes = eextras; tlist = out->tetrahedronlist; talist = out->tetrahedronattributelist; pointindex = 0; attribindex = 0; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift the output indices by 1. } // Count the total edge numbers. meshedges = 0l; tetrahedrons->traversalinit(); tptr = tetrahedrontraverse(); elementnumber = firstindex; // in->firstnumber; while (tptr != (tetrahedron *) NULL) { if (b->noelewritten == 2) { // Reverse the orientation, such that Orient3D() > 0. p1 = (point) tptr[5]; p2 = (point) tptr[4]; } else { p1 = (point) tptr[4]; p2 = (point) tptr[5]; } p3 = (point) tptr[6]; p4 = (point) tptr[7]; if (out == (tetgenio *) NULL) { // Tetrahedron number, indices for four points. fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, pointmark(p1) - shift, pointmark(p2) - shift, pointmark(p3) - shift, pointmark(p4) - shift); if (b->order == 2) { extralist = (point *) tptr[highorderindex]; // Tetrahedron number, indices for four points plus six extra points. fprintf(outfile, " %5d %5d %5d %5d %5d %5d", pointmark(extralist[0]) - shift, pointmark(extralist[1]) - shift, pointmark(extralist[2]) - shift, pointmark(extralist[3]) - shift, pointmark(extralist[4]) - shift, pointmark(extralist[5]) - shift); } for (i = 0; i < eextras; i++) { fprintf(outfile, " %.17g", elemattribute(tptr, i)); } fprintf(outfile, "\n"); } else { tlist[pointindex++] = pointmark(p1) - shift; tlist[pointindex++] = pointmark(p2) - shift; tlist[pointindex++] = pointmark(p3) - shift; tlist[pointindex++] = pointmark(p4) - shift; if (b->order == 2) { extralist = (point *) tptr[highorderindex]; tlist[pointindex++] = pointmark(extralist[0]) - shift; tlist[pointindex++] = pointmark(extralist[1]) - shift; tlist[pointindex++] = pointmark(extralist[2]) - shift; tlist[pointindex++] = pointmark(extralist[3]) - shift; tlist[pointindex++] = pointmark(extralist[4]) - shift; tlist[pointindex++] = pointmark(extralist[5]) - shift; } for (i = 0; i < eextras; i++) { talist[attribindex++] = elemattribute(tptr, i); } } if (b->neighout) { // Remember the index of this element. * (int *) (tptr + elemmarkerindex) = elementnumber; } // Count the number of Voronoi faces. Look at the six edges of each // tetrahedron. Count the edge only if the tetrahedron's pointer is // smaller than those of all other tetrahedra that share the edge. worktet.tet = tptr; for (i = 0; i < 6; i++) { worktet.loc = edge2locver[i][0]; worktet.ver = edge2locver[i][1]; adjustedgering(worktet, CW); spintet = worktet; hitbdry = 0; while (hitbdry < 2) { if (fnextself(spintet)) { if (apex(spintet) == apex(worktet)) break; if (spintet.tet < worktet.tet) break; } else { hitbdry++; if (hitbdry < 2) { esym(worktet, spintet); fnextself(spintet); // In the same tet. } } } // Count this edge if no adjacent tets are smaller than this tet. if (spintet.tet >= worktet.tet) { meshedges++; } } tptr = tetrahedrontraverse(); elementnumber++; } if (b->neighout) { // Set the outside element marker. * (int *) (dummytet + elemmarkerindex) = -1; } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outfaces() Output all faces to a .face file or a tetgenio structure. // // // // This routines outputs all triangular faces (including outer boundary // // faces and inner faces) of this mesh. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outfaces(tetgenio* out) { FILE *outfile; char facefilename[FILENAMESIZE]; int *elist; int *emlist; int neigh1, neigh2; int index; triface tface, tsymface; face checkmark; point torg, tdest, tapex; long faces; int bmark, faceid, marker; int firstindex, shift; int facenumber; if (out == (tetgenio *) NULL) { strcpy(facefilename, b->outfilename); strcat(facefilename, ".face"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", facefilename); } else { printf("Writing faces.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; elist = (int *) NULL; emlist = (int *) NULL; index = marker = 0; faces = (4l * tetrahedrons->items + hullsize) / 2l; bmark = !b->nobound && in->facetmarkerlist; if (out == (tetgenio *) NULL) { outfile = fopen(facefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", facefilename); terminatetetgen(3); } fprintf(outfile, "%ld %d\n", faces, bmark); } else { // Allocate memory for 'trifacelist'. out->trifacelist = new int[faces * 3]; if (out->trifacelist == (int *) NULL) { terminatetetgen(1); } // Allocate memory for 'trifacemarkerlist' if necessary. if (bmark) { out->trifacemarkerlist = new int[faces]; if (out->trifacemarkerlist == (int *) NULL) { terminatetetgen(1); } } if (b->neighout > 1) { // '-nn' switch. out->adjtetlist = new int[subfaces->items * 2]; if (out->adjtetlist == (int *) NULL) { terminatetetgen(1); } } out->numberoftrifaces = faces; elist = out->trifacelist; emlist = out->trifacemarkerlist; index = 0; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift the output indices by 1. } tetrahedrons->traversalinit(); tface.tet = tetrahedrontraverse(); facenumber = firstindex; // in->firstnumber; // To loop over the set of faces, loop over all tetrahedra, and look at // the four faces of each one. If there isn't another tetrahedron // adjacent to this face, operate on the face. If there is another // adjacent tetrahedron, operate on the face only if the current // tetrahedron has a smaller pointer than its neighbor. This way, each // face is considered only once. while (tface.tet != (tetrahedron *) NULL) { for (tface.loc = 0; tface.loc < 4; tface.loc ++) { sym(tface, tsymface); if ((tsymface.tet == dummytet) || (tface.tet < tsymface.tet)) { torg = org(tface); tdest = dest(tface); tapex = apex(tface); if (bmark) { // Get the boundary marker of this face. If it is an inner face, // it has no boundary marker, set it be zero. if (b->useshelles) { // Shell face is used. tspivot(tface, checkmark); if (checkmark.sh == dummysh) { marker = 0; // It is an inner face. } else { faceid = shellmark(checkmark) - 1; marker = in->facetmarkerlist[faceid]; } } else { // Shell face is not used, only distinguish outer and inner face. marker = tsymface.tet != dummytet ? 1 : 0; } } if (b->neighout > 1) { // '-nn' switch. Output adjacent tets indices. neigh1 = * (int *)(tface.tet + elemmarkerindex); if (tsymface.tet != dummytet) { neigh2 = * (int *)(tsymface.tet + elemmarkerindex); } else { neigh2 = -1; } } if (out == (tetgenio *) NULL) { // Face number, indices of three vertices. fprintf(outfile, "%5d %4d %4d %4d", facenumber, pointmark(torg) - shift, pointmark(tdest) - shift, pointmark(tapex) - shift); if (bmark) { // Output a boundary marker. fprintf(outfile, " %d", marker); } if (b->neighout > 1) { fprintf(outfile, " %5d %5d", neigh1, neigh2); } fprintf(outfile, "\n"); } else { // Output indices of three vertices. elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; elist[index++] = pointmark(tapex) - shift; if (bmark) { emlist[facenumber - in->firstnumber] = marker; } if (b->neighout > 1) { out->adjtetlist[(facenumber - in->firstnumber) * 2] = neigh1; out->adjtetlist[(facenumber - in->firstnumber) * 2 + 1] = neigh2; } } facenumber++; } } tface.tet = tetrahedrontraverse(); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outhullfaces() Output outer boundary faces to a .face file or a // // tetgenio structure. // // // // The normal of each face is arranged to point inside of the domain (use // // right-hand rule). This routines will outputs convex hull faces if the // // mesh is a Delaunay tetrahedralization. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outhullfaces(tetgenio* out) { FILE *outfile; char facefilename[FILENAMESIZE]; int *elist; int index; triface tface, tsymface; face checkmark; point torg, tdest, tapex; int firstindex, shift; int facenumber; if (out == (tetgenio *) NULL) { strcpy(facefilename, b->outfilename); strcat(facefilename, ".face"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", facefilename); } else { printf("Writing faces.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; elist = (int *) NULL; index = 0; if (out == (tetgenio *) NULL) { outfile = fopen(facefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", facefilename); terminatetetgen(3); } fprintf(outfile, "%ld 0\n", hullsize); } else { // Allocate memory for 'trifacelist'. out->trifacelist = new int[hullsize * 3]; if (out->trifacelist == (int *) NULL) { terminatetetgen(1); } out->numberoftrifaces = hullsize; elist = out->trifacelist; index = 0; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift the output indices by 1. } tetrahedrons->traversalinit(); tface.tet = tetrahedrontraverse(); facenumber = firstindex; // in->firstnumber; // To loop over the set of hull faces, loop over all tetrahedra, and look // at the four faces of each one. If there isn't another tetrahedron // adjacent to this face, operate on the face. while (tface.tet != (tetrahedron *) NULL) { for (tface.loc = 0; tface.loc < 4; tface.loc ++) { sym(tface, tsymface); if (tsymface.tet == dummytet) { torg = org(tface); tdest = dest(tface); tapex = apex(tface); if (out == (tetgenio *) NULL) { // Face number, indices of three vertices. fprintf(outfile, "%5d %4d %4d %4d", facenumber, pointmark(torg) - shift, pointmark(tdest) - shift, pointmark(tapex) - shift); fprintf(outfile, "\n"); } else { // Output indices of three vertices. elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; elist[index++] = pointmark(tapex) - shift; } facenumber++; } } tface.tet = tetrahedrontraverse(); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outsubfaces() Output subfaces (i.e. boundary faces) to a .face file or // // a tetgenio structure. // // // // The boundary faces are exist in 'subfaces'. For listing triangle vertices // // in the same sense for all triangles in the mesh, the direction determined // // by right-hand rule is pointer to the inside of the volume. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outsubfaces(tetgenio* out) { FILE *outfile; char facefilename[FILENAMESIZE]; int *elist; int *emlist; int index, index1, index2; triface abuttingtet; face faceloop; point torg, tdest, tapex; int bmark, faceid, marker; int firstindex, shift; int neigh1, neigh2; int facenumber; if (out == (tetgenio *) NULL) { strcpy(facefilename, b->outfilename); strcat(facefilename, ".face"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", facefilename); } else { printf("Writing faces.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; elist = (int *) NULL; emlist = (int *) NULL; index = index1 = index2 = 0; faceid = marker = 0; neigh1 = neigh2 = 0; bmark = !b->nobound && in->facetmarkerlist; if (out == (tetgenio *) NULL) { outfile = fopen(facefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", facefilename); terminatetetgen(3); } // Number of subfaces. fprintf(outfile, "%ld %d\n", subfaces->items, bmark); } else { // Allocate memory for 'trifacelist'. out->trifacelist = new int[subfaces->items * 3]; if (out->trifacelist == (int *) NULL) { terminatetetgen(1); } if (bmark) { // Allocate memory for 'trifacemarkerlist'. out->trifacemarkerlist = new int[subfaces->items]; if (out->trifacemarkerlist == (int *) NULL) { terminatetetgen(1); } } if (b->neighout > 1) { // '-nn' switch. out->adjtetlist = new int[subfaces->items * 2]; if (out->adjtetlist == (int *) NULL) { terminatetetgen(1); } } out->numberoftrifaces = subfaces->items; elist = out->trifacelist; emlist = out->trifacemarkerlist; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift the output indices by 1. } subfaces->traversalinit(); faceloop.sh = shellfacetraverse(subfaces); facenumber = firstindex; // in->firstnumber; while (faceloop.sh != (shellface *) NULL) { stpivot(faceloop, abuttingtet); if (abuttingtet.tet == dummytet) { sesymself(faceloop); stpivot(faceloop, abuttingtet); } if (abuttingtet.tet != dummytet) { // If there is a tetrahedron containing this subface, orient it so // that the normal of this face points to inside of the volume by // right-hand rule. adjustedgering(abuttingtet, CCW); torg = org(abuttingtet); tdest = dest(abuttingtet); tapex = apex(abuttingtet); } else { // This may happen when only a surface mesh be generated. torg = sorg(faceloop); tdest = sdest(faceloop); tapex = sapex(faceloop); } if (bmark) { faceid = shellmark(faceloop) - 1; marker = in->facetmarkerlist[faceid]; } if (b->neighout > 1) { // '-nn' switch. Output adjacent tets indices. neigh1 = -1; stpivot(faceloop, abuttingtet); if (abuttingtet.tet != dummytet) { neigh1 = * (int *)(abuttingtet.tet + elemmarkerindex); } neigh2 = -1; sesymself(faceloop); stpivot(faceloop, abuttingtet); if (abuttingtet.tet != dummytet) { neigh2 = * (int *)(abuttingtet.tet + elemmarkerindex); } } if (out == (tetgenio *) NULL) { fprintf(outfile, "%5d %4d %4d %4d", facenumber, pointmark(torg) - shift, pointmark(tdest) - shift, pointmark(tapex) - shift); if (bmark) { fprintf(outfile, " %d", marker); } if (b->neighout > 1) { fprintf(outfile, " %5d %5d", neigh1, neigh2); } fprintf(outfile, "\n"); } else { // Output three vertices of this face; elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; elist[index++] = pointmark(tapex) - shift; if (bmark) { emlist[index1++] = marker; } if (b->neighout > 1) { out->adjtetlist[index2++] = neigh1; out->adjtetlist[index2++] = neigh2; } } facenumber++; faceloop.sh = shellfacetraverse(subfaces); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outedges() Output all edges to a .edge file or a structure. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outedges(tetgenio* out) { FILE *outfile; char edgefilename[FILENAMESIZE]; int *elist, *emlist; int index, index1; triface tetloop, worktet, spintet; face checkseg; point torg, tdest; int firstindex, shift; int edgenumber, faceid, marker; int hitbdry, i; if (out == (tetgenio *) NULL) { strcpy(edgefilename, b->outfilename); strcat(edgefilename, ".edge"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", edgefilename); } else { printf("Writing edges.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; elist = (int *) NULL; emlist = (int *) NULL; index = index1 = 0; faceid = marker = 0; if (out == (tetgenio *) NULL) { outfile = fopen(edgefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", edgefilename); terminatetetgen(3); } // Write the number of edges, boundary markers (0 or 1). fprintf(outfile, "%ld %d\n", meshedges, !b->nobound); } else { // Allocate memory for 'edgelist'. out->edgelist = new int[meshedges * 2]; if (out->edgelist == (int *) NULL) { terminatetetgen(1); } if (!b->nobound) { out->edgemarkerlist = new int[meshedges]; } out->numberofedges = meshedges; elist = out->edgelist; emlist = out->edgemarkerlist; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift (reduce) the output indices by 1. } tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); edgenumber = firstindex; // in->firstnumber; while (tetloop.tet != (tetrahedron *) NULL) { // Count the number of Voronoi faces. Look at the six edges of each // tetrahedron. Count the edge only if the tetrahedron's pointer is // smaller than those of all other tetrahedra that share the edge. worktet.tet = tetloop.tet; for (i = 0; i < 6; i++) { worktet.loc = edge2locver[i][0]; worktet.ver = edge2locver[i][1]; adjustedgering(worktet, CW); spintet = worktet; hitbdry = 0; while (hitbdry < 2) { if (fnextself(spintet)) { if (apex(spintet) == apex(worktet)) break; if (spintet.tet < worktet.tet) break; } else { hitbdry++; if (hitbdry < 2) { esym(worktet, spintet); fnextself(spintet); // In the same tet. } } } // Count this edge if no adjacent tets are smaller than this tet. if (spintet.tet >= worktet.tet) { torg = org(worktet); tdest = dest(worktet); if (out == (tetgenio *) NULL) { fprintf(outfile, "%5d %4d %4d", edgenumber, pointmark(torg) - shift, pointmark(tdest) - shift); } else { // Output three vertices of this face; elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; } if (!b->nobound) { // Check if the edge is a segment. tsspivot(&worktet, &checkseg); if (checkseg.sh != dummysh) { marker = shellmark(checkseg); if (marker == 0) { // Does it have no marker? marker = 1; // Set the default marker for this segment. } } else { marker = 0; // It's not a segment. } if (out == (tetgenio *) NULL) { fprintf(outfile, " %d", marker); } else { emlist[index1++] = marker; } } if (out == (tetgenio *) NULL) { fprintf(outfile, "\n"); } edgenumber++; } } tetloop.tet = tetrahedrontraverse(); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outsubsegments() Output segments to a .edge file or a structure. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outsubsegments(tetgenio* out) { FILE *outfile; char edgefilename[FILENAMESIZE]; int *elist; int index; face edgeloop; point torg, tdest; int firstindex, shift; int edgenumber; if (out == (tetgenio *) NULL) { strcpy(edgefilename, b->outfilename); strcat(edgefilename, ".edge"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", edgefilename); } else { printf("Writing edges.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; elist = (int *) NULL; index = 0; if (out == (tetgenio *) NULL) { outfile = fopen(edgefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", edgefilename); terminatetetgen(3); } // Number of subsegments. fprintf(outfile, "%ld\n", subsegs->items); } else { // Allocate memory for 'edgelist'. out->edgelist = new int[subsegs->items * 2]; if (out->edgelist == (int *) NULL) { terminatetetgen(1); } out->numberofedges = subsegs->items; elist = out->edgelist; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift the output indices by 1. } subsegs->traversalinit(); edgeloop.sh = shellfacetraverse(subsegs); edgenumber = firstindex; // in->firstnumber; while (edgeloop.sh != (shellface *) NULL) { torg = sorg(edgeloop); tdest = sdest(edgeloop); if (out == (tetgenio *) NULL) { fprintf(outfile, "%5d %4d %4d\n", edgenumber, pointmark(torg) - shift, pointmark(tdest) - shift); } else { // Output three vertices of this face; elist[index++] = pointmark(torg) - shift; elist[index++] = pointmark(tdest) - shift; } edgenumber++; edgeloop.sh = shellfacetraverse(subsegs); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outneighbors() Output tet neighbors to a .neigh file or a structure. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outneighbors(tetgenio* out) { FILE *outfile; char neighborfilename[FILENAMESIZE]; int *nlist; int index; triface tetloop, tetsym; int neighbor1, neighbor2, neighbor3, neighbor4; int firstindex; int elementnumber; if (out == (tetgenio *) NULL) { strcpy(neighborfilename, b->outfilename); strcat(neighborfilename, ".neigh"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", neighborfilename); } else { printf("Writing neighbors.\n"); } } // Avoid compile warnings. outfile = (FILE *) NULL; nlist = (int *) NULL; index = 0; if (out == (tetgenio *) NULL) { outfile = fopen(neighborfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", neighborfilename); terminatetetgen(3); } // Number of tetrahedra, four faces per tetrahedron. fprintf(outfile, "%ld %d\n", tetrahedrons->items, 4); } else { // Allocate memory for 'neighborlist'. out->neighborlist = new int[tetrahedrons->items * 4]; if (out->neighborlist == (int *) NULL) { terminatetetgen(1); } nlist = out->neighborlist; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); elementnumber = firstindex; // in->firstnumber; while (tetloop.tet != (tetrahedron *) NULL) { tetloop.loc = 2; sym(tetloop, tetsym); neighbor1 = * (int *) (tetsym.tet + elemmarkerindex); tetloop.loc = 3; sym(tetloop, tetsym); neighbor2 = * (int *) (tetsym.tet + elemmarkerindex); tetloop.loc = 1; sym(tetloop, tetsym); neighbor3 = * (int *) (tetsym.tet + elemmarkerindex); tetloop.loc = 0; sym(tetloop, tetsym); neighbor4 = * (int *) (tetsym.tet + elemmarkerindex); if (out == (tetgenio *) NULL) { // Tetrahedra number, neighboring tetrahedron numbers. fprintf(outfile, "%4d %4d %4d %4d %4d\n", elementnumber, neighbor1, neighbor2, neighbor3, neighbor4); } else { nlist[index++] = neighbor1; nlist[index++] = neighbor2; nlist[index++] = neighbor3; nlist[index++] = neighbor4; } tetloop.tet = tetrahedrontraverse(); elementnumber++; } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outvoronoi() Output the Voronoi diagram to .v.node, .v.edge, v.face, // // and .v.cell. // // // // The Voronoi diagram is the geometric dual of the Delaunay triangulation. // // The Voronoi vertices are the circumcenters of Delaunay tetrahedra. Each // // Voronoi edge connects two Voronoi vertices at two sides of a common Dela- // // unay face. At a face of convex hull, it becomes a ray (goto the infinity).// // A Voronoi face is the convex hull of all Voronoi vertices around a common // // Delaunay edge. It is a closed polygon for any interal Delaunay edge. At a // // ridge, it is unbounded. Each Voronoi cell is the convex hull of all Vor- // // onoi vertices around a common Delaunay vertex. It is a polytope for any // // internal Delaunay vertex. It is an unbounded polyhedron for a Delaunay // // vertex belonging to the convex hull. // // // // Comment: Special thanks to Victor Liu for finding and fixing few bugs. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outvoronoi(tetgenio* out) { FILE *outfile; char outfilename[FILENAMESIZE]; tetgenio::voroedge *vedge; tetgenio::vorofacet *vfacet; list *tetlist, *ptlist; triface tetloop, worktet, spintet; point pt[4], ptloop, neipt; REAL ccent[3], infvec[3], vec1[3], vec2[3], L; long faces, edges; int *tetfaceindexarray, *tetedgeindexarray; int arraysize, *vertarray; int vpointcount, vedgecount, vfacecount, tcount; int index, shift; int end1, end2; int hitbdry, i, j, k; // Output Voronoi vertices to .v.node file. if (out == (tetgenio *) NULL) { strcpy(outfilename, b->outfilename); strcat(outfilename, ".v.node"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outfilename); } else { printf("Writing Voronoi vertices.\n"); } } // Determine the first index (0 or 1). shift = (b->zeroindex ? 0 : in->firstnumber); // The number of Delaunay faces (= the number of Voronoi edges). faces = (4l * tetrahedrons->items + hullsize) / 2l; // The number of Delaunay edges (= the number of Voronoi faces). // edges = points->items + faces - tetrahedrons->items - 1; edges = meshedges; outfile = (FILE *) NULL; // Avoid compile warnings. if (out == (tetgenio *) NULL) { outfile = fopen(outfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outfilename); terminatetetgen(3); } // Number of voronoi points, 3 dim, no attributes, no marker. fprintf(outfile, "%ld 3 0 0\n", tetrahedrons->items); } else { // Allocate space for 'vpointlist'. out->numberofvpoints = (int) tetrahedrons->items; out->vpointlist = new REAL[out->numberofvpoints * 3]; if (out->vpointlist == (REAL *) NULL) { terminatetetgen(1); } } // Loop the tetrahedronlist once, do the following: // (1) Output Voronoi vertices (the circumcenter of the tetrahedron). // (2) Make a map from points-to-tetrahedra (for Voronoi cells). tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); vpointcount = 0; index = 0; while (tetloop.tet != (tetrahedron *) NULL) { // Calculate the circumcenter. for (i = 0; i < 4; i++) { pt[i] = (point) tetloop.tet[4 + i]; setpoint2tet(pt[i], encode(tetloop)); } circumsphere(pt[0], pt[1], pt[2], pt[3], ccent, NULL); if (out == (tetgenio *) NULL) { fprintf(outfile, "%4d %16.8e %16.8e %16.8e\n", vpointcount + shift, ccent[0], ccent[1], ccent[2]); } else { out->vpointlist[index++] = ccent[0]; out->vpointlist[index++] = ccent[1]; out->vpointlist[index++] = ccent[2]; } // Remember the index of this element. * (int *) (tetloop.tet + elemmarkerindex) = vpointcount; vpointcount++; tetloop.tet = tetrahedrontraverse(); } // Set the outside element marker. * (int *) (dummytet + elemmarkerindex) = -1; if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } // Output Voronoi edges to .v.edge file. if (out == (tetgenio *) NULL) { strcpy(outfilename, b->outfilename); strcat(outfilename, ".v.edge"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outfilename); } else { printf("Writing Voronoi edges.\n"); } } if (out == (tetgenio *) NULL) { outfile = fopen(outfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outfilename); terminatetetgen(3); } // Number of Voronoi edges, no marker. fprintf(outfile, "%ld 0\n", faces); } else { // Allocate space for 'vpointlist'. out->numberofvedges = (int) faces; out->vedgelist = new tetgenio::voroedge[out->numberofvedges]; } // Loop the tetrahedronlist once, output the Voronoi edges. The index of // each Voronoi edge corresponding to the index of the Delaunay face. // The four faces' indices of each tetrahedron are saved in the list // 'tetfaceindexarray', in the entry of i, where i (0-based) is the // index of this tetrahedron (= vpointcount). tetfaceindexarray = new int[tetrahedrons->items * 4]; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); vedgecount = 0; index = 0; while (tetloop.tet != (tetrahedron *) NULL) { // Count the number of Voronoi edges. Look at the four faces of each // tetrahedron. Count the face if the tetrahedron's pointer is // smaller than its neighbor's or the neighbor is outside. end1 = * (int *) (tetloop.tet + elemmarkerindex); for (i = 0; i < 4; i++) { decode(tetloop.tet[i], worktet); if ((worktet.tet == dummytet) || (tetloop.tet < worktet.tet)) { if (out == (tetgenio *) NULL) { fprintf(outfile, "%4d %4d", vedgecount + shift, end1 + shift); } else { vedge = &(out->vedgelist[index++]); vedge->v1 = end1 + shift; } end2 = * (int *) (worktet.tet + elemmarkerindex); // Note that end2 may be -1 (worktet.tet is outside). if (end2 == -1) { // Calculate the out normal of this hull face. worktet.tet = tetloop.tet; worktet.loc = i; worktet.ver = 1; // The CW edge ring. pt[0] = org(worktet); pt[1] = dest(worktet); pt[2] = apex(worktet); for (j = 0; j < 3; j++) vec1[j] = pt[1][j] - pt[0][j]; for (j = 0; j < 3; j++) vec2[j] = pt[2][j] - pt[0][j]; cross(vec1, vec2, infvec); // Normalize it. L = sqrt(infvec[0] * infvec[0] + infvec[1] * infvec[1] + infvec[2] * infvec[2]); if (L > 0) for (j = 0; j < 3; j++) infvec[j] /= L; if (out == (tetgenio *) NULL) { fprintf(outfile, " -1"); fprintf(outfile, " %g %g %g\n", infvec[0], infvec[1], infvec[2]); } else { vedge->v2 = -1; vedge->vnormal[0] = infvec[0]; vedge->vnormal[1] = infvec[1]; vedge->vnormal[2] = infvec[2]; } } else { if (out == (tetgenio *) NULL) { fprintf(outfile, " %4d\n", end2 + shift); } else { vedge->v2 = end2 + shift; vedge->vnormal[0] = 0.0; vedge->vnormal[1] = 0.0; vedge->vnormal[2] = 0.0; } } // Save the face index in this tet and its neighbor if exists. tetfaceindexarray[end1 * 4 + i] = vedgecount; if (end2 != -1) { tetfaceindexarray[end2 * 4 + worktet.loc] = vedgecount; } vedgecount++; } } tetloop.tet = tetrahedrontraverse(); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } // Output Voronoi faces to .v.face file. if (out == (tetgenio *) NULL) { strcpy(outfilename, b->outfilename); strcat(outfilename, ".v.face"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outfilename); } else { printf("Writing Voronoi faces.\n"); } } if (out == (tetgenio *) NULL) { outfile = fopen(outfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outfilename); terminatetetgen(3); } // Number of Voronoi faces. fprintf(outfile, "%ld 0\n", edges); } else { out->numberofvfacets = edges; out->vfacetlist = new tetgenio::vorofacet[out->numberofvfacets]; if (out->vfacetlist == (tetgenio::vorofacet *) NULL) { terminatetetgen(1); } } // Loop the tetrahedronlist once, Output Voronoi facets. The index of each // Voronoi facet corresponding to the index of the Delaunay edge. The // six edges' indices of each tetrahedron are saved in the list 'tetedge- // indexarray', in the entry of i, where i (0-based) is the index of // this tetrahedron (= vpointcount). tetedgeindexarray = new int[tetrahedrons->items * 6]; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); vfacecount = 0; while (tetloop.tet != (tetrahedron *) NULL) { // Count the number of Voronoi faces. Look at the six edges of each // tetrahedron. Count the edge only if the tetrahedron's pointer is // smaller than those of all other tetrahedra that share the edge. worktet = tetloop; for (i = 0; i < 6; i++) { worktet.loc = edge2locver[i][0]; worktet.ver = edge2locver[i][1]; // Now count the number of tets surrounding this edge. tcount = 1; adjustedgering(worktet, CW); spintet = worktet; hitbdry = 0; while (hitbdry < 2) { if (fnextself(spintet)) { if (apex(spintet) == apex(worktet)) break; if (spintet.tet < worktet.tet) break; tcount++; } else { hitbdry++; if (hitbdry < 2) { esym(worktet, spintet); fnextself(spintet); // In the same tet. } } } // Count this edge if no adjacent tets are smaller than this tet. if (spintet.tet >= worktet.tet) { // Get the two endpoints of this edge. pt[0] = org(worktet); pt[1] = dest(worktet); end1 = pointmark(pt[0]) - in->firstnumber; end2 = pointmark(pt[1]) - in->firstnumber; if (out == (tetgenio *) NULL) { fprintf(outfile, "%4d %4d %4d %-2d ", vfacecount + shift, end1 + shift, end2 + shift, tcount + (hitbdry > 0)); } else { vfacet = &(out->vfacetlist[vfacecount]); vfacet->c1 = end1 + shift; vfacet->c2 = end2 + shift; vfacet->elist = new int[tcount + (hitbdry > 0) + 1]; vfacet->elist[0] = tcount + (hitbdry > 0); index = 1; } // If hitbdry > 0, then spintet is a hull face. if (hitbdry > 0) { // The edge list starts with a ray. vpointcount = * (int *) (spintet.tet + elemmarkerindex); vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc]; if (out == (tetgenio *) NULL) { fprintf(outfile, " %d", vedgecount + shift); } else { vfacet->elist[index++] = vedgecount + shift; } // Save this facet number in tet. tetedgeindexarray[vpointcount * 6 + locver2edge[spintet.loc][spintet.ver]] = vfacecount; esymself(spintet); fnextself(spintet); // In the same tet. } // Output internal Voronoi edges. for (j = 0; j < tcount; j++) { vpointcount = * (int *) (spintet.tet + elemmarkerindex); vedgecount = tetfaceindexarray[vpointcount * 4 + spintet.loc]; if (out == (tetgenio *) NULL) { fprintf(outfile, " %d", vedgecount + shift); } else { vfacet->elist[index++] = vedgecount + shift; } // Save this facet number in tet. tetedgeindexarray[vpointcount * 6 + locver2edge[spintet.loc][spintet.ver]] = vfacecount; fnextself(spintet); } if (out == (tetgenio *) NULL) { fprintf(outfile, "\n"); } vfacecount++; } } // if (i = 0; i < 6; i++) tetloop.tet = tetrahedrontraverse(); } if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } // Output Voronoi cells to .v.cell file. if (out == (tetgenio *) NULL) { strcpy(outfilename, b->outfilename); strcat(outfilename, ".v.cell"); } if (!b->quiet) { if (out == (tetgenio *) NULL) { printf("Writing %s.\n", outfilename); } else { printf("Writing Voronoi cells.\n"); } } if (out == (tetgenio *) NULL) { outfile = fopen(outfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", outfilename); terminatetetgen(3); } // Number of Voronoi cells. fprintf(outfile, "%ld\n", points->items); } else { out->numberofvcells = points->items; out->vcelllist = new int*[out->numberofvcells]; if (out->vcelllist == (int **) NULL) { terminatetetgen(1); } } // Loop through point list, for each point, output a Voronoi cell. tetlist = new list(sizeof(triface), NULL, 256); ptlist = new list(sizeof(point *), NULL, 256); points->traversalinit(); ptloop = pointtraverse(); vpointcount = 0; while (ptloop != (point) NULL) { decode(point2tet(ptloop), tetloop); // assert(!isdead(&tetloop)); if (!isdead(&tetloop)) { // Form the star of p. tetlist->append(&tetloop); formstarpolyhedron(ptloop, tetlist, ptlist, true); tcount = ptlist->len(); if (out == (tetgenio *) NULL) { fprintf(outfile, "%4d %-2d ", vpointcount + shift, tcount); } else { arraysize = tcount; vertarray = new int[arraysize + 1]; out->vcelllist[vpointcount] = vertarray; vertarray[0] = arraysize; index = 1; } // List Voronoi facets bounding this cell. for (i = 0; i < ptlist->len(); i++) { neipt = * (point *)(* ptlist)[i]; // Find a tet in tetlist having edge (ptloop, neipt) -- Very Slow. for (j = 0; j < tetlist->len(); j++) { tetloop = * (triface *)(* tetlist)[j]; for (k = 0; k < 6; k++) { tetloop.loc = edge2locver[k][0]; tetloop.ver = edge2locver[k][1]; if (org(tetloop) == ptloop) { if (dest(tetloop) == neipt) break; } else if (org(tetloop) == neipt) { if (dest(tetloop) == ptloop) break; } } if (k < 6) break; // Found this edge. } assert(j < tetlist->len()); // k is the right edge number. end1 = * (int *) (tetloop.tet + elemmarkerindex); vfacecount = tetedgeindexarray[end1 * 6 + k]; if (out == (tetgenio *) NULL) { fprintf(outfile, " %d", vfacecount + shift); } else { vertarray[index++] = vfacecount + shift; } } // for (i = 0; i < ptlist->len(); i++) { if (out == (tetgenio *) NULL) { fprintf(outfile, "\n"); } vpointcount++; } tetlist->clear(); ptlist->clear(); ptloop = pointtraverse(); } delete tetlist; delete ptlist; delete [] tetfaceindexarray; delete [] tetedgeindexarray; if (out == (tetgenio *) NULL) { fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } } /////////////////////////////////////////////////////////////////////////////// // // // outsmesh() Write surface mesh to a .smesh file, which can be read and // // tetrahedralized by TetGen. // // // // You can specify a filename (without suffix) in 'smfilename'. If you don't // // supply a filename (let smfilename be NULL), the default name stored in // // 'tetgenbehavior' will be used. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outsmesh(char* smfilename) { FILE *outfile; char nodfilename[FILENAMESIZE]; char smefilename[FILENAMESIZE]; face faceloop; point p1, p2, p3; int firstindex, shift; int bmark; int faceid, marker; int i; if (smfilename != (char *) NULL && smfilename[0] != '\0') { strcpy(smefilename, smfilename); } else if (b->outfilename[0] != '\0') { strcpy(smefilename, b->outfilename); } else { strcpy(smefilename, "unnamed"); } strcpy(nodfilename, smefilename); strcat(smefilename, ".smesh"); strcat(nodfilename, ".node"); if (!b->quiet) { printf("Writing %s.\n", smefilename); } outfile = fopen(smefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", smefilename); return; } // Determine the first index (0 or 1). firstindex = b->zeroindex ? 0 : in->firstnumber; shift = 0; // Default no shiftment. if ((in->firstnumber == 1) && (firstindex == 0)) { shift = 1; // Shift the output indices by 1. } fprintf(outfile, "# %s. TetGen's input file.\n", smefilename); fprintf(outfile, "\n# part 1: node list.\n"); fprintf(outfile, "0 3 0 0 # nodes are found in %s.\n", nodfilename); marker = 0; // avoid compile warning. bmark = !b->nobound && in->facetmarkerlist; fprintf(outfile, "\n# part 2: facet list.\n"); // Number of facets, boundary marker. fprintf(outfile, "%ld %d\n", subfaces->items, bmark); subfaces->traversalinit(); faceloop.sh = shellfacetraverse(subfaces); while (faceloop.sh != (shellface *) NULL) { p1 = sorg(faceloop); p2 = sdest(faceloop); p3 = sapex(faceloop); if (bmark) { faceid = shellmark(faceloop) - 1; if (faceid >= 0) { marker = in->facetmarkerlist[faceid]; } else { marker = 0; // This subface must be added manually later. } } fprintf(outfile, "3 %4d %4d %4d", pointmark(p1) - shift, pointmark(p2) - shift, pointmark(p3) - shift); if (bmark) { fprintf(outfile, " %d", marker); } fprintf(outfile, "\n"); faceloop.sh = shellfacetraverse(subfaces); } // Copy input holelist. fprintf(outfile, "\n# part 3: hole list.\n"); fprintf(outfile, "%d\n", in->numberofholes); for (i = 0; i < in->numberofholes; i++) { fprintf(outfile, "%d %g %g %g\n", i + in->firstnumber, in->holelist[i * 3], in->holelist[i * 3 + 1], in->holelist[i * 3 + 2]); } // Copy input regionlist. fprintf(outfile, "\n# part 4: region list.\n"); fprintf(outfile, "%d\n", in->numberofregions); for (i = 0; i < in->numberofregions; i++) { fprintf(outfile, "%d %g %g %g %d %g\n", i + in->firstnumber, in->regionlist[i * 5], in->regionlist[i * 5 + 1], in->regionlist[i * 5 + 2], (int) in->regionlist[i * 5 + 3], in->regionlist[i * 5 + 4]); } fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } /////////////////////////////////////////////////////////////////////////////// // // // outmesh2medit() Write mesh to a .mesh file, which can be read and // // rendered by Medit (a free mesh viewer from INRIA). // // // // You can specify a filename (without suffix) in 'mfilename'. If you don't // // supply a filename (let mfilename be NULL), the default name stored in // // 'tetgenbehavior' will be used. The output file will have the suffix .mesh.// // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outmesh2medit(char* mfilename) { FILE *outfile; char mefilename[FILENAMESIZE]; tetrahedron* tetptr; triface tface, tsymface; face segloop, checkmark; point ptloop, p1, p2, p3, p4; long faces; int pointnumber; int i; if (mfilename != (char *) NULL && mfilename[0] != '\0') { strcpy(mefilename, mfilename); } else if (b->outfilename[0] != '\0') { strcpy(mefilename, b->outfilename); } else { strcpy(mefilename, "unnamed"); } strcat(mefilename, ".mesh"); if (!b->quiet) { printf("Writing %s.\n", mefilename); } outfile = fopen(mefilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", mefilename); return; } fprintf(outfile, "MeshVersionFormatted 1\n"); fprintf(outfile, "\n"); fprintf(outfile, "Dimension\n"); fprintf(outfile, "3\n"); fprintf(outfile, "\n"); fprintf(outfile, "\n# Set of mesh vertices\n"); fprintf(outfile, "Vertices\n"); fprintf(outfile, "%ld\n", points->items); points->traversalinit(); ptloop = pointtraverse(); pointnumber = 1; // Medit need start number form 1. while (ptloop != (point) NULL) { // Point coordinates. fprintf(outfile, "%.17g %.17g %.17g", ptloop[0], ptloop[1], ptloop[2]); if (in->numberofpointattributes > 0) { // Write an attribute, ignore others if more than one. fprintf(outfile, " %.17g\n", ptloop[3]); } else { fprintf(outfile, " 0\n"); } setpointmark(ptloop, pointnumber); ptloop = pointtraverse(); pointnumber++; } // Compute the number of edges. faces = (4l * tetrahedrons->items + hullsize) / 2l; fprintf(outfile, "\n# Set of Triangles\n"); fprintf(outfile, "Triangles\n"); fprintf(outfile, "%ld\n", faces); tetrahedrons->traversalinit(); tface.tet = tetrahedrontraverse(); // To loop over the set of faces, loop over all tetrahedra, and look at // the four faces of each tetrahedron. If there isn't another tetrahedron // adjacent to the face, operate on the face. If there is another adj- // acent tetrahedron, operate on the face only if the current tetrahedron // has a smaller pointer than its neighbor. This way, each face is // considered only once. while (tface.tet != (tetrahedron *) NULL) { for (tface.loc = 0; tface.loc < 4; tface.loc ++) { sym(tface, tsymface); if (tface.tet < tsymface.tet || tsymface.tet == dummytet) { p1 = org (tface); p2 = dest(tface); p3 = apex(tface); fprintf(outfile, "%5d %5d %5d", pointmark(p1), pointmark(p2), pointmark(p3)); fprintf(outfile, " 0\n"); } } tface.tet = tetrahedrontraverse(); } fprintf(outfile, "\n# Set of Tetrahedra\n"); fprintf(outfile, "Tetrahedra\n"); fprintf(outfile, "%ld\n", tetrahedrons->items); tetrahedrons->traversalinit(); tetptr = tetrahedrontraverse(); while (tetptr != (tetrahedron *) NULL) { p1 = (point) tetptr[4]; p2 = (point) tetptr[5]; p3 = (point) tetptr[6]; p4 = (point) tetptr[7]; fprintf(outfile, "%5d %5d %5d %5d", pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); if (in->numberoftetrahedronattributes > 0) { fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); } else { fprintf(outfile, " 0"); } fprintf(outfile, "\n"); tetptr = tetrahedrontraverse(); } fprintf(outfile, "\nCorners\n"); fprintf(outfile, "%d\n", in->numberofpoints); for (i = 0; i < in->numberofpoints; i++) { fprintf(outfile, "%4d\n", i + 1); } if (b->useshelles) { fprintf(outfile, "\nEdges\n"); fprintf(outfile, "%ld\n", subsegs->items); subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { p1 = sorg(segloop); p2 = sdest(segloop); fprintf(outfile, "%5d %5d", pointmark(p1), pointmark(p2)); fprintf(outfile, " 0\n"); segloop.sh = shellfacetraverse(subsegs); } } fprintf(outfile, "\nEnd\n"); fclose(outfile); } /////////////////////////////////////////////////////////////////////////////// // // // outmesh2gid() Write mesh to a .ele.msh file and a .face.msh file, // // which can be imported and rendered by Gid. // // // // You can specify a filename (without suffix) in 'gfilename'. If you don't // // supply a filename (let gfilename be NULL), the default name stored in // // 'tetgenbehavior' will be used. The suffixes (.ele.msh and .face.msh) will // // be automatically added. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outmesh2gid(char* gfilename) { FILE *outfile; char gidfilename[FILENAMESIZE]; tetrahedron* tetptr; triface tface, tsymface; face sface; point ptloop, p1, p2, p3, p4; int pointnumber; int elementnumber; if (gfilename != (char *) NULL && gfilename[0] != '\0') { strcpy(gidfilename, gfilename); } else if (b->outfilename[0] != '\0') { strcpy(gidfilename, b->outfilename); } else { strcpy(gidfilename, "unnamed"); } strcat(gidfilename, ".ele.msh"); if (!b->quiet) { printf("Writing %s.\n", gidfilename); } outfile = fopen(gidfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", gidfilename); return; } fprintf(outfile, "mesh dimension = 3 elemtype tetrahedron nnode = 4\n"); fprintf(outfile, "coordinates\n"); points->traversalinit(); ptloop = pointtraverse(); pointnumber = 1; // Gid need start number form 1. while (ptloop != (point) NULL) { // Point coordinates. fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, ptloop[0], ptloop[1], ptloop[2]); if (in->numberofpointattributes > 0) { // Write an attribute, ignore others if more than one. fprintf(outfile, " %.17g", ptloop[3]); } fprintf(outfile, "\n"); setpointmark(ptloop, pointnumber); ptloop = pointtraverse(); pointnumber++; } fprintf(outfile, "end coordinates\n"); fprintf(outfile, "elements\n"); tetrahedrons->traversalinit(); tetptr = tetrahedrontraverse(); elementnumber = 1; while (tetptr != (tetrahedron *) NULL) { p1 = (point) tetptr[4]; p2 = (point) tetptr[5]; p3 = (point) tetptr[6]; p4 = (point) tetptr[7]; fprintf(outfile, "%5d %5d %5d %5d %5d", elementnumber, pointmark(p1), pointmark(p2), pointmark(p3), pointmark(p4)); if (in->numberoftetrahedronattributes > 0) { fprintf(outfile, " %.17g", elemattribute(tetptr, 0)); } fprintf(outfile, "\n"); tetptr = tetrahedrontraverse(); elementnumber++; } fprintf(outfile, "end elements\n"); fclose(outfile); if (gfilename != (char *) NULL && gfilename[0] != '\0') { strcpy(gidfilename, gfilename); } else if (b->outfilename[0] != '\0') { strcpy(gidfilename, b->outfilename); } else { strcpy(gidfilename, "unnamed"); } strcat(gidfilename, ".face.msh"); if (!b->quiet) { printf("Writing %s.\n", gidfilename); } outfile = fopen(gidfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", gidfilename); return; } fprintf(outfile, "mesh dimension = 3 elemtype triangle nnode = 3\n"); fprintf(outfile, "coordinates\n"); points->traversalinit(); ptloop = pointtraverse(); pointnumber = 1; // Gid need start number form 1. while (ptloop != (point) NULL) { // Point coordinates. fprintf(outfile, "%4d %.17g %.17g %.17g", pointnumber, ptloop[0], ptloop[1], ptloop[2]); if (in->numberofpointattributes > 0) { // Write an attribute, ignore others if more than one. fprintf(outfile, " %.17g", ptloop[3]); } fprintf(outfile, "\n"); setpointmark(ptloop, pointnumber); ptloop = pointtraverse(); pointnumber++; } fprintf(outfile, "end coordinates\n"); fprintf(outfile, "elements\n"); tetrahedrons->traversalinit(); tface.tet = tetrahedrontraverse(); elementnumber = 1; while (tface.tet != (tetrahedron *) NULL) { for (tface.loc = 0; tface.loc < 4; tface.loc ++) { sym(tface, tsymface); if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) { p1 = org(tface); p2 = dest(tface); p3 = apex(tface); if (tsymface.tet == dummytet) { // It's a hull face, output it. fprintf(outfile, "%5d %d %d %d\n", elementnumber, pointmark(p1), pointmark(p2), pointmark(p3)); elementnumber++; } else if (b->useshelles) { // Only output it if it's a subface. tspivot(tface, sface); if (sface.sh != dummysh) { fprintf(outfile, "%5d %d %d %d\n", elementnumber, pointmark(p1), pointmark(p2), pointmark(p3)); elementnumber++; } } } } tface.tet = tetrahedrontraverse(); } fprintf(outfile, "end elements\n"); fclose(outfile); } /////////////////////////////////////////////////////////////////////////////// // // // outmesh2off() Write the mesh to an .off file. // // // // .off, the Object File Format, is one of the popular file formats from the // // Geometry Center's Geomview package (http://www.geomview.org). // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outmesh2off(char* ofilename) { FILE *outfile; char offfilename[FILENAMESIZE]; triface tface, tsymface; point ptloop, p1, p2, p3; long faces; int shift; if (ofilename != (char *) NULL && ofilename[0] != '\0') { strcpy(offfilename, ofilename); } else if (b->outfilename[0] != '\0') { strcpy(offfilename, b->outfilename); } else { strcpy(offfilename, "unnamed"); } strcat(offfilename, ".off"); if (!b->quiet) { printf("Writing %s.\n", offfilename); } outfile = fopen(offfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", offfilename); return; } // Calculate the number of triangular faces in the tetrahedral mesh. faces = (4l * tetrahedrons->items + hullsize) / 2l; // Number of points, faces, and edges(not used, here show hullsize). fprintf(outfile, "OFF\n%ld %ld %ld\n", points->items, faces, hullsize); // Write the points. points->traversalinit(); ptloop = pointtraverse(); while (ptloop != (point) NULL) { fprintf(outfile, " %.17g %.17g %.17g\n",ptloop[0], ptloop[1], ptloop[2]); ptloop = pointtraverse(); } // OFF always use zero as the first index. shift = in->firstnumber == 1 ? 1 : 0; tetrahedrons->traversalinit(); tface.tet = tetrahedrontraverse(); // To loop over the set of faces, loop over all tetrahedra, and look at // the four faces of each tetrahedron. If there isn't another tetrahedron // adjacent to the face, operate on the face. If there is another adj- // acent tetrahedron, operate on the face only if the current tetrahedron // has a smaller pointer than its neighbor. This way, each face is // considered only once. while (tface.tet != (tetrahedron *) NULL) { for (tface.loc = 0; tface.loc < 4; tface.loc ++) { sym(tface, tsymface); if ((tface.tet < tsymface.tet) || (tsymface.tet == dummytet)) { p1 = org(tface); p2 = dest(tface); p3 = apex(tface); // Face number, indices of three vertexs. fprintf(outfile, "3 %4d %4d %4d\n", pointmark(p1) - shift, pointmark(p2) - shift, pointmark(p3) - shift); } } tface.tet = tetrahedrontraverse(); } fprintf(outfile, "# Generated by %s\n", b->commandline); fclose(outfile); } /////////////////////////////////////////////////////////////////////////////// // // // outmesh2vtk() Save mesh to file in VTK Legacy format. // // // // This function was contributed by Bryn Llyod from ETH, 2007. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::outmesh2vtk(char* ofilename) { FILE *outfile; char vtkfilename[FILENAMESIZE]; point pointloop; tetrahedron* tptr; double x, y, z; int n1, n2, n3, n4; int nnodes = 4; int celltype = 10; int NEL = tetrahedrons->items; int NN = points->items; if (ofilename != (char *) NULL && ofilename[0] != '\0') { strcpy(vtkfilename, ofilename); } else if (b->outfilename[0] != '\0') { strcpy(vtkfilename, b->outfilename); } else { strcpy(vtkfilename, "unnamed"); } strcat(vtkfilename, ".vtk"); if (!b->quiet) { printf("Writing %s.\n", vtkfilename); } outfile = fopen(vtkfilename, "w"); if (outfile == (FILE *) NULL) { printf("File I/O Error: Cannot create file %s.\n", vtkfilename); return; } //always write big endian //bool ImALittleEndian = !testIsBigEndian(); fprintf(outfile, "# vtk DataFile Version 2.0\n"); fprintf(outfile, "Unstructured Grid\n"); fprintf(outfile, "ASCII\n"); // BINARY fprintf(outfile, "DATASET UNSTRUCTURED_GRID\n"); fprintf(outfile, "POINTS %d double\n", NN); points->traversalinit(); pointloop = pointtraverse(); for(int id=0; idtraversalinit(); tptr = tetrahedrontraverse(); //elementnumber = firstindex; // in->firstnumber; if (b->order == 2) { printf(" Write VTK not implemented for order 2 elements \n"); return; } while (tptr != (tetrahedron *) NULL) { point p1 = (point) tptr[4]; point p2 = (point) tptr[5]; point p3 = (point) tptr[6]; point p4 = (point) tptr[7]; n1 = pointmark(p1) - in->firstnumber; n2 = pointmark(p2) - in->firstnumber; n3 = pointmark(p3) - in->firstnumber; n4 = pointmark(p4) - in->firstnumber; //if(ImALittleEndian){ // swapBytes((unsigned char *) &nnodes, sizeof(nnodes)); // swapBytes((unsigned char *) &n1, sizeof(n1)); // swapBytes((unsigned char *) &n2, sizeof(n2)); // swapBytes((unsigned char *) &n3, sizeof(n3)); // swapBytes((unsigned char *) &n4, sizeof(n4)); //} //fwrite((char*)(&nnodes),sizeof(int), 1, outfile); //fwrite((char*)(&n1),sizeof(int), 1, outfile); //fwrite((char*)(&n2),sizeof(int), 1, outfile); //fwrite((char*)(&n3),sizeof(int), 1, outfile); //fwrite((char*)(&n4),sizeof(int), 1, outfile); fprintf(outfile, "%d %4d %4d %4d %4d\n", nnodes, n1, n2, n3, n4); tptr = tetrahedrontraverse(); } fprintf(outfile, "\n"); fprintf(outfile, "CELL_TYPES %d\n", NEL); for(int tid=0; tidquiet) { printf(" Checking consistency of mesh...\n"); } horrors = 0; // Run through the list of tetrahedra, checking each one. tetrahedrons->traversalinit(); tetraloop.tet = tetrahedrontraverse(); while (tetraloop.tet != (tetrahedron *) NULL) { // Check all four faces of the tetrahedron. for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) { tetorg = org(tetraloop); tetdest = dest(tetraloop); tetapex = apex(tetraloop); tetoppo = oppo(tetraloop); if (tetraloop.loc == 0) { // Only test for inversion once. oritest = orient3d(tetorg, tetdest, tetapex, tetoppo); if (oritest >= 0.0) { printf(" !! !! %s ", oritest > 0.0 ? "Inverted" : "Degenerated"); printtet(&tetraloop); printf(" orient3d = %.17g.\n", oritest); horrors++; } } // Find the neighboring tetrahedron on this face. sym(tetraloop, oppotet); if (oppotet.tet != dummytet) { // Check if it is a dead tet. if (!isdead(&oppotet)) { // Check that the tetrahedron's neighbor knows it's a neighbor. sym(oppotet, oppooppotet); if ((tetraloop.tet != oppooppotet.tet) || (tetraloop.loc != oppooppotet.loc)) { printf(" !! !! Asymmetric tetra-tetra bond:\n"); if (tetraloop.tet == oppooppotet.tet) { printf(" (Right tetrahedron, wrong orientation)\n"); } printf(" First "); printtet(&tetraloop); printf(" Second (nonreciprocating) "); printtet(&oppotet); horrors++; } } else { printf(" !! !! A dead neighbor:\n"); printtet(&tetraloop); horrors++; } } } if (infected(tetraloop)) { pts = (point *) &(tetraloop.tet[4]); printf(" !! tet (%d, %d, %d, %d) is infected.\n", pointmark(pts[0]), pointmark(pts[1]), pointmark(pts[2]), pointmark(pts[3])); horrors++; } if (marktested(tetraloop)) { pts = (point *) &(tetraloop.tet[4]); printf(" !! tet (%d, %d, %d, %d) is marktested.\n", pointmark(pts[0]), pointmark(pts[1]), pointmark(pts[2]), pointmark(pts[3])); horrors++; } tetraloop.tet = tetrahedrontraverse(); } if (horrors == 0) { if (!b->quiet) { printf(" In my studied opinion, the mesh appears to be consistent.\n"); } } else if (horrors == 1) { printf(" !! !! !! !! Precisely one festering wound discovered.\n"); } else { printf(" !! !! !! !! %d abominations witnessed.\n", horrors); } return horrors; } /////////////////////////////////////////////////////////////////////////////// // // // checkshells() Test the boundary mesh for topological consistency. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::checkshells() { triface oppotet, oppooppotet, testtet; face shloop, segloop, spin; face testsh, testseg, testshsh; point shorg, shdest, segorg, segdest; REAL checksign; bool same; int horrors; int i, j; if (!b->quiet) { printf(" Checking consistency of the mesh boundary...\n"); } horrors = 0; // Run through the list of subfaces, checking each one. subfaces->traversalinit(); shloop.sh = shellfacetraverse(subfaces); while (shloop.sh != (shellface *) NULL) { // Check two connected tetrahedra if they exist. shloop.shver = 0; stpivot(shloop, oppotet); if (oppotet.tet != dummytet) { // Check if the tet and the face have the same vertices. for (i = 0; i < 3; i++) { pinfect((point) shloop.sh[3 + i]); } for (j = 0; j < 3; j++) { if (org(oppotet) == NULL) break; if (!pinfected(org(oppotet))) break; enextself(oppotet); } for (i = 0; i < 3; i++) { puninfect((point) shloop.sh[3 + i]); } if (j < 3) { printf(" !! !! Wrong subface-tet connection.\n"); printf(" p:draw_subface(%d, %d, %d).\n", pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); printf(" p:draw_tet(%d, %d, %d, %d).\n", pointmark(org(oppotet)), pointmark(dest(oppotet)), pointmark(apex(oppotet)), pointmark(oppo(oppotet))); horrors++; } tspivot(oppotet, testsh); if (testsh.sh != shloop.sh) { printf(" !! !! Wrong tetra-subface connection.\n"); printf(" Tetra: "); printtet(&oppotet); printf(" Subface: "); printsh(&shloop); horrors++; } if (oppo(oppotet) != (point) NULL) { adjustedgering(oppotet, CCW); checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop), oppo(oppotet)); if (checksign >= 0.0) { printf(" !! !! Wrong subface orientation.\n"); printf(" Subface: "); printsh(&shloop); horrors++; } } } sesymself(shloop); stpivot(shloop, oppooppotet); if (oppooppotet.tet != dummytet) { tspivot(oppooppotet, testsh); if (testsh.sh != shloop.sh) { printf(" !! !! Wrong tetra-subface connection.\n"); printf(" Tetra: "); printtet(&oppooppotet); printf(" Subface: "); printsh(&shloop); horrors++; } if (oppotet.tet != dummytet) { sym(oppotet, testtet); if (testtet.tet != oppooppotet.tet) { printf(" !! !! Wrong tetra-subface-tetra connection.\n"); printf(" Tetra 1: "); printtet(&oppotet); printf(" Subface: "); printsh(&shloop); printf(" Tetra 2: "); printtet(&oppooppotet); horrors++; } } if (oppo(oppooppotet) != (point) NULL) { adjustedgering(oppooppotet, CCW); checksign = orient3d(sorg(shloop), sdest(shloop), sapex(shloop), oppo(oppooppotet)); if (checksign >= 0.0) { printf(" !! !! Wrong subface orientation.\n"); printf(" Subface: "); printsh(&shloop); horrors++; } } } // Check connection between subfaces. shloop.shver = 0; for (i = 0; i < 3; i++) { shorg = sorg(shloop); shdest = sdest(shloop); sspivot(shloop, testseg); if (testseg.sh != dummysh) { segorg = sorg(testseg); segdest = sdest(testseg); same = ((shorg == segorg) && (shdest == segdest)) || ((shorg == segdest) && (shdest == segorg)); if (!same) { printf(" !! !! Wrong subface-subsegment connection.\n"); printf(" Subface: "); printsh(&shloop); printf(" Subsegment: "); printsh(&testseg); horrors++; } } spivot(shloop, testsh); if (testsh.sh != dummysh) { // Check if the subface is self-bonded. if (testsh.sh == shloop.sh) { printf(" !! !! Subface is self-bonded.\n"); printsh(&shloop); horrors++; } segorg = sorg(testsh); segdest = sdest(testsh); same = ((shorg == segorg) && (shdest == segdest)) || ((shorg == segdest) && (shdest == segorg)); if (!same) { printf(" !! !! Wrong subface-subface connection.\n"); printf(" Subface 1: "); printsh(&shloop); printf(" Subface 2: "); printsh(&testsh); horrors++; } spivot(testsh, testshsh); shorg = sorg(testshsh); shdest = sdest(testshsh); same = ((shorg == segorg) && (shdest == segdest)) || ((shorg == segdest) && (shdest == segorg)); if (!same) { printf(" !! !! Wrong subface-subface connection.\n"); printf(" Subface 1: "); printsh(&testsh); printf(" Subface 2: "); printsh(&testshsh); horrors++; } if (testseg.sh == dummysh) { if (testshsh.sh != shloop.sh) { printf(" !! !! Wrong subface-subface connection.\n"); printf(" Subface 1: "); printsh(&shloop); printf(" Subface 2: "); printsh(&testsh); horrors++; } } } senextself(shloop); } if (sinfected(shloop)) { printf(" !! subface (%d, %d, %d) is infected.\n", pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); horrors++; } if (smarktested(shloop)) { printf(" !! subface (%d, %d, %d) is marktested.\n", pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); horrors++; } shloop.sh = shellfacetraverse(subfaces); } if (horrors > 0) { return horrors; } // Run through the list of subsegs, checking each one. subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { segorg = sorg(segloop); segdest = sdest(segloop); spivot(segloop, testsh); if (testsh.sh == dummysh) { printf(" !! !! Wrong subsegment-subface connection.\n"); printf(" Subsegment: "); printsh(&segloop); horrors++; segloop.sh = shellfacetraverse(subsegs); continue; } shorg = sorg(testsh); shdest = sdest(testsh); same = ((shorg == segorg) && (shdest == segdest)) || ((shorg == segdest) && (shdest == segorg)); if (!same) { printf(" !! !! Wrong subsegment-subface connection.\n"); printf(" Subsegment : "); printsh(&segloop); printf(" Subface : "); printsh(&testsh); horrors++; segloop.sh = shellfacetraverse(subsegs); continue; } // Check the connection of face loop around this subsegment. spin = testsh; i = 0; do { spivotself(spin); if (spin.sh != dummysh) { shorg = sorg(spin); shdest = sdest(spin); same = ((shorg == segorg) && (shdest == segdest)) || ((shorg == segdest) && (shdest == segorg)); if (!same) { printf(" !! !! Wrong subsegment-subface connection.\n"); printf(" Subsegment : "); printsh(&segloop); printf(" Subface : "); printsh(&testsh); horrors++; break; } i++; } else { break; } } while (spin.sh != testsh.sh && i < 1000); if (i >= 1000) { printf(" !! !! Wrong subsegment-subface connection.\n"); printf(" Subsegment : "); printsh(&segloop); horrors++; } segloop.sh = shellfacetraverse(subsegs); } if (horrors == 0) { if (!b->quiet) { printf(" Mesh boundaries connected correctly.\n"); } } else { printf(" !! !! !! !! %d boundary connection viewed with horror.\n", horrors); } return horrors; } /////////////////////////////////////////////////////////////////////////////// // // // checksegments() Check the connections between tetrahedra and segments. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::checksegments() { triface tetloop, neightet; face sseg, checkseg; point pa, pb; int hitbdry; int horrors, i; if (!b->quiet) { printf(" Checking tet-seg connections...\n"); } horrors = 0; tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != NULL) { // Loop the six edges of the tet. if (tetloop.tet[8] != NULL) { for (i = 0; i < 6; i++) { tetloop.loc = edge2locver[i][0]; tetloop.ver = edge2locver[i][1]; tsspivot1(tetloop, sseg); if (sseg.sh != dummysh) { // Check if they are the same edge. sseg.shver = 0; pa = (point) sorg(sseg); pb = (point) sdest(sseg); if (!(((org(tetloop) == pa) && (dest(tetloop) == pb)) || ((org(tetloop) == pb) && (dest(tetloop) == pa)))) { printf(" !! Wrong tet-seg connection.\n"); printf(" Tet: x%lx (%d, %d, %d, %d) - Seg: x%lx (%d, %d).\n", (unsigned long) tetloop.tet, pointmark(org(tetloop)), pointmark(dest(tetloop)), pointmark(apex(tetloop)), pointmark(oppo(tetloop)), (unsigned long) sseg.sh, pointmark(pa), pointmark(pb)); horrors++; } else { // Loop all tets sharing at this edge. neightet = tetloop; hitbdry = 0; do { tsspivot1(neightet, checkseg); if (checkseg.sh != sseg.sh) { printf(" !! Wrong tet-seg connection.\n"); printf(" Tet: x%lx (%d, %d, %d, %d) - ", (unsigned long) tetloop.tet, pointmark(org(tetloop)), pointmark(dest(tetloop)), pointmark(apex(tetloop)), pointmark(oppo(tetloop))); if (checkseg.sh != NULL) { printf("Seg x%lx (%d, %d).\n", (unsigned long) checkseg.sh, pointmark(sorg(checkseg)), pointmark(sdest(checkseg))); } else { printf("Seg: NULL.\n"); } horrors++; } tfnextself(neightet); if (neightet.tet == dummytet) { hitbdry++; if (hitbdry == 2) break; esym(tetloop, neightet); tfnextself(neightet); if (neightet.tet == dummytet) break; } } while (neightet.tet != tetloop.tet); } } } } tetloop.tet = tetrahedrontraverse(); } if (horrors == 0) { printf(" Segments are connected properly.\n"); } else { printf(" !! !! !! !! Found %d missing connections.\n", horrors); } return horrors; } /////////////////////////////////////////////////////////////////////////////// // // // checkdelaunay() Ensure that the mesh is constrained Delaunay. // // // // If 'flipqueue' is not NULL, non-locally Delaunay faces are saved in it. // // // /////////////////////////////////////////////////////////////////////////////// int tetgenmesh::checkdelaunay(REAL eps, queue* flipqueue) { triface tetraloop; triface oppotet; face opposhelle; point tetorg, tetdest, tetapex, tetoppo; point oppooppo; REAL sign; int shouldbedelaunay; int horrors; if (!b->quiet) { printf(" Checking Delaunay property of the mesh...\n"); } horrors = 0; // Run through the list of triangles, checking each one. tetrahedrons->traversalinit(); tetraloop.tet = tetrahedrontraverse(); while (tetraloop.tet != (tetrahedron *) NULL) { // Check all four faces of the tetrahedron. for (tetraloop.loc = 0; tetraloop.loc < 4; tetraloop.loc++) { tetorg = org(tetraloop); tetdest = dest(tetraloop); tetapex = apex(tetraloop); tetoppo = oppo(tetraloop); sym(tetraloop, oppotet); oppooppo = oppo(oppotet); // Only do testif there is an adjoining tetrahedron whose pointer is // larger (to ensure that each pair isn't tested twice). shouldbedelaunay = (oppotet.tet != dummytet) && (tetoppo != (point) NULL) && (oppooppo != (point) NULL) && (tetraloop.tet < oppotet.tet); if (checksubfaces && shouldbedelaunay) { // If a shell face separates the tetrahedra, then the face is // constrained, so no local Delaunay test should be done. tspivot(tetraloop, opposhelle); if (opposhelle.sh != dummysh){ shouldbedelaunay = 0; } } if (shouldbedelaunay) { sign = insphere(tetdest, tetorg, tetapex, tetoppo, oppooppo); if ((sign > 0.0) && (eps > 0.0)) { if (iscospheric(tetdest, tetorg, tetapex, tetoppo, oppooppo, sign, eps)) sign = 0.0; } if (sign > 0.0) { if (flipqueue) { enqueueflipface(tetraloop, flipqueue); } horrors++; } } } tetraloop.tet = tetrahedrontraverse(); } if (flipqueue == (queue *) NULL) { if (horrors == 0) { if (!b->quiet) { printf(" The mesh is %s.\n", checksubfaces ? "constrained Delaunay" : "Delaunay"); } } else { printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); } } return horrors; } /////////////////////////////////////////////////////////////////////////////// // // // checkconforming() Ensure that the mesh is conforming Delaunay. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::checkconforming() { face segloop, shloop; int encsubsegs, encsubfaces; if (!b->quiet) { printf(" Checking conforming Delaunay property of mesh...\n"); } encsubsegs = encsubfaces = 0; // Run through the list of subsegments, check each one. subsegs->traversalinit(); segloop.sh = shellfacetraverse(subsegs); while (segloop.sh != (shellface *) NULL) { if (checkseg4encroach(&segloop, NULL, NULL, false)) { printf(" !! !! Non-conforming subsegment: (%d, %d)\n", pointmark(sorg(segloop)), pointmark(sdest(segloop))); encsubsegs++; } segloop.sh = shellfacetraverse(subsegs); } // Run through the list of subfaces, check each one. subfaces->traversalinit(); shloop.sh = shellfacetraverse(subfaces); while (shloop.sh != (shellface *) NULL) { if (checksub4encroach(&shloop, NULL, false)) { printf(" !! !! Non-conforming subface: (%d, %d, %d)\n", pointmark(sorg(shloop)), pointmark(sdest(shloop)), pointmark(sapex(shloop))); encsubfaces++; } shloop.sh = shellfacetraverse(subfaces); } if (encsubsegs == 0 && encsubfaces == 0) { if (!b->quiet) { printf(" The mesh is conforming Delaunay.\n"); } } else { if (encsubsegs > 0) { printf(" !! !! %d subsegments are non-conforming.\n", encsubsegs); } if (encsubfaces > 0) { printf(" !! !! %d subfaces are non-conforming.\n", encsubfaces); } } } /////////////////////////////////////////////////////////////////////////////// // // // algorithmicstatistics() Print statistics about the mesh algorithms. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::algorithmicstatistics() { printf("Algorithmic statistics:\n\n"); printf(" Number of orient3d tests: %ld\n", orient3dcount); printf(" Number of insphere tests: %ld\n", inspherecount); printf(" Number of symbolic insphere tests: %ld\n", insphere_sos_count); printf(" Number of visited tets in point location: %ld\n", ptloc_count); printf(" Maximal number of tets per point location: %ld\n",ptloc_max_count); printf(" Number of hull sites: %ld\n", inserthullcount); printf(" Number of 1-to-4 flips: %ld\n", flip14count); printf(" Number of 2-to-6 flips: %ld\n", flip26count); printf(" Number of n-t-2n flips: %ld\n", flipn2ncount); if (!b->plc) { if (1) { printf(" Number of deleted tets: %ld\n", totaldeadtets); printf(" Number of created tets: %ld\n", totalbowatcavsize); printf(" Maximum number of tets per new point: %ld\n", maxbowatcavsize); // printf(" Number of 3-to-2 flips: %ld\n", flip32count); } else { // printf(" Number of 3-to-2 flips: %ld\n", flip32count); // printf(" Number of 2-to-3 flips: %ld\n", flip23count); // printf(" Number of n-to-m flips: %ld\n", flipnmcount); // printf(" Total number of primitive flips: %ld\n", // flip23count + flip32count); } } if (b->plc) { printf(" Number of 2-to-2 flips: %ld\n", flip22count); // printf(" Number of tri-edge inter (coplanar) tests: %ld (%ld)\n", // triedgcount, triedgcopcount); printf(" Number of crossed faces (edges) in scout segs: %ld (%ld)\n", across_face_count, across_edge_count); printf(" Maximal number of crossed faces per segment: %ld\n", across_max_count); printf(" Number of rule-1 points: %ld\n", r1count); printf(" Number of rule-2 points: %ld\n", r2count); printf(" Number of rule-3 points: %ld\n", r3count); printf(" Maximal size of a missing region: %ld\n", maxregionsize); printf(" Maximal size of a recovered cavity: %ld\n", maxcavsize); printf(" Number of non-Delaunay edges: %ld\n", ndelaunayedgecount); printf(" Number of cavity expansions: %ld\n", cavityexpcount); } // printf(" Total point location time (millisec): %g\n", tloctime * 1e+3); // printf(" Total point insertion time (millisec): %g\n",tinserttime*1e+3); // if (b->bowyerwatson == 0) { // printf(" Total flip time (millisec): %g\n", tfliptime * 1e+3); // } printf("\n"); } /////////////////////////////////////////////////////////////////////////////// // // // qualitystatistics() Print statistics about the quality of the mesh. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::qualitystatistics() { triface tetloop, neightet; point p[4]; char sbuf[128]; REAL radiusratiotable[12]; REAL aspectratiotable[12]; REAL A[4][4], rhs[4], D; REAL V[6][3], N[4][3], H[4]; // edge-vectors, face-normals, face-heights. REAL edgelength[6], alldihed[6], faceangle[3]; REAL shortest, longest; REAL smallestvolume, biggestvolume; REAL smallestratio, biggestratio; REAL smallestdiangle, biggestdiangle; REAL smallestfaangle, biggestfaangle; REAL tetvol, minaltitude; REAL cirradius, minheightinv; // insradius; REAL shortlen, longlen; REAL tetaspect, tetradius; REAL smalldiangle, bigdiangle; REAL smallfaangle, bigfaangle; int radiustable[12]; int aspecttable[16]; int dihedangletable[18]; int faceangletable[18]; int indx[4]; int radiusindex; int aspectindex; int tendegree; int i, j; printf("Mesh quality statistics:\n\n"); // Avoid compile warnings. shortlen = longlen = 0.0; smalldiangle = bigdiangle = 0.0; radiusratiotable[0] = 0.707; radiusratiotable[1] = 1.0; radiusratiotable[2] = 1.1; radiusratiotable[3] = 1.2; radiusratiotable[4] = 1.4; radiusratiotable[5] = 1.6; radiusratiotable[6] = 1.8; radiusratiotable[7] = 2.0; radiusratiotable[8] = 2.5; radiusratiotable[9] = 3.0; radiusratiotable[10] = 10.0; radiusratiotable[11] = 0.0; aspectratiotable[0] = 1.5; aspectratiotable[1] = 2.0; aspectratiotable[2] = 2.5; aspectratiotable[3] = 3.0; aspectratiotable[4] = 4.0; aspectratiotable[5] = 6.0; aspectratiotable[6] = 10.0; aspectratiotable[7] = 15.0; aspectratiotable[8] = 25.0; aspectratiotable[9] = 50.0; aspectratiotable[10] = 100.0; aspectratiotable[11] = 0.0; for (i = 0; i < 12; i++) radiustable[i] = 0; for (i = 0; i < 12; i++) aspecttable[i] = 0; for (i = 0; i < 18; i++) dihedangletable[i] = 0; for (i = 0; i < 18; i++) faceangletable[i] = 0; minaltitude = xmax - xmin + ymax - ymin + zmax - zmin; minaltitude = minaltitude * minaltitude; shortest = minaltitude; longest = 0.0; smallestvolume = minaltitude; biggestvolume = 0.0; smallestratio = minaltitude; biggestratio = 0.0; smallestdiangle = smallestfaangle = 180.0; biggestdiangle = biggestfaangle = 0.0; // Loop all elements, calculate quality parameters for each element. tetrahedrons->traversalinit(); tetloop.tet = tetrahedrontraverse(); while (tetloop.tet != (tetrahedron *) NULL) { // Get four vertices: p0, p1, p2, p3. for (i = 0; i < 4; i++) p[i] = (point) tetloop.tet[4 + i]; // Set the edge vectors: V[0], ..., V[5] for (i = 0; i < 3; i++) V[0][i] = p[0][i] - p[3][i]; // V[0]: p3->p0. for (i = 0; i < 3; i++) V[1][i] = p[1][i] - p[3][i]; // V[1]: p3->p1. for (i = 0; i < 3; i++) V[2][i] = p[2][i] - p[3][i]; // V[2]: p3->p2. for (i = 0; i < 3; i++) V[3][i] = p[1][i] - p[0][i]; // V[3]: p0->p1. for (i = 0; i < 3; i++) V[4][i] = p[2][i] - p[1][i]; // V[4]: p1->p2. for (i = 0; i < 3; i++) V[5][i] = p[0][i] - p[2][i]; // V[5]: p2->p0. // Set the matrix A = [V[0], V[1], V[2]]^T. for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) A[j][i] = V[j][i]; } // Decompose A just once. lu_decmp(A, 3, indx, &D, 0); // Get the tet volume. tetvol = fabs(A[indx[0]][0] * A[indx[1]][1] * A[indx[2]][2]) / 6.0; // Get the three faces normals. for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) rhs[i] = 0.0; rhs[j] = 1.0; // Positive means the inside direction lu_solve(A, 3, indx, rhs, 0); for (i = 0; i < 3; i++) N[j][i] = rhs[i]; } // Get the fourth face normal by summing up the first three. for (i = 0; i < 3; i++) N[3][i] = - N[0][i] - N[1][i] - N[2][i]; // Get the radius of the circumsphere. for (i = 0; i < 3; i++) rhs[i] = 0.5 * dot(V[i], V[i]); lu_solve(A, 3, indx, rhs, 0); cirradius = sqrt(dot(rhs, rhs)); // Normalize the face normals. for (i = 0; i < 4; i++) { // H[i] is the inverse of height of its corresponding face. H[i] = sqrt(dot(N[i], N[i])); for (j = 0; j < 3; j++) N[i][j] /= H[i]; } // Get the radius of the inscribed sphere. // insradius = 1.0 / (H[0] + H[1] + H[2] + H[3]); // Get the biggest H[i] (corresponding to the smallest height). minheightinv = H[0]; for (i = 1; i < 3; i++) { if (H[i] > minheightinv) minheightinv = H[i]; } // Get the squares of the edge lengthes. for (i = 0; i < 6; i++) edgelength[i] = dot(V[i], V[i]); // Get the dihedrals (in degree) at each edges. j = 0; for (i = 1; i < 4; i++) { alldihed[j] = -dot(N[0], N[i]); // Edge cd, bd, bc. if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding. else if (alldihed[j] > 1.0) alldihed[j] = 1; alldihed[j] = acos(alldihed[j]) / PI * 180.0; j++; } for (i = 2; i < 4; i++) { alldihed[j] = -dot(N[1], N[i]); // Edge ad, ac. if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding. else if (alldihed[j] > 1.0) alldihed[j] = 1; alldihed[j] = acos(alldihed[j]) / PI * 180.0; j++; } alldihed[j] = -dot(N[2], N[3]); // Edge ab. if (alldihed[j] < -1.0) alldihed[j] = -1; // Rounding. else if (alldihed[j] > 1.0) alldihed[j] = 1; alldihed[j] = acos(alldihed[j]) / PI * 180.0; // Calculate the longest and shortest edge length. for (i = 0; i < 6; i++) { if (i == 0) { shortlen = longlen = edgelength[i]; } else { shortlen = edgelength[i] < shortlen ? edgelength[i] : shortlen; longlen = edgelength[i] > longlen ? edgelength[i] : longlen; } if (edgelength[i] > longest) { longest = edgelength[i]; } if (edgelength[i] < shortest) { shortest = edgelength[i]; } } // Calculate the largest and smallest volume. if (tetvol < smallestvolume) { smallestvolume = tetvol; } if (tetvol > biggestvolume) { biggestvolume = tetvol; } // Calculate the largest and smallest dihedral angles. for (i = 0; i < 6; i++) { if (i == 0) { smalldiangle = bigdiangle = alldihed[i]; } else { smalldiangle = alldihed[i] < smalldiangle ? alldihed[i] : smalldiangle; bigdiangle = alldihed[i] > bigdiangle ? alldihed[i] : bigdiangle; } if (alldihed[i] < smallestdiangle) { smallestdiangle = alldihed[i]; } if (alldihed[i] > biggestdiangle) { biggestdiangle = alldihed[i]; } } // Accumulate the corresponding number in the dihedral angle histogram. if (smalldiangle < 5.0) { tendegree = 0; } else if (smalldiangle >= 5.0 && smalldiangle < 10.0) { tendegree = 1; } else if (smalldiangle >= 80.0 && smalldiangle < 110.0) { tendegree = 9; // Angles between 80 to 110 degree are in one entry. } else { tendegree = (int) (smalldiangle / 10.); if (smalldiangle < 80.0) { tendegree++; // In the left column. } else { tendegree--; // In the right column. } } dihedangletable[tendegree]++; if (bigdiangle >= 80.0 && bigdiangle < 110.0) { tendegree = 9; // Angles between 80 to 110 degree are in one entry. } else if (bigdiangle >= 170.0 && bigdiangle < 175.0) { tendegree = 16; } else if (bigdiangle >= 175.0) { tendegree = 17; } else { tendegree = (int) (bigdiangle / 10.); if (bigdiangle < 80.0) { tendegree++; // In the left column. } else { tendegree--; // In the right column. } } dihedangletable[tendegree]++; // Calulate the largest and smallest face angles. tetloop.ver = 0; for (tetloop.loc = 0; tetloop.loc < 4; tetloop.loc++) { sym(tetloop, neightet); // Only do the calulation once for a face. if ((neightet.tet == dummytet) || (tetloop.tet < neightet.tet)) { p[0] = org(tetloop); p[1] = dest(tetloop); p[2] = apex(tetloop); faceangle[0] = interiorangle(p[0], p[1], p[2], NULL); faceangle[1] = interiorangle(p[1], p[2], p[0], NULL); faceangle[2] = PI - (faceangle[0] + faceangle[1]); // Translate angles into degrees. for (i = 0; i < 3; i++) { faceangle[i] = (faceangle[i] * 180.0) / PI; } // Calculate the largest and smallest face angles. for (i = 0; i < 3; i++) { if (i == 0) { smallfaangle = bigfaangle = faceangle[i]; } else { smallfaangle = faceangle[i] < smallfaangle ? faceangle[i] : smallfaangle; bigfaangle = faceangle[i] > bigfaangle ? faceangle[i] : bigfaangle; } if (faceangle[i] < smallestfaangle) { smallestfaangle = faceangle[i]; } if (faceangle[i] > biggestfaangle) { biggestfaangle = faceangle[i]; } } tendegree = (int) (smallfaangle / 10.); faceangletable[tendegree]++; tendegree = (int) (bigfaangle / 10.); faceangletable[tendegree]++; } } // Calculate aspect ratio and radius-edge ratio for this element. tetradius = cirradius / sqrt(shortlen); // tetaspect = sqrt(longlen) / (2.0 * insradius); tetaspect = sqrt(longlen) * minheightinv; // Remember the largest and smallest aspect ratio.. if (tetaspect < smallestratio) { smallestratio = tetaspect; } if (tetaspect > biggestratio) { biggestratio = tetaspect; } // Accumulate the corresponding number in the aspect ratio histogram. aspectindex = 0; while ((tetaspect > aspectratiotable[aspectindex]) && (aspectindex < 11)) { aspectindex++; } aspecttable[aspectindex]++; radiusindex = 0; while ((tetradius > radiusratiotable[radiusindex]) && (radiusindex < 11)) { radiusindex++; } radiustable[radiusindex]++; tetloop.tet = tetrahedrontraverse(); } shortest = sqrt(shortest); longest = sqrt(longest); minaltitude = sqrt(minaltitude); printf(" Smallest volume: %16.5g | Largest volume: %16.5g\n", smallestvolume, biggestvolume); printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", shortest, longest); printf(" Smallest aspect ratio: %9.5g | Largest aspect ratio: %9.5g\n", smallestratio, biggestratio); sprintf(sbuf, "%.17g", biggestfaangle); if (strlen(sbuf) > 8) { sbuf[8] = '\0'; } printf(" Smallest facangle: %14.5g | Largest facangle: %s\n", smallestfaangle, sbuf); sprintf(sbuf, "%.17g", biggestdiangle); if (strlen(sbuf) > 8) { sbuf[8] = '\0'; } printf(" Smallest dihedral: %14.5g | Largest dihedral: %s\n\n", smallestdiangle, sbuf); /* printf(" Radius-edge ratio histogram:\n"); printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", radiusratiotable[0], radiustable[0], radiusratiotable[5], radiusratiotable[6], radiustable[6]); for (i = 1; i < 5; i++) { printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", radiusratiotable[i - 1], radiusratiotable[i], radiustable[i], radiusratiotable[i + 5], radiusratiotable[i + 6], radiustable[i + 6]); } printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", radiusratiotable[4], radiusratiotable[5], radiustable[5], radiusratiotable[10], radiustable[11]); printf(" (A tetrahedron's radius-edge ratio is its radius of "); printf("circumsphere divided\n"); printf(" by its shortest edge length)\n\n"); */ printf(" Aspect ratio histogram:\n"); printf(" < %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", aspectratiotable[0], aspecttable[0], aspectratiotable[5], aspectratiotable[6], aspecttable[6]); for (i = 1; i < 5; i++) { printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", aspectratiotable[i - 1], aspectratiotable[i], aspecttable[i], aspectratiotable[i + 5], aspectratiotable[i + 6], aspecttable[i + 6]); } printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", aspectratiotable[4], aspectratiotable[5], aspecttable[5], aspectratiotable[10], aspecttable[11]); printf(" (A tetrahedron's aspect ratio is its longest edge length"); printf(" divided by its\n"); printf(" smallest side height)\n\n"); printf(" Face angle histogram:\n"); for (i = 0; i < 9; i++) { printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", i * 10, i * 10 + 10, faceangletable[i], i * 10 + 90, i * 10 + 100, faceangletable[i + 9]); } if (minfaceang != PI) { printf(" Minimum input face angle is %g (degree).\n", minfaceang / PI * 180.0); } printf("\n"); printf(" Dihedral angle histogram:\n"); // Print the three two rows: printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 0, 5, dihedangletable[0], 80, 110, dihedangletable[9]); printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 5, 10, dihedangletable[1], 110, 120, dihedangletable[10]); // Print the third to seventh rows. for (i = 2; i < 7; i++) { printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", (i - 1) * 10, (i - 1) * 10 + 10, dihedangletable[i], (i - 1) * 10 + 110, (i - 1) * 10 + 120, dihedangletable[i + 9]); } // Print the last two rows. printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 60, 70, dihedangletable[7], 170, 175, dihedangletable[16]); printf(" %3d - %2d degrees: %8d | %3d - %3d degrees: %8d\n", 70, 80, dihedangletable[8], 175, 180, dihedangletable[17]); if (minfacetdihed != PI) { printf(" Minimum input facet dihedral angle is %g (degree).\n", minfacetdihed / PI * 180.0); } printf("\n"); } /////////////////////////////////////////////////////////////////////////////// // // // statistics() Print all sorts of cool facts. // // // /////////////////////////////////////////////////////////////////////////////// void tetgenmesh::statistics() { printf("\nStatistics:\n\n"); printf(" Input points: %d\n", in->numberofpoints + jettisoninverts); if (b->refine) { printf(" Input tetrahedra: %d\n", in->numberoftetrahedra); } if (b->plc) { printf(" Input facets: %d\n", in->numberoffacets); printf(" Input segments: %ld\n", insegments); printf(" Input holes: %d\n", in->numberofholes); printf(" Input regions: %d\n", in->numberofregions); } printf("\n Mesh points: %ld\n", points->items); printf(" Mesh tetrahedra: %ld\n", tetrahedrons->items); printf(" Mesh faces: %ld\n", (4l * tetrahedrons->items + hullsize) / 2l); printf(" Mesh edges: %ld\n", meshedges); if (b->plc || b->refine) { printf(" Mesh boundary faces: %ld\n", subfaces->items); printf(" Mesh boundary edges: %ld\n\n", subsegs->items); } else { printf(" Convex hull faces: %ld\n\n", hullsize); } if (b->verbose > 0) { if (b->plc || b->refine) { qualitystatistics(); } // algorithmicstatistics(); } } //// //// //// //// //// report_cxx /////////////////////////////////////////////////////////////// //// main_cxx ///////////////////////////////////////////////////////////////// //// //// //// //// /////////////////////////////////////////////////////////////////////////////// // // // tetrahedralize() The interface for users using TetGen library to // // generate tetrahedral meshes with all features. // // // // The sequence is roughly as follows. Many of these steps can be skipped, // // depending on the command line switches. // // // // - Initialize constants and parse the command line. // // - Read the vertices from a file and either // // - tetrahedralize them (no -r), or // // - read an old mesh from files and reconstruct it (-r). // // - Insert the PLC segments and facets (-p). // // - Read the holes (-p), regional attributes (-pA), and regional volume // // constraints (-pa). Carve the holes and concavities, and spread the // // regional attributes and volume constraints. // // - Enforce the constraints on minimum quality bound (-q) and maximum // // volume (-a). Also enforce the conforming Delaunay property (-q and -a). // // - Promote the mesh's linear tetrahedra to higher order elements (-o). // // - Write the output files and print the statistics. // // - Check the consistency and Delaunay property of the mesh (-C). // // // /////////////////////////////////////////////////////////////////////////////// void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, tetgenio *addin, tetgenio *bgmin) { tetgenmesh m; // Variables for timing the performance of TetGen (defined in time.h). clock_t tv[17]; tv[0] = clock(); m.b = b; m.in = in; m.macheps = exactinit(); m.steinerleft = b->steiner; if (b->metric) { m.bgm = new tetgenmesh(); m.bgm->b = b; m.bgm->in = bgmin; m.bgm->macheps = exactinit(); } m.initializepools(); m.transfernodes(); tv[1] = clock(); if (b->refine) { m.reconstructmesh(); } else { m.delaunizevertices(); if (m.hullsize == 0l) { printf("The input point set does not span a 3D subspace.\n"); return; } } tv[2] = clock(); if (!b->quiet) { if (b->refine) { printf("Mesh reconstruction seconds:"); } else { printf("Delaunay seconds:"); } printf(" %g\n", (tv[2] - tv[1]) / (REAL) CLOCKS_PER_SEC); } if (b->metric) { if (bgmin != (tetgenio *) NULL) { m.bgm->initializepools(); m.bgm->transfernodes(); m.bgm->reconstructmesh(); } else { m.bgm->in = in; m.bgm->initializepools(); m.duplicatebgmesh(); } } tv[3] = clock(); if (!b->quiet) { if (b->metric) { printf("Background mesh reconstruct seconds: %g\n", (tv[3] - tv[2]) / (REAL) CLOCKS_PER_SEC); } } if (b->useshelles && !b->refine) { m.meshsurface(); tv[14] = clock(); if (b->diagnose != 1) { m.markacutevertices(60.0); m.formskeleton(tv[15]); } else { m.detectinterfaces(); } } tv[4] = clock(); if (!b->quiet) { if (b->useshelles && !b->refine) { if (b->diagnose != 1) { printf("Boundary recovery "); } else { printf("Intersection "); } printf("seconds: %g\n", (tv[4] - tv[3]) / (REAL) CLOCKS_PER_SEC); /*if ((b->diagnose != 1) && (b->verbose > 0)) { printf(" Surface mesh seconds: %g\n", (tv[14] - tv[3]) / (REAL) CLOCKS_PER_SEC); printf(" Segment recovery seconds: %g\n", (tv[15] - tv[14]) / (REAL) CLOCKS_PER_SEC); printf(" Facet recovery seconds: %g\n", (tv[4] - tv[15]) / (REAL) CLOCKS_PER_SEC); }*/ } } if (b->plc && !(b->diagnose == 1)) { m.carveholes(); } tv[5] = clock(); if (!b->quiet) { if (b->plc && !(b->diagnose == 1)) { printf("Hole seconds: %g\n", (tv[5] - tv[4]) / (REAL) CLOCKS_PER_SEC); } } if ((b->plc || b->refine) && !(b->diagnose == 1)) { m.optimizemesh2(false); } tv[6] = clock(); if (!b->quiet) { if ((b->plc || b->refine) && !(b->diagnose == 1)) { printf("Repair seconds: %g\n", (tv[6] - tv[5]) / (REAL) CLOCKS_PER_SEC); } } if ((b->plc && b->nobisect) && !(b->diagnose == 1)) { m.removesteiners2(); } tv[7] = clock(); if (!b->quiet) { if ((b->plc && b->nobisect) && !(b->diagnose == 1)) { printf("Steiner removal seconds: %g\n", (tv[7] - tv[6]) / (REAL) CLOCKS_PER_SEC); } } if (b->insertaddpoints && (addin != (tetgenio *) NULL)) { if (addin->numberofpoints > 0) { m.insertconstrainedpoints(addin); } } tv[8] = clock(); if (!b->quiet) { if ((b->plc || b->refine) && (b->insertaddpoints)) { printf("Constrained points seconds: %g\n", (tv[8] - tv[7]) / (REAL) CLOCKS_PER_SEC); } } if (b->metric) { m.interpolatesizemap(); } tv[9] = clock(); if (!b->quiet) { if (b->metric) { printf("Size interpolating seconds: %g\n", (tv[9] - tv[8]) / (REAL) CLOCKS_PER_SEC); } } //if (b->coarse) { // m.removesteiners2(true); //} tv[10] = clock(); if (!b->quiet) { if (b->coarse) { printf("Mesh coarsening seconds: %g\n", (tv[10] - tv[9]) / (REAL) CLOCKS_PER_SEC); } } if (b->quality) { m.enforcequality(); } tv[11] = clock(); if (!b->quiet) { if (b->quality) { printf("Quality seconds: %g\n", (tv[11] - tv[10]) / (REAL) CLOCKS_PER_SEC); } } if (b->quality && (b->optlevel > 0)) { m.optimizemesh2(true); } tv[12] = clock(); if (!b->quiet) { if (b->quality && (b->optlevel > 0)) { printf("Optimize seconds: %g\n", (tv[12] - tv[11]) / (REAL) CLOCKS_PER_SEC); } } if (!b->nojettison && ((m.dupverts > 0) || (m.unuverts > 0) || (b->refine && (in->numberofcorners == 10)))) { m.jettisonnodes(); } if (b->order > 1) { m.highorder(); } if (!b->quiet) { printf("\n"); } if (out != (tetgenio *) NULL) { out->firstnumber = in->firstnumber; out->mesh_dim = in->mesh_dim; } if (b->nonodewritten || b->noiterationnum) { if (!b->quiet) { printf("NOT writing a .node file.\n"); } } else { if (b->diagnose == 1) { if (m.subfaces->items > 0l) { m.outnodes(out); // Only output when self-intersecting faces exist. } } else { m.outnodes(out); if (b->quality && b->metric) { m.outmetrics(out); } } } if (b->noelewritten == 1) { if (!b->quiet) { printf("NOT writing an .ele file.\n"); } m.numberedges(); } else { if (!(b->diagnose == 1)) { if (m.tetrahedrons->items > 0l) { m.outelements(out); } } } if (b->nofacewritten) { if (!b->quiet) { printf("NOT writing an .face file.\n"); } } else { if (b->facesout) { if (m.tetrahedrons->items > 0l) { m.outfaces(out); // Output all faces. } } else { if (b->diagnose == 1) { if (m.subfaces->items > 0l) { m.outsubfaces(out); // Only output self-intersecting faces. } } else if (b->plc || b->refine) { if (m.subfaces->items > 0l) { m.outsubfaces(out); // Output boundary faces. } } else { if (m.tetrahedrons->items > 0l) { m.outhullfaces(out); // Output convex hull faces. } } } } //if (m.checkpbcs) { // m.outpbcnodes(out); //} if (b->edgesout) { if (b->edgesout > 1) { m.outedges(out); // -ee, output all mesh edges. } else { m.outsubsegments(out); // -e, only output subsegments. } } if (!out && b->plc && ((b->object == tetgenbehavior::OFF) || (b->object == tetgenbehavior::PLY) || (b->object == tetgenbehavior::STL))) { m.outsmesh(b->outfilename); } if (!out && b->meditview) { m.outmesh2medit(b->outfilename); } if (!out && b->gidview) { m.outmesh2gid(b->outfilename); } if (!out && b->geomview) { m.outmesh2off(b->outfilename); } if (!out && b->vtkview) { m.outmesh2vtk(b->outfilename); } if (b->neighout) { m.outneighbors(out); } if (b->voroout) { m.outvoronoi(out); } tv[13] = clock(); if (!b->quiet) { printf("\nOutput seconds: %g\n", (tv[13] - tv[12]) / (REAL) CLOCKS_PER_SEC); printf("Total running seconds: %g\n", (tv[13] - tv[0]) / (REAL) CLOCKS_PER_SEC); } if (b->docheck) { m.checkmesh(); if (m.checksubfaces) { m.checkshells(); } if (b->docheck > 1) { if (m.checkdelaunay(0.0, NULL) > 0) { assert(0); } if (b->docheck > 2) { if (b->quality || b->refine) { m.checkconforming(); } } } } if (!b->quiet) { m.statistics(); } if (b->metric) { delete m.bgm; } } #ifndef TETLIBRARY /////////////////////////////////////////////////////////////////////////////// // // // main() The entrance for running TetGen from command line. // // // /////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv[]) #else // with TETLIBRARY /////////////////////////////////////////////////////////////////////////////// // // // tetrahedralize() The entrance for calling TetGen from another program. // // // /////////////////////////////////////////////////////////////////////////////// void tetrahedralize(char *switches, tetgenio *in, tetgenio *out, tetgenio *addin, tetgenio *bgmin) #endif // not TETLIBRARY { tetgenbehavior b; #ifndef TETLIBRARY tetgenio in, addin, bgmin; if (!b.parse_commandline(argc, argv)) { terminatetetgen(0); } if (b.refine) { if (!in.load_tetmesh(b.infilename)) { terminatetetgen(3); } } else { if (!in.load_plc(b.infilename, (int) b.object)) { terminatetetgen(3); } } if (b.insertaddpoints) { if (!addin.load_node(b.addinfilename)) { addin.numberofpoints = 0l; } } if (b.metric) { if (!bgmin.load_tetmesh(b.bgmeshfilename)) { bgmin.numberoftetrahedra = 0l; } } if (bgmin.numberoftetrahedra > 0l) { tetrahedralize(&b, &in, NULL, &addin, &bgmin); } else { tetrahedralize(&b, &in, NULL, &addin, NULL); } return 0; #else // with TETLIBRARY if (!b.parse_commandline(switches)) { terminatetetgen(1); } tetrahedralize(&b, in, out, addin, bgmin); #endif // not TETLIBRARY } //// //// //// //// //// main_cxx ///////////////////////////////////////////////////////////////// vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/LICENSE0000664000175000017500000000542311757446472017453 0ustar lucalucaTetGen License -------------- The software (TetGen) is licensed under the terms of the MIT license with the following exceptions: Distribution of modified versions of this code is permissible UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE SAME SOURCE FILES tetgen.h AND tetgen.cxx REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code for any commercial purpose is permissible ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER. The full license text is reproduced below. This means that TetGen is no free software, but for private, research, and educational purposes it can be used at absolutely no cost and without further arrangements. For details, see http://tetgen.berlios.de ============================================================================== TetGen A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator Version 1.4 (Released on January 14, 2006). Copyright 2002, 2004, 2005, 2006 Hang Si Rathausstr. 9, 10178 Berlin, Germany si@wias-berlin.de Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Distribution of modified versions of this code is permissible UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE SAME SOURCE FILES tetgen.h AND tetgen.cxx REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code for any commercial purpose is permissible ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==============================================================================vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/makefile0000664000175000017500000000504211757446472020143 0ustar lucaluca############################################################################### # # # makefile for TetGen # # # # Type "make" to compile TetGen into an executable program (tetgen). # # Type "make tetlib" to compile TetGen into a library (libtet.a). # # Type "make distclean" to delete all object (*.o) files. # # # ############################################################################### # CXX should be set to the name of your favorite C++ compiler. # =========================================================== CXX = g++ #CXX = icpc #CXX = CC # CXXFLAGS is the level of optimiztion, default is -O. One should try # -O2, -O3 ... to find the best optimization level. # =================================================================== CXXFLAGS = -g # PREDCXXFLAGS is for compiling J. Shewchuk's predicates. It should # always be equal to -O0 (no optimization). Otherwise, TetGen may not # work properly. PREDCXXFLAGS = -O0 # SWITCHES is a list of switches to compile TetGen. # ================================================= # # By default, TetGen uses double precision floating point numbers. If you # prefer single precision, use the -DSINGLE switch. # # The source code of TetGen includes a lot of assertions, which are mainly # used for catching bugs at that places. These assertions somewhat slow # down the speed of TetGen. They can be skipped by define the -DNDEBUG # switch. SWITCHES = -Wall -DSELF_CHECK # SWITCHES = -Wall -Wabi -Wctor-dtor-privacy \ # -Woverloaded-virtual -Wno-pmf-conversions -Wsign-promo \ # -Wsynth -Wchar-subscripts -Wconversion -Wsign-compare \ # -Wcomment -Wimplicit -Wmissing-braces -Wparentheses \ # -Wreturn-type -Wswitch -Wswitch-default \ # -Wswitch-enum -Wtrigraphs -W -DSELF_CHECK # RM should be set to the name of your favorite rm (file deletion program). RM = /bin/rm # The action starts here. tetgen: tetgen.cxx predicates.o $(CXX) $(CXXFLAGS) $(SWITCHES) -o tetgen tetgen.cxx predicates.o -lm tetlib: tetgen.cxx predicates.o $(CXX) $(CXXFLAGS) $(SWITCHES) -DTETLIBRARY -c tetgen.cxx ar r libtet.a tetgen.o predicates.o predicates.o: predicates.cxx $(CXX) $(PREDCXXFLAGS) -c predicates.cxx clean: $(RM) *.o *.a tetgen *~ vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/tetgen.h0000664000175000017500000042105411757446472020107 0ustar lucaluca/////////////////////////////////////////////////////////////////////////////// // // // TetGen // // // // A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator // // // // Version 1.4 // // September 6, 2009 // // // // Copyright (C) 2002--2009 // // Hang Si // // Research Group: Numerical Mathematics and Scientific Computing // // Weierstrass Institute for Applied Analysis and Stochastics (WIAS) // // Mohrenstr. 39, 10117 Berlin, Germany // // si@wias-berlin.de // // // // TetGen is freely available through the website: http://tetgen.berlios.de. // // It may be copied, modified, and redistributed for non-commercial use. // // Please consult the file LICENSE for the detailed copyright notices. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // TetGen is a library to generate tetrahedral meshes for 3D domains. It's // // main purpose is to generate suitable tetrahedral meshes for numerical // // simulations using finite element and finite volume methods. // // // // TetGen incorporates a suit of geometrical and mesh generation algorithms. // // A brief description of algorithms used in TetGen is found in the first // // section of the user's manual. References are given for users who are // // interesting in these approaches. The main references are given below: // // // // The efficient Delaunay tetrahedralization algorithm is: H. Edelsbrunner // // and N. R. Shah, "Incremental Topological Flipping Works for Regular // // Triangulations". Algorithmica 15: 223--241, 1996. // // // // The constrained Delaunay tetrahedralization algorithm is described in: // // H. Si and K. Gaertner, "Meshing Piecewise Linear Complexes by Constr- // // ained Delaunay Tetrahedralizations". In Proceeding of the 14th Inter- // // national Meshing Roundtable. September 2005. // // // // The mesh refinement algorithm is from: Hang Si, "Adaptive Tetrahedral // // Mesh Generation by Constrained Delaunay Refinement". International // // Journal for Numerical Methods in Engineering, 75(7): 856--880, 2008. // // // // The mesh data structure of TetGen is a combination of two types of mesh // // data structures. The tetrahedron-based mesh data structure introduced // // by Shewchuk is eligible for tetrahedralization algorithms. The triangle // // -edge data structure developed by Muecke is adopted for representing // // boundary elements: subfaces and subsegments. // // // // J. R. Shewchuk, "Delaunay Refinement Mesh Generation". PhD thesis, // // Carnegie Mellon University, Pittsburgh, PA, 1997. // // // // E. P. Muecke, "Shapes and Implementations in Three-Dimensional // // Geometry". PhD thesis, Univ. of Illinois, Urbana, Illinois, 1993. // // // // The research of mesh generation is definitly on the move. Many State-of- // // the-art algorithms need implementing and evaluating. I heartily welcome // // any new algorithm especially for generating quality conforming Delaunay // // meshes and anisotropic conforming Delaunay meshes. // // // // TetGen is supported by the "pdelib" project of Weierstrass Institute for // // Applied Analysis and Stochastics (WIAS) in Berlin. It is a collection // // of software components for solving non-linear partial differential // // equations including 2D and 3D mesh generators, sparse matrix solvers, // // and scientific visualization tools, etc. For more information please // // visit: http://www.wias-berlin.de/software/pdelib. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // tetgen.h // // // // Header file of the TetGen library. Also is the user-level header file. // // // /////////////////////////////////////////////////////////////////////////////// #ifndef tetgenH #define tetgenH #include #include #include #include #include #include // The types 'intptr_t' and 'uintptr_t' are signed and unsigned integer types, // respectively. They are guaranteed to be the same width as a pointer. // They are defined in by the C99 Standard. // However, Microsoft Visual C++ doesn't ship with this header file yet. We // need to define them. (Thanks to Steven G. Johnson from MIT for the // following piece of code.) // Define the _MSC_VER symbol if you are using Microsoft Visual C++. // #define _MSC_VER // Define the _WIN64 symbol if you are running TetGen on Win64. // #define _WIN64 #ifdef _MSC_VER // Microsoft Visual C++ # ifdef _WIN64 typedef __int64 intptr_t; typedef unsigned __int64 uintptr_t; # else // not _WIN64 typedef int intptr_t; typedef unsigned int uintptr_t; # endif #else // not Visual C++ # include #endif // To compile TetGen as a library instead of an executable program, define // the TETLIBRARY symbol. // #define TETLIBRARY // Uncomment the following line to disable assert macros. These macros are // inserted in places where I hope to catch bugs. // #define NDEBUG // To insert lots of self-checks for internal errors, define the SELF_CHECK // symbol. This will slow down the program a bit. // #define SELF_CHECK // 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 #define REAL float #else #define REAL double #endif // not defined SINGLE /////////////////////////////////////////////////////////////////////////////// // // // TetGen Library Overview // // // // TetGen library is comprised by several data types and global functions. // // // // There are three main data types: tetgenio, tetgenbehavior, and tetgenmesh.// // Tetgenio is used to pass data into and out of TetGen library; tetgenbeha- // // vior keeps the runtime options and thus controls the behaviors of TetGen; // // tetgenmesh, the biggest data type I've ever defined, contains mesh data // // structures and mesh traversing and transformation operators. The meshing // // algorithms are implemented on top of it. These data types are defined as // // C++ classes. // // // // There are few global functions. tetrahedralize() is provided for calling // // TetGen from another program. Two functions: orient3d() and insphere() are // // incorporated from a public C code provided by Shewchuk. They performing // // exact geometrical tests. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // Class tetgenio // // // // The interface for passing data into and out of the library of TetGen. // // // // The tetgenio data structure is actually a collection of arrays of points, // // facets, tetrahedra, and so forth. The library will read and write these // // arrays according to the options specified in tetgenbehavior structure. // // // // If you want to program with the library of TetGen, it's necessary for you // // to understand this data type,while the other two structures can be hidden // // through calling the global function "tetrahedralize()". Each array corre- // // sponds to a list of data in the file formats of TetGen. It is necessary // // to understand TetGen's input/output file formats (see user's manual). // // // // Once an object of tetgenio is declared, no array is created. One has to // // allocate enough memory for them, e.g., use the "new" operator in C++. On // // deletion of the object, the memory occupied by these arrays needs to be // // freed. Routine deinitialize() will be automatically called. It will de- // // allocate the memory for an array if it is not a NULL. However, it assumes // // that the memory is allocated by the C++ "new" operator. If you use malloc // // (), you should free() them and set the pointers to NULLs before reaching // // deinitialize(). // // // // tetgenio ontains routines for reading and writing TetGen's files, i.e., // // .node, .poly, .smesh, .ele, .face, and .edge files. Both the library of // // TetGen and TetView use these routines to process input files. // // // /////////////////////////////////////////////////////////////////////////////// class tetgenio { public: // Maximum number of characters in a file name (including the null). enum {FILENAMESIZE = 1024}; // Maxi. numbers of chars in a line read from a file (incl. the null). enum {INPUTLINESIZE = 1024}; // The polygon data structure. A "polygon" describes a simple polygon // (no holes). It is not necessarily convex. Each polygon contains a // number of corners (points) and the same number of sides (edges). // Note that the points of the polygon must be given in either counter- // clockwise or clockwise order and they form a ring, so every two // consective points forms an edge of the polygon. typedef struct { int *vertexlist; int numberofvertices; } polygon; static void init(polygon* p) { p->vertexlist = (int *) NULL; p->numberofvertices = 0; } // The facet data structure. A "facet" describes a facet. Each facet is // a polygonal region possibly with holes, edges, and points in it. typedef struct { polygon *polygonlist; int numberofpolygons; REAL *holelist; int numberofholes; } facet; static void init(facet* f) { f->polygonlist = (polygon *) NULL; f->numberofpolygons = 0; f->holelist = (REAL *) NULL; f->numberofholes = 0; } // A 'voroedge' is an edge of the Voronoi diagram. It corresponds to a // Delaunay face. Each voroedge is either a line segment connecting // two Voronoi vertices or a ray starting from a Voronoi vertex to an // "infinite vertex". 'v1' and 'v2' are two indices pointing to the // list of Voronoi vertices. 'v1' must be non-negative, while 'v2' may // be -1 if it is a ray, in this case, the unit normal of this ray is // given in 'vnormal'. typedef struct { int v1, v2; REAL vnormal[3]; } voroedge; // A 'vorofacet' is an facet of the Voronoi diagram. It corresponds to a // Delaunay edge. Each Voronoi facet is a convex polygon formed by a // list of Voronoi edges, it may not be closed. 'c1' and 'c2' are two // indices pointing into the list of Voronoi cells, i.e., the two cells // share this facet. 'elist' is an array of indices pointing into the // list of Voronoi edges, 'elist[0]' saves the number of Voronoi edges // (including rays) of this facet. typedef struct { int c1, c2; int *elist; } vorofacet; // The periodic boundary condition group data structure. A "pbcgroup" // contains the definition of a pbc and the list of pbc point pairs. // 'fmark1' and 'fmark2' are the facetmarkers of the two pbc facets f1 // and f2, respectively. 'transmat' is the transformation matrix which // maps a point in f1 into f2. An array of pbc point pairs are saved // in 'pointpairlist'. The first point pair is at indices [0] and [1], // followed by remaining pairs. Two integers per pair. typedef struct { int fmark1, fmark2; REAL transmat[4][4]; int numberofpointpairs; int *pointpairlist; } pbcgroup; // A callback function for mesh refinement. typedef bool (* TetSizeFunc)(REAL*, REAL*, REAL*, REAL*, REAL*, REAL); // Items are numbered starting from 'firstnumber' (0 or 1), default is 0. int firstnumber; // Dimension of the mesh (2 or 3), default is 3. int mesh_dim; // Does the lines in .node file contain index or not, default is TRUE. bool useindex; // 'pointlist': An array of point coordinates. The first point's x // coordinate is at index [0] and its y coordinate at index [1], its // z coordinate is at index [2], followed by the coordinates of the // remaining points. Each point occupies three REALs. // 'pointattributelist': An array of point attributes. Each point's // attributes occupy 'numberofpointattributes' REALs. // 'pointmtrlist': An array of metric tensors at points. Each point's // tensor occupies 'numberofpointmtr' REALs. // `pointmarkerlist': An array of point markers; one int per point. REAL *pointlist; REAL *pointattributelist; REAL *pointmtrlist; int *pointmarkerlist; int numberofpoints; int numberofpointattributes; int numberofpointmtrs; // `elementlist': An array of element (triangle or tetrahedron) corners. // The first element's first corner is at index [0], followed by its // other corners in counterclockwise order, followed by any other // nodes if the element represents a nonlinear element. Each element // occupies `numberofcorners' ints. // `elementattributelist': An array of element attributes. Each // element's attributes occupy `numberofelementattributes' REALs. // `elementconstraintlist': An array of constraints, i.e. triangle's // area or tetrahedron's volume; one REAL per element. Input only. // `neighborlist': An array of element neighbors; 3 or 4 ints per // element. Output only. int *tetrahedronlist; REAL *tetrahedronattributelist; REAL *tetrahedronvolumelist; int *neighborlist; int numberoftetrahedra; int numberofcorners; int numberoftetrahedronattributes; // `facetlist': An array of facets. Each entry is a structure of facet. // `facetmarkerlist': An array of facet markers; one int per facet. facet *facetlist; int *facetmarkerlist; int numberoffacets; // `holelist': An array of holes. The first hole's x, y and z // coordinates are at indices [0], [1] and [2], followed by the // remaining holes. Three REALs per hole. REAL *holelist; int numberofholes; // `regionlist': An array of regional attributes and volume constraints. // The first constraint's x, y and z coordinates are at indices [0], // [1] and [2], followed by the regional attribute at index [3], foll- // owed by the maximum volume at index [4]. Five REALs per constraint. // Note that each regional attribute is used only if you select the `A' // switch, and each volume constraint is used only if you select the // `a' switch (with no number following). REAL *regionlist; int numberofregions; // `facetconstraintlist': An array of facet maximal area constraints. // Two REALs per constraint. The first (at index [0]) is the facet // marker (cast it to int), the second (at index [1]) is its maximum // area bound. REAL *facetconstraintlist; int numberoffacetconstraints; // `segmentconstraintlist': An array of segment max. length constraints. // Three REALs per constraint. The first two (at indcies [0] and [1]) // are the indices of the endpoints of the segment, the third (at index // [2]) is its maximum length bound. REAL *segmentconstraintlist; int numberofsegmentconstraints; // 'pbcgrouplist': An array of periodic boundary condition groups. pbcgroup *pbcgrouplist; int numberofpbcgroups; // `trifacelist': An array of triangular face endpoints. The first // face's endpoints are at indices [0], [1] and [2], followed by the // remaining faces. Three ints per face. // `adjtetlist': An array of adjacent tetrahedra to the faces of // trifacelist. Each face has at most two adjacent tets, the first // face's adjacent tets are at [0], [1]. Two ints per face. A '-1' // indicates outside (no adj. tet). This list is output when '-nn' // switch is used. // `trifacemarkerlist': An array of face markers; one int per face. int *trifacelist; int *adjtetlist; int *trifacemarkerlist; int numberoftrifaces; // `edgelist': An array of edge endpoints. The first edge's endpoints // are at indices [0] and [1], followed by the remaining edges. Two // ints per edge. // `edgemarkerlist': An array of edge markers; one int per edge. int *edgelist; int *edgemarkerlist; int numberofedges; // 'vpointlist': An array of Voronoi vertex coordinates (like pointlist). // 'vedgelist': An array of Voronoi edges. Each entry is a 'voroedge'. // 'vfacetlist': An array of Voronoi facets. Each entry is a 'vorofacet'. // 'vcelllist': An array of Voronoi cells. Each entry is an array of // indices pointing into 'vfacetlist'. The 0th entry is used to store // the length of this array. REAL *vpointlist; voroedge *vedgelist; vorofacet *vfacetlist; int **vcelllist; int numberofvpoints; int numberofvedges; int numberofvfacets; int numberofvcells; // A callback function. TetSizeFunc tetunsuitable; // Input & output routines. bool load_node_call(FILE* infile, int markers, char* nodefilename); bool load_node(char* filebasename); bool load_var(char*); bool load_mtr(char*); bool load_poly(char*); bool load_pbc(char*); bool load_off(char*); bool load_ply(char*); bool load_stl(char*); bool load_medit(char*); bool load_vtk(char*); bool load_plc(char*, int); bool load_tetmesh(char*); void save_nodes(char*); void save_elements(char*); void save_faces(char*); void save_edges(char*); void save_neighbors(char*); void save_poly(char*); // Read line and parse string functions. char *readline(char* string, FILE* infile, int *linenumber); char *findnextfield(char* string); char *readnumberline(char* string, FILE* infile, char* infilename); char *findnextnumber(char* string); // Initialize routine. void initialize() { firstnumber = 0; // Default item index is numbered from Zero. mesh_dim = 3; // Default mesh dimension is 3. useindex = true; pointlist = (REAL *) NULL; pointattributelist = (REAL *) NULL; pointmtrlist = (REAL *) NULL; pointmarkerlist = (int *) NULL; numberofpoints = 0; numberofpointattributes = 0; numberofpointmtrs = 0; tetrahedronlist = (int *) NULL; tetrahedronattributelist = (REAL *) NULL; tetrahedronvolumelist = (REAL *) NULL; neighborlist = (int *) NULL; numberoftetrahedra = 0; numberofcorners = 4; // Default is 4 nodes per element. numberoftetrahedronattributes = 0; trifacelist = (int *) NULL; adjtetlist = (int *) NULL; trifacemarkerlist = (int *) NULL; numberoftrifaces = 0; facetlist = (facet *) NULL; facetmarkerlist = (int *) NULL; numberoffacets = 0; edgelist = (int *) NULL; edgemarkerlist = (int *) NULL; numberofedges = 0; holelist = (REAL *) NULL; numberofholes = 0; regionlist = (REAL *) NULL; numberofregions = 0; facetconstraintlist = (REAL *) NULL; numberoffacetconstraints = 0; segmentconstraintlist = (REAL *) NULL; numberofsegmentconstraints = 0; pbcgrouplist = (pbcgroup *) NULL; numberofpbcgroups = 0; vpointlist = (REAL *) NULL; vedgelist = (voroedge *) NULL; vfacetlist = (vorofacet *) NULL; vcelllist = (int **) NULL; numberofvpoints = 0; numberofvedges = 0; numberofvfacets = 0; numberofvcells = 0; tetunsuitable = NULL; } // Free the memory allocated in 'tetgenio'. void deinitialize() { facet *f; polygon *p; pbcgroup *pg; int i, j; // Notince that this routine assumes that the memory was allocated by // C++ memory allocation operator 'new'. if (pointlist != (REAL *) NULL) { delete [] pointlist; } if (pointattributelist != (REAL *) NULL) { delete [] pointattributelist; } if (pointmtrlist != (REAL *) NULL) { delete [] pointmtrlist; } if (pointmarkerlist != (int *) NULL) { delete [] pointmarkerlist; } if (tetrahedronlist != (int *) NULL) { delete [] tetrahedronlist; } if (tetrahedronattributelist != (REAL *) NULL) { delete [] tetrahedronattributelist; } if (tetrahedronvolumelist != (REAL *) NULL) { delete [] tetrahedronvolumelist; } if (neighborlist != (int *) NULL) { delete [] neighborlist; } if (trifacelist != (int *) NULL) { delete [] trifacelist; } if (adjtetlist != (int *) NULL) { delete [] adjtetlist; } if (trifacemarkerlist != (int *) NULL) { delete [] trifacemarkerlist; } if (edgelist != (int *) NULL) { delete [] edgelist; } if (edgemarkerlist != (int *) NULL) { delete [] edgemarkerlist; } if (facetlist != (facet *) NULL) { for (i = 0; i < numberoffacets; i++) { f = &facetlist[i]; for (j = 0; j < f->numberofpolygons; j++) { p = &f->polygonlist[j]; delete [] p->vertexlist; } delete [] f->polygonlist; if (f->holelist != (REAL *) NULL) { delete [] f->holelist; } } delete [] facetlist; } if (facetmarkerlist != (int *) NULL) { delete [] facetmarkerlist; } if (holelist != (REAL *) NULL) { delete [] holelist; } if (regionlist != (REAL *) NULL) { delete [] regionlist; } if (facetconstraintlist != (REAL *) NULL) { delete [] facetconstraintlist; } if (segmentconstraintlist != (REAL *) NULL) { delete [] segmentconstraintlist; } if (pbcgrouplist != (pbcgroup *) NULL) { for (i = 0; i < numberofpbcgroups; i++) { pg = &(pbcgrouplist[i]); if (pg->pointpairlist != (int *) NULL) { delete [] pg->pointpairlist; } } delete [] pbcgrouplist; } if (vpointlist != (REAL *) NULL) { delete [] vpointlist; } if (vedgelist != (voroedge *) NULL) { delete [] vedgelist; } if (vfacetlist != (vorofacet *) NULL) { for (i = 0; i < numberofvfacets; i++) { delete [] vfacetlist[i].elist; } delete [] vfacetlist; } if (vcelllist != (int **) NULL) { for (i = 0; i < numberofvcells; i++) { delete [] vcelllist[i]; } delete [] vcelllist; } } // Constructor & destructor. tetgenio() {initialize();} ~tetgenio() {deinitialize();} }; /////////////////////////////////////////////////////////////////////////////// // // // Class tetgenbehavior // // // // The object holding a collection of options controlling TetGen's behavior. // // See "command line switches" in User's manual. // // // // parse_commandline() provides an simple interface to set the vaules of the // // variables. It accepts the standard parameters (e.g., 'argc' and 'argv') // // that pass to C/C++ main() function. Alternatively a string which contains // // the command line options can be used as its parameter. // // // /////////////////////////////////////////////////////////////////////////////// class tetgenbehavior { public: // Labels define the objects which are acceptable by TetGen. They are // recognized by the file extensions. // - NODES, a list of nodes (.node); // - POLY, a piecewise linear complex (.poly or .smesh); // - OFF, a polyhedron (.off, Geomview's file format); // - PLY, a polyhedron (.ply, file format from gatech); // - STL, a surface mesh (.stl, stereolithography format); // - MEDIT, a surface mesh (.mesh, Medit's file format); // - MESH, a tetrahedral mesh (.ele). // If no extension is available, the imposed commandline switch // (-p or -r) implies the object. enum objecttype {NONE, NODES, POLY, OFF, PLY, STL, MEDIT, VTK, MESH}; // Variables of command line switches. Each variable corresponds to a // switch and will be initialized. int plc; // '-p' switch, 0. int quality; // '-q' switch, 0. int refine; // '-r' switch, 0. int coarse; // '-R' switch, 0. int metric; // '-m' switch, 0. int varvolume; // '-a' switch without number, 0. int fixedvolume; // '-a' switch with number, 0. int insertaddpoints; // '-i' switch, 0. int regionattrib; // '-A' switch, 0. int conformdel; // '-D' switch, 0. int diagnose; // '-d' switch, 0. int zeroindex; // '-z' switch, 0. int optlevel; // number specified after '-s' switch, 3. int optpasses; // number specified after '-ss' switch, 3. int order; // element order, specified after '-o' switch, 1. int facesout; // '-f' switch, 0. int edgesout; // '-e' switch, 0. int neighout; // '-n' switch, 0. int voroout; // '-v',switch, 0. int meditview; // '-g' switch, 0. int gidview; // '-G' switch, 0. int geomview; // '-O' switch, 0. int vtkview; // '-K' switch, 0. int nobound; // '-B' switch, 0. int nonodewritten; // '-N' switch, 0. int noelewritten; // '-E' switch, 0. int nofacewritten; // '-F' switch, 0. int noiterationnum; // '-I' switch, 0. int nomerge; // '-M',switch, 0. int nobisect; // count of how often '-Y' switch is selected, 0. int noflip; // do not perform flips. '-X' switch. 0. int nojettison; // do not jettison redundants nodes. '-J' switch. 0. int steiner; // number after '-S' switch. 0. int fliprepair; // '-X' switch, 1. int offcenter; // '-R' switch, 0. int docheck; // '-C' switch, 0. int quiet; // '-Q' switch, 0. int verbose; // count of how often '-V' switch is selected, 0. int useshelles; // '-p', '-r', '-q', '-d', or '-R' switch, 0. int maxflipedgelinksize; // The maximum flippable edge link size 10. REAL minratio; // number after '-q' switch, 2.0. REAL goodratio; // number calculated from 'minratio', 0.0. REAL minangle; // minimum angle bound, 20.0. REAL goodangle; // cosine squared of minangle, 0.0. REAL maxvolume; // number after '-a' switch, -1.0. REAL mindihedral; // number after '-qq' switch, 5.0. REAL maxdihedral; // number after '-qqq' switch, 165.0. REAL alpha1; // number after '-m' switch, sqrt(2). REAL alpha2; // number after '-mm' switch, 1.0. REAL alpha3; // number after '-mmm' switch, 0.6. REAL epsilon; // number after '-T' switch, 1.0e-8. REAL epsilon2; // number after '-TT' switch, 1.0e-5. enum objecttype object; // determined by -p, or -r switch. NONE. // Variables used to save command line switches and in/out file names. char commandline[1024]; char infilename[1024]; char outfilename[1024]; char addinfilename[1024]; char bgmeshfilename[1024]; void syntax(); void usage(); // Command line parse routine. bool parse_commandline(int argc, char **argv); bool parse_commandline(char *switches) { return parse_commandline(0, &switches); } // Initialize all variables. tetgenbehavior() { plc = 0; quality = 0; refine = 0; coarse = 0; metric = 0; minratio = 2.0; goodratio = 0.0; minangle = 20.0; goodangle = 0.0; maxdihedral = 165.0; mindihedral = 5.0; varvolume = 0; fixedvolume = 0; maxvolume = -1.0; regionattrib = 0; insertaddpoints = 0; diagnose = 0; offcenter = 0; conformdel = 0; alpha1 = sqrt(2.0); alpha2 = 1.0; alpha3 = 0.6; zeroindex = 0; facesout = 0; edgesout = 0; neighout = 0; voroout = 0; meditview = 0; gidview = 0; geomview = 0; vtkview = 0; optlevel = 3; optpasses = 3; order = 1; nojettison = 0; nobound = 0; nonodewritten = 0; noelewritten = 0; nofacewritten = 0; noiterationnum = 0; nobisect = 0; noflip = 0; steiner = -1; fliprepair = 1; nomerge = 0; docheck = 0; quiet = 0; verbose = 0; useshelles = 0; maxflipedgelinksize = 10; epsilon = 1.0e-8; epsilon2 = 1.0e-5; object = NONE; commandline[0] = '\0'; infilename[0] = '\0'; outfilename[0] = '\0'; addinfilename[0] = '\0'; bgmeshfilename[0] = '\0'; } ~tetgenbehavior() { } }; /////////////////////////////////////////////////////////////////////////////// // // // Class tetgenmesh // // // // The object to store, generate, and refine a tetrahedral mesh. // // // // It implements the mesh data structures and functions to create and update // // a tetrahedral mesh according to the specified options. // // // /////////////////////////////////////////////////////////////////////////////// class tetgenmesh { public: // Maximum number of characters in a file name (including the null). enum {FILENAMESIZE = 1024}; // For efficiency, a variety of data structures are allocated in bulk. // The following constants determine how many of each structure is // allocated at once. enum {VERPERBLOCK = 4092, SUBPERBLOCK = 4092, ELEPERBLOCK = 8188}; // Used for the point location scheme of Mucke, Saias, and Zhu, to // decide how large a random sample of tetrahedra to inspect. enum {SAMPLEFACTOR = 11}; // Labels that signify two edge rings of a triangle (see Muecke's thesis). enum {CCW = 0, CW = 1}; // Labels that signify whether a record consists primarily of pointers // or of floating-point words. Used for data alignment. enum wordtype {POINTER, FLOATINGPOINT}; // Labels that signify the type of a vertex. enum verttype {UNUSEDVERTEX, DUPLICATEDVERTEX, NACUTEVERTEX, ACUTEVERTEX, FREESEGVERTEX, FREESUBVERTEX, FREEVOLVERTEX, DEADVERTEX = -32768}; // Labels that signify the type of a subface/subsegment. enum shestype {NSHARP, SHARP}; // Labels that signify the type of flips can be applied on a face. enum fliptype {T23, T32, T22, T44, N32, N40, FORBIDDENFACE, FORBIDDENEDGE}; // Labels that signify the result of triangle-triangle intersection test. enum interresult {DISJOINT, INTERSECT, SHAREVERTEX, SHAREEDGE, SHAREFACE, TOUCHEDGE, TOUCHFACE, INTERVERT, INTEREDGE, INTERFACE, INTERTET, TRIEDGEINT, EDGETRIINT, COLLISIONFACE, INTERSUBSEG, INTERSUBFACE, BELOWHULL2}; // Labels that signify the result of point location. enum locateresult {INTETRAHEDRON, ONFACE, ONEDGE, ONVERTEX, OUTSIDE, ENCSEGMENT}; // Labels that signify the result of vertex insertion. enum insertsiteresult {SUCCESSINTET, SUCCESSONFACE, SUCCESSONEDGE, DUPLICATEPOINT, OUTSIDEPOINT}; // Labels that signify the result of direction finding. enum finddirectionresult {ACROSSEDGE, ACROSSFACE, LEFTCOLLINEAR, RIGHTCOLLINEAR, TOPCOLLINEAR, BELOWHULL}; /////////////////////////////////////////////////////////////////////////////// // // // Mesh elements // // // // There are four types of mesh elements: tetrahedra, subfaces, subsegments, // // and points, where subfaces and subsegments are triangles and edges which // // appear on boundaries. A tetrahedralization of a 3D point set comprises // // tetrahedra and points; a surface mesh of a 3D domain comprises subfaces // // subsegments and points. The elements of all the four types consist of a // // tetrahedral mesh of a 3D domain. However, TetGen uses three data types: // // 'tetrahedron', 'shellface', and 'point'. A 'tetrahedron' is a tetrahedron;// // while a 'shellface' can be either a subface or a subsegment; and a 'point'// // is a point. These three data types, linked by pointers comprise a mesh. // // // // A tetrahedron primarily consists of a list of 4 pointers to its corners, // // a list of 4 pointers to its adjoining tetrahedra, a list of 4 pointers to // // its adjoining subfaces (when subfaces are needed). Optinoally, (depending // // on the selected switches), it may contain an arbitrary number of user- // // defined floating-point attributes, an optional maximum volume constraint // // (for -a switch), and a pointer to a list of high-order nodes (-o2 switch).// // Since the size of a tetrahedron is not determined until running time. // // // // The data structure of tetrahedron also stores the geometrical information.// // Let t be a tetrahedron, v0, v1, v2, and v3 be the 4 nodes corresponding // // to the order of their storage in t. v3 always has a negative orientation // // with respect to v0, v1, v2 (ie,, v3 lies above the oriented plane passes // // through v0, v1, v2). Let the 4 faces of t be f0, f1, f2, and f3. Vertices // // of each face are stipulated as follows: f0 (v0, v1, v2), f1 (v0, v3, v1), // // f2 (v1, v3, v2), f3 (v2, v3, v0). // // // // A subface has 3 pointers to vertices, 3 pointers to adjoining subfaces, 3 // // pointers to adjoining subsegments, 2 pointers to adjoining tetrahedra, a // // boundary marker(an integer). Like a tetrahedron, the pointers to vertices,// // subfaces, and subsegments are ordered in a way that indicates their geom- // // etric relation. Let s be a subface, v0, v1 and v2 be the 3 nodes corres- // // ponding to the order of their storage in s, e0, e1 and e2 be the 3 edges,// // then we have: e0 (v0, v1), e1 (v1, v2), e2 (v2, v0). // // // // A subsegment has exactly the same data fields as a subface has, but only // // uses some of them. It has 2 pointers to its endpoints, 2 pointers to its // // adjoining (and collinear) subsegments, a pointer to a subface containing // // it (there may exist any number of subfaces having it, choose one of them // // arbitrarily). The geometric relation between its endpoints and adjoining // // subsegments is kept with respect to the storing order of its endpoints. // // // // The data structure of point is relatively simple. A point is a list of // // floating-point numbers, starting with the x, y, and z coords, followed by // // an arbitrary number of optional user-defined floating-point attributes, // // an integer boundary marker, an integer for the point type, and a pointer // // to a tetrahedron (used for speeding up point location). // // // // For a tetrahedron on a boundary (or a hull) of the mesh, some or all of // // the adjoining tetrahedra may not be present. For an interior tetrahedron, // // often no neighboring subfaces are present, Such absent tetrahedra and // // subfaces are never represented by the NULL pointers; they are represented // // by two special records: `dummytet', the tetrahedron fills "outer space", // // and `dummysh', the vacuous subfaces which are omnipresent. // // // // Tetrahedra and adjoining subfaces are glued together through the pointers // // saved in each data fields of them. Subfaces and adjoining subsegments are // // connected in the same fashion. However, there are no pointers directly // // gluing tetrahedra and adjoining subsegments. For the purpose of saving // // space, the connections between tetrahedra and subsegments are entirely // // mediated through subfaces. The following part explains how subfaces are // // connected in TetGen. // // // /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // // // Subface-subface and subface-subsegment connections // // // // Adjoining subfaces sharing a common edge are connected in such a way that // // they form a face ring around the edge. It is indeed a single linked list // // which is cyclic, e.g., one can start from any subface in it and traverse // // back. When the edge is not a subsegment, the ring only has two coplanar // // subfaces which are pointing to each other. Otherwise, the face ring may // // have any number of subfaces (and are not all coplanar). // // // // How is the face ring formed? Let s be a subsegment, f is one of subfaces // // containing s as an edge. The direction of s is stipulated from its first // // endpoint to its second (according to their storage in s). Once the dir of // // s is determined, the other two edges of f are oriented to follow this dir.// // The "directional normal" N_f is a vector formed from any point in f and a // // points orthogonally above f. // // // // The face ring of s is a cyclic ordered set of subfaces containing s, i.e.,// // F(s) = {f1, f2, ..., fn}, n >= 1. Where the order is defined as follows: // // let fi, fj be two faces in F(s), the "normal-angle", NAngle(i,j) (range // // from 0 to 360 degree) is the angle between the N_fi and N_fj; then fi is // // in front of fj (or symbolically, fi < fj) if there exists another fk in // // F(s), and NAangle(k, i) < NAngle(k, j). The face ring of s is: f1 < f2 < // // ... < fn < f1. // // // // The easiest way to imagine how a face ring is formed is to use the right- // // hand rule. Make a fist using your right hand with the thumb pointing to // // the direction of the subsegment. The face ring is connected following the // // direction of your fingers. // // // // The subface and subsegment are also connected through pointers stored in // // their own data fields. Every subface has a pointer to its adjoining sub- // // segment. However, a subsegment only has one pointer to a subface which is // // containing it. Such subface can be chosen arbitrarily, other subfaces are // // found through the face ring. // // // /////////////////////////////////////////////////////////////////////////////// // The tetrahedron data structure. Fields of a tetrahedron contains: // - a list of four adjoining tetrahedra; // - a list of four vertices; // - a list of four subfaces (optional, used for -p switch); // - a list of user-defined floating-point attributes (optional); // - a volume constraint (optional, used for -a switch); // - an integer of element marker (optional, used for -n switch); // - a pointer to a list of high-ordered nodes (optional, -o2 switch); typedef REAL **tetrahedron; // The shellface data structure. Fields of a shellface contains: // - a list of three adjoining subfaces; // - a list of three vertices; // - a list of two adjoining tetrahedra; // - a list of three adjoining subsegments; // - a pointer to a badface containing it (used for -q); // - an area constraint (optional, used for -q); // - an integer for boundary marker; // - an integer for type: SHARPSEGMENT, NONSHARPSEGMENT, ...; // - an integer for pbc group (optional, if in->pbcgrouplist exists); typedef REAL **shellface; // The point data structure. It is actually an array of REALs: // - x, y and z coordinates; // - a list of user-defined point attributes (optional); // - a list of REALs of a user-defined metric tensor (optional); // - a pointer to a simplex (tet, tri, edge, or vertex); // - a pointer to a parent (or duplicate) point; // - a pointer to a tet in background mesh (optional); // - a pointer to another pbc point (optional); // - an integer for boundary marker; // - an integer for verttype: INPUTVERTEX, FREEVERTEX, ...; typedef REAL *point; /////////////////////////////////////////////////////////////////////////////// // // // Mesh handles // // // // Two special data types, 'triface' and 'face' are defined for maintaining // // and updating meshes. They are like pointers (or handles), which allow you // // to hold one particular part of the mesh, i.e., a tetrahedron, a triangle, // // an edge and a vertex. However, these data types do not themselves store // // any part of the mesh. The mesh is made of the data types defined above. // // // // Muecke's "triangle-edge" data structure is the prototype for these data // // types. It allows a universal representation for every tetrahedron, // // triangle, edge and vertex. For understanding the following descriptions // // of these handle data structures, readers are required to read both the // // introduction and implementation detail of "triangle-edge" data structure // // in Muecke's thesis. // // // // A 'triface' represents a face of a tetrahedron and an oriented edge of // // the face simultaneously. It has a pointer 'tet' to a tetrahedron, an // // integer 'loc' (range from 0 to 3) as the face index, and an integer 'ver' // // (range from 0 to 5) as the edge version. A face of the tetrahedron can be // // uniquly determined by the pair (tet, loc), and an oriented edge of this // // face can be uniquly determined by the triple (tet, loc, ver). Therefore, // // different usages of one triface are possible. If we only use the pair // // (tet, loc), it refers to a face, and if we add the 'ver' additionally to // // the pair, it is an oriented edge of this face. // // // // A 'face' represents a subface and an oriented edge of it simultaneously. // // It has a pointer 'sh' to a subface, an integer 'shver'(range from 0 to 5) // // as the edge version. The pair (sh, shver) determines a unique oriented // // edge of this subface. A 'face' is also used to represent a subsegment, // // in this case, 'sh' points to the subsegment, and 'shver' indicates the // // one of two orientations of this subsegment, hence, it only can be 0 or 1. // // // // Mesh navigation and updating are accomplished through a set of mesh // // manipulation primitives which operate on trifaces and faces. They are // // introduced below. // // // /////////////////////////////////////////////////////////////////////////////// class triface { public: tetrahedron* tet; int loc, ver; // Constructors; triface() : tet(0), loc(0), ver(0) {} // Operators; triface& operator=(const triface& t) { tet = t.tet; loc = t.loc; ver = t.ver; return *this; } bool operator==(triface& t) { return tet == t.tet && loc == t.loc && ver == t.ver; } bool operator!=(triface& t) { return tet != t.tet || loc != t.loc || ver != t.ver; } }; class face { public: shellface *sh; int shver; // Constructors; face() : sh(0), shver(0) {} // Operators; face& operator=(const face& s) { sh = s.sh; shver = s.shver; return *this; } bool operator==(face& s) {return (sh == s.sh) && (shver == s.shver);} bool operator!=(face& s) {return (sh != s.sh) || (shver != s.shver);} }; /////////////////////////////////////////////////////////////////////////////// // // // The badface structure // // // // A multiple usages structure. Despite of its name, a 'badface' can be used // // to represent the following objects: // // - a face of a tetrahedron which is (possibly) non-Delaunay; // // - an encroached subsegment or subface; // // - a bad-quality tetrahedron, i.e, has too large radius-edge ratio; // // - a sliver, i.e., has good radius-edge ratio but nearly zero volume; // // - a degenerate tetrahedron (see routine checkdegetet()). // // - a recently flipped face (saved for undoing the flip later). // // // // It has the following fields: 'tt' holds a tetrahedron; 'ss' holds a sub- // // segment or subface; 'cent' is the circumcent of 'tt' or 'ss', 'key' is a // // special value depending on the use, it can be either the square of the // // radius-edge ratio of 'tt' or the flipped type of 'tt'; 'forg', 'fdest', // // 'fapex', and 'foppo' are vertices saved for checking the object in 'tt' // // or 'ss' is still the same when it was stored; 'noppo' is the fifth vertex // // of a degenerate point set. 'previtem' and 'nextitem' implement a double // // link for managing many basfaces. // // // /////////////////////////////////////////////////////////////////////////////// struct badface { triface tt; face ss; REAL key; REAL cent[3]; point forg, fdest, fapex, foppo; point noppo; struct badface *previtem, *nextitem; }; /////////////////////////////////////////////////////////////////////////////// // // // Elementary flip data structure // // // // A data structure to record three types of elementary flips, which are // // 2-to-3, 3-to-2, and 2-to-2 flips. // // // /////////////////////////////////////////////////////////////////////////////// class elemflip { public: enum fliptype ft; // ft \in {T23, T32, T22}. point pset1[3]; point pset2[3]; elemflip() { ft = T23; // Default. pset1[0] = pset1[1] = pset1[2] = (point) NULL; pset2[0] = pset2[1] = pset2[2] = (point) NULL; } }; /////////////////////////////////////////////////////////////////////////////// // // // The pbcdata structure // // // // A pbcdata stores data of a periodic boundary condition defined on a pair // // of facets or segments. Let f1 and f2 define a pbcgroup. 'fmark' saves the // // facet markers of f1 and f2; 'ss' contains two subfaces belong to f1 and // // f2, respectively. Let s1 and s2 define a segment pbcgroup. 'segid' are // // the segment ids of s1 and s2; 'ss' contains two segments belong to s1 and // // s2, respectively. 'transmat' are two transformation matrices. transmat[0] // // transforms a point of f1 (or s1) into a point of f2 (or s2), transmat[1] // // does the inverse. // // // /////////////////////////////////////////////////////////////////////////////// struct pbcdata { int fmark[2]; int segid[2]; face ss[2]; REAL transmat[2][4][4]; }; /////////////////////////////////////////////////////////////////////////////// // // // Fast lookup tables for mesh manipulation primitives. // // // // Mesh manipulation primitives (given below) are basic operations on mesh // // data structures. They answer basic queries on mesh handles, such as "what // // is the origin (or destination, or apex) of the face?", "what is the next // // (or previous) edge in the edge ring?", and "what is the next face in the // // face ring?", and so on. // // // // The implementation of teste basic queries can take advangtage of the fact // // that the mesh data structures additionally store geometric informations. // // For example, we have ordered the 4 vertices (from 0 to 3) and the 4 faces // // (from 0 to 3) of a tetrahedron, and for each face of the tetrahedron, a // // sequence of vertices has stipulated, therefore the origin of any face of // // the tetrahedron can be quickly determined by a table 'locver2org', which // // takes the index of the face and the edge version as inputs. A list of // // fast lookup tables are defined below. They're just like global variables. // // These tables are initialized at the runtime. // // // /////////////////////////////////////////////////////////////////////////////// // For enext() primitive, uses 'ver' as the index. static int ve[6]; // For org(), dest() and apex() primitives, uses 'ver' as the index. static int vo[6], vd[6], va[6]; // For org(), dest() and apex() primitives, uses 'loc' as the first // index and 'ver' as the second index. static int locver2org[4][6]; static int locver2dest[4][6]; static int locver2apex[4][6]; // For oppo() primitives, uses 'loc' as the index. static int loc2oppo[4]; // For fnext() primitives, uses 'loc' as the first index and 'ver' as // the second index, returns an array containing a new 'loc' and a // new 'ver'. Note: Only valid for 'ver' equals one of {0, 2, 4}. static int locver2nextf[4][6][2]; // The edge number (from 0 to 5) of a tet is defined as follows: static int locver2edge[4][6]; static int edge2locver[6][2]; // The map from a given face ('loc') to the other three faces in the tet. // and the map from a given face's edge ('loc', 'ver') to other two // faces in the tet opposite to this edge. (used in speeding the Bowyer- // Watson cavity construction). static int locpivot[4][3]; static int locverpivot[4][6][2]; // For enumerating three edges of a triangle. static int plus1mod3[3]; static int minus1mod3[3]; /////////////////////////////////////////////////////////////////////////////// // // // Mesh manipulation primitives // // // // A serial of mesh operations such as topological maintenance, navigation, // // local modification, etc., is accomplished through a set of mesh manipul- // // ation primitives. These primitives are indeed very simple functions which // // take one or two handles ('triface's and 'face's) as parameters, perform // // basic operations such as "glue two tetrahedra at a face", "return the // // origin of a tetrahedron", "return the subface adjoining at the face of a // // tetrahedron", and so on. // // // /////////////////////////////////////////////////////////////////////////////// // Primitives for tetrahedra. inline void decode(tetrahedron ptr, triface& t); inline tetrahedron encode(triface& t); inline void sym(triface& t1, triface& t2); inline void symself(triface& t); inline void bond(triface& t1, triface& t2); inline void dissolve(triface& t); inline point org(triface& t); inline point dest(triface& t); inline point apex(triface& t); inline point oppo(triface& t); inline void setorg(triface& t, point pointptr); inline void setdest(triface& t, point pointptr); inline void setapex(triface& t, point pointptr); inline void setoppo(triface& t, point pointptr); inline void esym(triface& t1, triface& t2); inline void esymself(triface& t); inline void enext(triface& t1, triface& t2); inline void enextself(triface& t); inline void enext2(triface& t1, triface& t2); inline void enext2self(triface& t); inline bool fnext(triface& t1, triface& t2); inline bool fnextself(triface& t); inline void symedge(triface& t1, triface& t2); inline void symedgeself(triface& t); inline void tfnext(triface& t1, triface& t2); inline void tfnextself(triface& t); inline void enextfnext(triface& t1, triface& t2); inline void enextfnextself(triface& t); inline void enext2fnext(triface& t1, triface& t2); inline void enext2fnextself(triface& t); inline REAL elemattribute(tetrahedron* ptr, int attnum); inline void setelemattribute(tetrahedron* ptr, int attnum, REAL value); inline REAL volumebound(tetrahedron* ptr); inline void setvolumebound(tetrahedron* ptr, REAL value); inline int getelemmarker(tetrahedron* ptr); inline void setelemmarker(tetrahedron* ptr, int value); inline void infect(triface& t); inline void uninfect(triface& t); inline bool infected(triface& t); inline void marktest(triface& t); inline void unmarktest(triface& t); inline bool marktested(triface& t); inline void markface(triface& t); inline void unmarkface(triface& t); inline bool facemarked(triface& t); inline void markedge(triface& t); inline void unmarkedge(triface& t); inline bool edgemarked(triface& t); // Primitives for subfaces and subsegments. inline void sdecode(shellface sptr, face& s); inline shellface sencode(face& s); inline void spivot(face& s1, face& s2); inline void spivotself(face& s); inline void sbond(face& s1, face& s2); inline void sbond1(face& s1, face& s2); inline void sdissolve(face& s); inline point sorg(face& s); inline point sdest(face& s); inline point sapex(face& s); inline void setsorg(face& s, point pointptr); inline void setsdest(face& s, point pointptr); inline void setsapex(face& s, point pointptr); inline void sesym(face& s1, face& s2); inline void sesymself(face& s); inline void senext(face& s1, face& s2); inline void senextself(face& s); inline void senext2(face& s1, face& s2); inline void senext2self(face& s); inline void sfnext(face&, face&); inline void sfnextself(face&); inline badface* shell2badface(face& s); inline void setshell2badface(face& s, badface* value); inline REAL areabound(face& s); inline void setareabound(face& s, REAL value); inline int shellmark(face& s); inline void setshellmark(face& s, int value); inline enum shestype shelltype(face& s); inline void setshelltype(face& s, enum shestype value); inline int shellpbcgroup(face& s); inline void setshellpbcgroup(face& s, int value); inline void sinfect(face& s); inline void suninfect(face& s); inline bool sinfected(face& s); // Primitives for interacting tetrahedra and subfaces. inline void tspivot(triface& t, face& s); inline void stpivot(face& s, triface& t); inline void tsbond(triface& t, face& s); inline void tsdissolve(triface& t); inline void stdissolve(face& s); // Primitives for interacting subfaces and subsegs. inline void sspivot(face& s, face& edge); inline void ssbond(face& s, face& edge); inline void ssdissolve(face& s); inline void tsspivot1(triface& t, face& seg); inline void tssbond1(triface& t, face& seg); inline void tssdissolve1(triface& t); // Primitives for points. inline int pointmark(point pt); inline void setpointmark(point pt, int value); inline enum verttype pointtype(point pt); inline void setpointtype(point pt, enum verttype value); inline void pinfect(point pt); inline void puninfect(point pt); inline bool pinfected(point pt); inline tetrahedron point2tet(point pt); inline void setpoint2tet(point pt, tetrahedron value); inline shellface point2sh(point pt); inline void setpoint2sh(point pt, shellface value); inline shellface point2seg(point pt); inline void setpoint2seg(point pt, shellface value); inline point point2ppt(point pt); inline void setpoint2ppt(point pt, point value); inline tetrahedron point2bgmtet(point pt); inline void setpoint2bgmtet(point pt, tetrahedron value); inline point point2pbcpt(point pt); inline void setpoint2pbcpt(point pt, point value); // Advanced primitives. inline void adjustedgering(triface& t, int direction); inline void adjustedgering(face& s, int direction); inline bool isdead(triface* t); inline bool isdead(face* s); inline bool isfacehaspoint(triface* t, point testpoint); inline bool isfacehaspoint(face* t, point testpoint); inline bool isfacehasedge(face* s, point tend1, point tend2); inline bool issymexist(triface* t); void getnextsface(face*, face*); void tsspivot(triface*, face*); void sstpivot(face*, triface*); void point2tetorg(point, triface&); void point2shorg(point, face&); void point2segorg(point, face&); bool findorg(triface* t, point dorg); bool findorg(face* s, point dorg); void findedge(triface* t, point eorg, point edest); void findedge(face* s, point eorg, point edest); void getonextseg(face* s, face* lseg); void getseghasorg(face* sseg, point dorg); point getsubsegfarorg(face* sseg); point getsubsegfardest(face* sseg); void printtet(triface*); void printsh(face*); /////////////////////////////////////////////////////////////////////////////// // // // Arraypool // // // // Each arraypool contains an array of pointers to a number of blocks. Each // // block contains the same fixed number of objects. Each index of the array // // addesses a particular object in the pool. The most significant bits add- // // ress the index of the block containing the object. The less significant // // bits address this object within the block. // // // // 'objectbytes' is the size of one object in blocks; 'log2objectsperblock' // // is the base-2 logarithm of 'objectsperblock'; 'objects' counts the number // // of allocated objects; 'totalmemory' is the totoal memorypool in bytes. // // // /////////////////////////////////////////////////////////////////////////////// class arraypool { public: int objectbytes; int objectsperblock; int log2objectsperblock; int toparraylen; char **toparray; unsigned long objects; unsigned long totalmemory; void restart(); void poolinit(int sizeofobject, int log2objperblk); char* getblock(int objectindex); void* lookup(int objectindex); int newindex(void **newptr); arraypool(int sizeofobject, int log2objperblk); ~arraypool(); }; // fastlookup() -- A fast, unsafe operation. Return the pointer to the object // with a given index. Note: The object's block must have been allocated, // i.e., by the function newindex(). #define fastlookup(pool, index) \ (void *) ((pool)->toparray[(index) >> (pool)->log2objectsperblock] + \ ((index) & ((pool)->objectsperblock - 1)) * (pool)->objectbytes) // A function: int cmp(const T &, const T &), is said to realize a // linear order on the type T if there is a linear order <= on T such // that for all x and y in T satisfy the following relation: // -1 if x < y. // comp(x, y) = 0 if x is equivalent to y. // +1 if x > y. // A 'compfunc' is a pointer to a linear-order function. typedef int (*compfunc) (const void *, const void *); /////////////////////////////////////////////////////////////////////////////// // // // List // // // // An array of items with automatically reallocation of memory. // // // // 'base' is the starting address of the array. 'itembytes' is the size of // // each item in byte. // // // // 'items' is the number of items stored in list. 'maxitems' indicates how // // many items can be stored in this list. 'expandsize' is the increasing // // size (items) when the list is full. // // // // The index of list always starts from zero, i.e., for a list L contains // // n elements, the first element is L[0], and the last element is L[n-1]. // // // /////////////////////////////////////////////////////////////////////////////// class list { public: char *base; int itembytes; int items, maxitems, expandsize; compfunc comp; list(int itbytes, compfunc pcomp, int mitems = 256, int exsize = 128) { listinit(itbytes, pcomp, mitems, exsize); } ~list() { free(base); } void *operator[](int i) { return (void *) (base + i * itembytes); } void listinit(int itbytes, compfunc pcomp, int mitems, int exsize); void setcomp(compfunc compf) { comp = compf; } void clear() { items = 0; } int len() { return items; } void *append(void* appitem); void *insert(int pos, void* insitem); void del(int pos, int order); int hasitem(void* checkitem); }; /////////////////////////////////////////////////////////////////////////////// // // // Memorypool // // // // A type used to allocate memory. // // // // firstblock is the first block of items. nowblock is the block from which // // items are currently being allocated. nextitem points to the next slab // // of free memory for an item. deaditemstack is the head of a linked list // // (stack) of deallocated items that can be recycled. unallocateditems is // // the number of items that remain to be allocated from nowblock. // // // // Traversal is the process of walking through the entire list of items, and // // is separate from allocation. Note that a traversal will visit items on // // the "deaditemstack" stack as well as live items. pathblock points to // // the block currently being traversed. pathitem points to the next item // // to be traversed. pathitemsleft is the number of items that remain to // // be traversed in pathblock. // // // // itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest // // what sort of word the record is primarily made up of. alignbytes // // determines how new records should be aligned in memory. itembytes and // // itemwords are the length of a record in bytes (after rounding up) and // // words. itemsperblock is the number of items allocated at once in a // // single block. items is the number of currently allocated items. // // maxitems is the maximum number of items that have been allocated at // // once; it is the current number of items plus the number of records kept // // on deaditemstack. // // // /////////////////////////////////////////////////////////////////////////////// class memorypool { public: void **firstblock, **nowblock; void *nextitem; void *deaditemstack; void **pathblock; void *pathitem; wordtype itemwordtype; int alignbytes; int itembytes, itemwords; int itemsperblock; long items, maxitems; int unallocateditems; int pathitemsleft; memorypool(); memorypool(int, int, enum wordtype, int); ~memorypool(); void poolinit(int, int, enum wordtype, int); void restart(); void *alloc(); void dealloc(void*); void traversalinit(); void *traverse(); }; /////////////////////////////////////////////////////////////////////////////// // // // Queue // // // // A 'queue' is a FIFO data structure. // // // /////////////////////////////////////////////////////////////////////////////// class queue : public memorypool { public: void **head, **tail; int linkitembytes; int linkitems; // Not count 'head' and 'tail'. queue(int bytecount, int itemcount = 256) { linkitembytes = bytecount; poolinit(bytecount + sizeof(void *), itemcount, POINTER, 0); head = (void **) alloc(); tail = (void **) alloc(); *head = (void *) tail; *tail = NULL; linkitems = 0; } void clear() { // Reset the pool. restart(); // Initialize all variables. head = (void **) alloc(); tail = (void **) alloc(); *head = (void *) tail; *tail = NULL; linkitems = 0; } long len() { return linkitems; } bool empty() { return linkitems == 0; } void *push(void* newitem) { void **newnode = tail; if (newitem != (void *) NULL) { memcpy((void *)(newnode + 1), newitem, linkitembytes); } tail = (void **) alloc(); *tail = NULL; *newnode = (void *) tail; linkitems++; return (void *)(newnode + 1); } void *pop() { if (linkitems > 0) { void **deadnode = (void **) *head; *head = *deadnode; dealloc((void *) deadnode); linkitems--; return (void *)(deadnode + 1); } else { return NULL; } } }; /////////////////////////////////////////////////////////////////////////////// // // // Memory managment routines // // // /////////////////////////////////////////////////////////////////////////////// void dummyinit(int, int); void initializepools(); void tetrahedrondealloc(tetrahedron*); tetrahedron *tetrahedrontraverse(); void shellfacedealloc(memorypool*, shellface*); shellface *shellfacetraverse(memorypool*); void badfacedealloc(memorypool*, badface*); badface *badfacetraverse(memorypool*); void pointdealloc(point); point pointtraverse(); void maketetrahedron(triface*); void makeshellface(memorypool*, face*); void makepoint(point*); void makepoint2tetmap(); void makepoint2segmap(); void makeindex2pointmap(point*&); void makesegmentmap(int*&, shellface**&); void makesubfacemap(int*&, shellface**&); void maketetrahedronmap(int*&, tetrahedron**&); /////////////////////////////////////////////////////////////////////////////// // // // Geometric functions // // // /////////////////////////////////////////////////////////////////////////////// // PI is the ratio of a circle's circumference to its diameter. static REAL PI; // Triangle-triangle intersection test enum interresult edge_vert_col_inter(REAL*, REAL*, REAL*); enum interresult edge_edge_cop_inter(REAL*, REAL*, REAL*, REAL*, REAL*); enum interresult tri_vert_cop_inter(REAL*, REAL*, REAL*, REAL*, REAL*); enum interresult tri_edge_cop_inter(REAL*, REAL*, REAL*,REAL*,REAL*,REAL*); enum interresult tri_edge_inter_tail(REAL*, REAL*, REAL*, REAL*, REAL*, REAL, REAL); enum interresult tri_edge_inter(REAL*, REAL*, REAL*, REAL*, REAL*); enum interresult tri_tri_inter(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*); int tri_edge_2d(point, point, point, point, point, point, int, int*, int*); int tri_edge_test(point, point, point, point, point, point, int, int*, int*); // Geometric tests REAL incircle3d(point pa, point pb, point pc, point pd); REAL insphere_s(REAL*, REAL*, REAL*, REAL*, REAL*); bool iscollinear(REAL*, REAL*, REAL*, REAL eps); bool iscoplanar(REAL*, REAL*, REAL*, REAL*, REAL vol6, REAL eps); bool iscospheric(REAL*, REAL*, REAL*, REAL*, REAL*, REAL vol24, REAL eps); // Linear algebra functions inline REAL dot(REAL* v1, REAL* v2); inline void cross(REAL* v1, REAL* v2, REAL* n); bool lu_decmp(REAL lu[4][4], int n, int* ps, REAL* d, int N); void lu_solve(REAL lu[4][4], int n, int* ps, REAL* b, int N); // Geometric calculations inline REAL distance(REAL* p1, REAL* p2); REAL shortdistance(REAL* p, REAL* e1, REAL* e2); REAL shortdistance(REAL* p, REAL* e1, REAL* e2, REAL* e3); REAL interiorangle(REAL* o, REAL* p1, REAL* p2, REAL* n); void projpt2edge(REAL* p, REAL* e1, REAL* e2, REAL* prj); void projpt2face(REAL* p, REAL* f1, REAL* f2, REAL* f3, REAL* prj); void facenormal(REAL* pa, REAL* pb, REAL* pc, REAL* n, REAL* nlen); void facenormal2(point pa, point pb, point pc, REAL *n, int pivot); void edgeorthonormal(REAL* e1, REAL* e2, REAL* op, REAL* n); REAL facedihedral(REAL* pa, REAL* pb, REAL* pc1, REAL* pc2); void tetalldihedral(point, point, point, point, REAL*, REAL*, REAL*); void tetallnormal(point, point, point, point, REAL N[4][3], REAL* volume); REAL tetaspectratio(point, point, point, point); bool circumsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius); void inscribedsphere(REAL*, REAL*, REAL*, REAL*, REAL* cent, REAL* radius); void rotatepoint(REAL* p, REAL rotangle, REAL* p1, REAL* p2); void planelineint(REAL*, REAL*, REAL*, REAL*, REAL*, REAL*, REAL*); // Point location routines. unsigned long randomnation(unsigned int choices); REAL distance2(tetrahedron* tetptr, point p); void randomsample(point searchpt, triface *searchtet); enum locateresult locate(point searchpt, triface* searchtet); enum locateresult locate2(point searchpt, triface* searchtet, arraypool*); enum locateresult preciselocate(point searchpt, triface* searchtet, long); enum locateresult adjustlocate(point, triface*, enum locateresult, REAL); enum locateresult hullwalk(point searchpt, triface* hulltet); enum locateresult locatesub(point searchpt, face* searchsh, int, REAL); enum locateresult adjustlocatesub(point, face*, enum locateresult, REAL); enum locateresult locateseg(point searchpt, face* searchseg); enum locateresult adjustlocateseg(point, face*, enum locateresult, REAL); /////////////////////////////////////////////////////////////////////////////// // // // Mesh update functions // // // /////////////////////////////////////////////////////////////////////////////// void enqueueflipface(triface&, queue*); void enqueueflipedge(face&, queue*); void flip23(triface*, queue*); void flip32(triface*, queue*); void flip22(triface*, queue*); void flip22sub(face*, queue*); long lawson3d(queue* flipqueue); long lawson(queue* flipqueue); bool removetetbypeeloff(triface *striptet, triface*); bool removefacebyflip23(REAL *key, triface*, triface*, queue*); bool removeedgebyflip22(REAL *key, int, triface*, queue*); bool removeedgebyflip32(REAL *key, triface*, triface*, queue*); bool removeedgebytranNM(REAL*,int,triface*,triface*,point,point,queue*); bool removeedgebycombNM(REAL*,int,triface*,int*,triface*,triface*,queue*); void splittetrahedron(point, triface*, queue*); void splittetface(point, triface*, queue*); void splitsubface(point, face*, queue*); bool splittetedge(point, triface*, queue*); void splitsubedge(point, face*, queue*); void formstarpolyhedron(point pt, list* tetlist, list* verlist, bool); void formbowatcavitysub(point, face*, list*, list*); void formbowatcavityquad(point, list*, list*); void formbowatcavitysegquad(point, list*, list*); void formbowatcavity(point bp, face* bpseg, face* bpsh, int* n, int* nmax, list** sublists, list** subceillists, list** tetlists, list** ceillists); void releasebowatcavity(face*, int, list**, list**, list**, list**); bool validatebowatcavityquad(point bp, list* ceillist, REAL maxcosd); void updatebowatcavityquad(list* tetlist, list* ceillist); void updatebowatcavitysub(list* sublist, list* subceillist, int* cutcount); bool trimbowatcavity(point bp, face* bpseg, int n, list** sublists, list** subceillists, list** tetlists,list** ceillists, REAL maxcosd); void bowatinsertsite(point bp, face* splitseg, int n, list** sublists, list** subceillists, list** tetlists, list** ceillists, list* verlist, queue* flipque, bool chkencseg, bool chkencsub, bool chkbadtet); /////////////////////////////////////////////////////////////////////////////// // // // Delaunay tetrahedralization functions // // // /////////////////////////////////////////////////////////////////////////////// enum locateresult insertvertexbw(point insertpt, triface *searchtet, bool bwflag, bool visflag, bool noencsegflag, bool noencsubflag); bool unifypoint(point testpt, triface*, enum locateresult, REAL); bool incrflipdelaunay(triface*, point*, long, bool, bool, REAL, queue*); long delaunizevertices(); /////////////////////////////////////////////////////////////////////////////// // // // Surface triangulation functions // // // /////////////////////////////////////////////////////////////////////////////// enum locateresult sinsertvertex(point insertpt, face *splitsh,face *splitseg, bool bwflag, bool cflag); void formstarpolygon(point pt, list* trilist, list* verlist); void getfacetabovepoint(face* facetsh); bool incrflipdelaunaysub(int shmark, REAL eps, list*, int, REAL*, queue*); enum finddirectionresult finddirectionsub(face* searchsh, point tend); void insertsubseg(face* tri); bool scoutsegmentsub(face* searchsh, point tend); void flipedgerecursive(face* flipedge, queue* flipqueue); void constrainededge(face* startsh, point tend, queue* flipqueue); void recoversegment(point tstart, point tend, queue* flipqueue); void infecthullsub(memorypool* viri); void plaguesub(memorypool* viri); void carveholessub(int holes, REAL* holelist, memorypool* viri); void triangulate(int shmark, REAL eps, list* ptlist, list* conlist,int holes, REAL* holelist, memorypool* viri, queue*); void retrievenewsubs(list* newshlist, bool removeseg); void unifysegments(); void assignsegmentmarkers(); void mergefacets(queue* flipqueue); long meshsurface(); // Detect intersecting facets of PLC. void interecursive(shellface** subfacearray, int arraysize, int axis, REAL bxmin, REAL bxmax, REAL bymin, REAL bymax, REAL bzmin, REAL bzmax, int* internum); void detectinterfaces(); /////////////////////////////////////////////////////////////////////////////// // // // Constrained Delaunay tetrahedralization functions // // // /////////////////////////////////////////////////////////////////////////////// // Segment recovery routines. void markacutevertices(REAL acuteangle); enum finddirectionresult finddirection(triface* searchtet, point, long); enum interresult finddirection2(triface* searchtet, point); enum interresult finddirection3(triface* searchtet, point); enum interresult scoutsegment2(face*, triface*, point*); void getsegmentsplitpoint2(face* sseg, point refpt, REAL* vt); void delaunizesegments2(); // Facets recovery routines. enum interresult scoutsubface(face* ssub, triface* searchtet, int); enum interresult scoutcrosstet(face* ssub, triface* searchtet, arraypool*); void recoversubfacebyflips(face* pssub, triface* crossface, arraypool*); void formcavity(face*, arraypool*, arraypool*, arraypool*, arraypool*, arraypool*, arraypool*, arraypool*); bool delaunizecavity(arraypool*, arraypool*, arraypool*, arraypool*, arraypool*, arraypool*); bool fillcavity(arraypool*, arraypool*, arraypool*, arraypool*); void carvecavity(arraypool*, arraypool*, arraypool*); void restorecavity(arraypool*, arraypool*, arraypool*); void splitsubedge(point, face*, arraypool*, arraypool*); void constrainedfacets2(); void formskeleton(clock_t&); // Carving out holes and concavities routines. void infecthull(memorypool *viri); void plague(memorypool *viri); void regionplague(memorypool *viri, REAL attribute, REAL volume); void removeholetets(memorypool *viri); void assignregionattribs(); void carveholes(); /////////////////////////////////////////////////////////////////////////////// // // // Steiner points removal functions // // // /////////////////////////////////////////////////////////////////////////////// void initializecavity(list* floorlist, list* ceillist, list* frontlist, list* ptlist, list* gluelist); bool delaunizecavvertices(triface*, list*, list*, list*, queue*); void retrievenewtets(list* newtetlist); void insertauxsubface(triface* front, triface* idfront); bool scoutfront(triface* front, triface* idfront); void gluefronts(triface* front, triface* front1, list* gluetetlist, list* glueshlist); bool identifyfronts(list* frontlist,list* misfrontlist,list* gluetetlist, list* glueshlist); void detachauxsubfaces(list* newtetlist); bool carvecavity(list* newtetlist, list* outtetlist, list* gluetetlist, queue* flipque); void replacepolygonsubs(list* oldshlist, list* newshlist); void orientnewsubs(list* newshlist, face* orientsh, REAL* norm); bool registerelemflip(enum fliptype ft, point pa1, point pb1, point pc1, point pa2, point pb2, point pc2); bool check4fixededge(point pa, point pb); bool removeedgebyflips(triface* remedge, int*); bool removefacebyflips(triface* remface, int*); bool recoveredgebyflips(triface* searchtet, point pb, int*); bool recoverfacebyflips(triface* front, int*); bool constrainedcavity(triface* oldtet, list* floorlist, list* ceillist, list* ptlist, list* frontlist, list* misfrontlist, list* newtetlist, list* gluetetlist, list* glueshlist, queue* flipque); bool findrelocatepoint2(point sp, point np, REAL* n, list*, list*); bool relocatepoint(point steinpt, triface* oldtet, list*, list*, queue*); bool findcollapseedge(point suppt, point* conpt, list* oldtetlist, list*); void collapseedge(point suppt, point conpt, list* oldtetlist, list*); void deallocfaketets(list* frontlist); void restorepolyhedron(list* oldtetlist); bool suppressfacetpoint(face* supsh, list* frontlist, list* misfrontlist, list* ptlist, list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag); bool suppresssegpoint(face* supseg, list* spinshlist, list* newsegshlist, list* frontlist, list* misfrontlist, list* ptlist, list* conlist, memorypool* viri, queue* flipque, bool noreloc, bool optflag); bool suppressvolpoint(triface* suptet, list* frontlist, list* misfrontlist, list* ptlist, queue* flipque, bool optflag); void removesteiners2(); /////////////////////////////////////////////////////////////////////////////// // // // Mesh rebuild functions // // // /////////////////////////////////////////////////////////////////////////////// void transfernodes(); long reconstructmesh(); void insertconstrainedpoints(tetgenio *addio); bool p1interpolatebgm(point pt, triface* bgmtet, long *scount); void interpolatesizemap(); void duplicatebgmesh(); /////////////////////////////////////////////////////////////////////////////// // // // Mesh refinement functions // // // /////////////////////////////////////////////////////////////////////////////// void marksharpsegments(REAL sharpangle); void decidefeaturepointsizes(); void enqueueencsub(face* ss, point encpt, int quenumber, REAL* cent); badface* dequeueencsub(int* quenumber); void enqueuebadtet(triface* tt, REAL key, REAL* cent); badface* topbadtetra(); void dequeuebadtet(); bool checkseg4encroach(face* testseg, point testpt, point*, bool enqflag); bool checksub4encroach(face* testsub, point testpt, bool enqflag); bool checktet4badqual(triface* testtet, bool enqflag); bool acceptsegpt(point segpt, point refpt, face* splitseg); bool acceptfacpt(point facpt, list* subceillist, list* verlist); bool acceptvolpt(point volpt, list* ceillist, list* verlist); void getsplitpoint(point e1, point e2, point refpt, point newpt); void setnewpointsize(point newpt, point e1, point e2); bool splitencseg(point, face*, list*, list*, list*,queue*,bool,bool,bool); bool tallencsegs(point testpt, int n, list** ceillists); bool tallencsubs(point testpt, int n, list** ceillists); void tallbadtetrahedrons(); void repairencsegs(bool chkencsub, bool chkbadtet); void repairencsubs(bool chkbadtet); void repairbadtets(); void enforcequality(); /////////////////////////////////////////////////////////////////////////////// // // // Mesh optimization routines // // // /////////////////////////////////////////////////////////////////////////////// bool checktet4ill(triface* testtet, bool enqflag); bool checktet4opt(triface* testtet, bool enqflag); bool removeedge(badface* remedge, bool optflag); bool smoothpoint(point smthpt, point, point, list*, bool, REAL*); bool smoothsliver(badface* remedge, list *starlist); bool splitsliver(badface* remedge, list *tetlist, list *ceillist); void tallslivers(bool optflag); void optimizemesh2(bool optflag); /////////////////////////////////////////////////////////////////////////////// // // // Mesh output functions // // // /////////////////////////////////////////////////////////////////////////////// void jettisonnodes(); void highorder(); void numberedges(); void outnodes(tetgenio*); void outmetrics(tetgenio*); void outelements(tetgenio*); void outfaces(tetgenio*); void outhullfaces(tetgenio*); void outsubfaces(tetgenio*); void outedges(tetgenio*); void outsubsegments(tetgenio*); void outneighbors(tetgenio*); void outvoronoi(tetgenio*); void outsmesh(char*); void outmesh2medit(char*); void outmesh2gid(char*); void outmesh2off(char*); void outmesh2vtk(char*); /////////////////////////////////////////////////////////////////////////////// // // // Mesh check functions // // // /////////////////////////////////////////////////////////////////////////////// int checkmesh(); int checkshells(); int checksegments(); int checkdelaunay(REAL, queue*); void checkconforming(); void algorithmicstatistics(); void qualitystatistics(); void statistics(); /////////////////////////////////////////////////////////////////////////////// // // // Class variables // // // /////////////////////////////////////////////////////////////////////////////// // Pointer to the input data (a set of nodes, a PLC, or a mesh). tetgenio *in; // Pointer to the options (and filenames). tetgenbehavior *b; // Pointer to a background mesh (contains size specification map). tetgenmesh *bgm; // Variables used to allocate and access memory for tetrahedra, subfaces // subsegments, points, encroached subfaces, encroached subsegments, // bad-quality tetrahedra, and so on. memorypool *tetrahedrons; memorypool *subfaces; memorypool *subsegs; memorypool *points; memorypool *badsubsegs; memorypool *badsubfaces; memorypool *badtetrahedrons; memorypool *tet2segpool, *tet2subpool; // Pointer to the 'tetrahedron' that occupies all of "outer space". tetrahedron *dummytet; tetrahedron *dummytetbase; // Keep base address so we can free it later. // Pointer to the omnipresent subface. Referenced by any tetrahedron, // or subface that isn't connected to a subface at that location. shellface *dummysh; shellface *dummyshbase; // Keep base address so we can free it later. // Arrays used by Bowyer-Watson algorithm. arraypool *cavetetlist, *cavebdrylist, *caveoldtetlist; arraypool *caveshlist, *caveshbdlist; // Stacks used by the boundary recovery algorithm. arraypool *subsegstack, *subfacstack; // Two handles used in constrained facet recovery. triface firsttopface, firstbotface; // An array for registering elementary flips. arraypool *elemfliplist; // An array of fixed edges for facet recovering by flips. arraypool *fixededgelist; // A point above the plane in which the facet currently being used lies. // It is used as a reference point for orient3d(). point *facetabovepointarray, abovepoint, dummypoint; // Array (size = numberoftetrahedra * 6) for storing high-order nodes of // tetrahedra (only used when -o2 switch is selected). point *highordertable; // Arrays for storing and searching pbc data. 'subpbcgrouptable', (size // is numberofpbcgroups) for pbcgroup of subfaces. 'segpbcgrouptable', // a list for pbcgroup of segments. Because a segment can have several // pbcgroup incident on it, its size is unknown on input, it will be // found in 'createsegpbcgrouptable()'. pbcdata *subpbcgrouptable; list *segpbcgrouptable; // A map for searching the pbcgroups of a given segment. 'idx2segpglist' // (size = number of input segments + 1), and 'segpglist'. int *idx2segpglist, *segpglist; // Queues that maintain the bad (badly-shaped or too large) tetrahedra. // The tails are pointers to the pointers that have to be filled in to // enqueue an item. The queues are ordered from 63 (highest priority) // to 0 (lowest priority). badface *subquefront[3], **subquetail[3]; badface *tetquefront[64], *tetquetail[64]; int nextnonemptyq[64]; int firstnonemptyq, recentq; // Pointer to a recently visited tetrahedron. Improves point location // if proximate points are inserted sequentially. triface recenttet; REAL xmax, xmin, ymax, ymin, zmax, zmin; // Bounding box of points. REAL longest; // The longest possible edge length. REAL lengthlimit; // The limiting length of a new edge. long hullsize; // Number of faces of convex hull. long insegments; // Number of input segments. long meshedges; // Number of output mesh edges. int steinerleft; // Number of Steiner points not yet used. int sizeoftensor; // Number of REALs per metric tensor. int pointmtrindex; // Index to find the metric tensor of a point. int point2simindex; // Index to find a simplex adjacent to a point. int pointmarkindex; // Index to find boundary marker of a point. int point2pbcptindex; // Index to find a pbc point to a point. int highorderindex; // Index to find extra nodes for highorder elements. int elemattribindex; // Index to find attributes of a tetrahedron. int volumeboundindex; // Index to find volume bound of a tetrahedron. int elemmarkerindex; // Index to find marker of a tetrahedron. int shmarkindex; // Index to find boundary marker of a subface. int areaboundindex; // Index to find area bound of a subface. int checksubfaces; // Are there subfaces in the mesh yet? int checksubsegs; // Are there subsegs in the mesh yet? int checkpbcs; // Are there periodic boundary conditions? int varconstraint; // Are there variant (node, seg, facet) constraints? int nonconvex; // Is current mesh non-convex? int dupverts; // Are there duplicated vertices? int unuverts; // Are there unused vertices? int relverts; // The number of relocated vertices. int suprelverts; // The number of suppressed relocated vertices. int collapverts; // The number of collapsed relocated vertices. int unsupverts; // The number of unsuppressed vertices. int smoothsegverts; // The number of smoothed vertices. int jettisoninverts; // The number of jettisoned input vertices. long samples; // Number of random samples for point location. unsigned long randomseed; // Current random number seed. REAL macheps; // The machine epsilon. REAL cosmaxdihed, cosmindihed; // The cosine values of max/min dihedral. REAL minfaceang, minfacetdihed; // The minimum input (dihedral) angles. int maxcavfaces, maxcavverts; // The size of the largest cavity. bool b_steinerflag; // Algorithm statistical counters. long ptloc_count, ptloc_max_count; long orient3dcount; long inspherecount, insphere_sos_count; long flip14count, flip26count, flipn2ncount; long flip22count; long inserthullcount; long maxbowatcavsize, totalbowatcavsize, totaldeadtets; long across_face_count, across_edge_count, across_max_count; long maxcavsize, maxregionsize; long ndelaunayedgecount, cavityexpcount; long opt_tet_peels, opt_face_flips, opt_edge_flips; long abovecount; // Number of abovepoints calculation. long bowatvolcount, bowatsubcount, bowatsegcount; // Bowyer-Watsons. long updvolcount, updsubcount, updsegcount; // Bow-Wat cavities updates. long failvolcount, failsubcount, failsegcount; // Bow-Wat fails. long outbowatcircumcount; // Number of circumcenters outside Bowat-cav. long r1count, r2count, r3count; // Numbers of edge splitting rules. long cdtenforcesegpts; // Number of CDT enforcement points. long rejsegpts, rejsubpts, rejtetpts; // Number of rejected points. long optcount[10]; // Numbers of various optimizing operations. long flip23s, flip32s, flip22s, flip44s; // Number of flips performed. /////////////////////////////////////////////////////////////////////////////// // // // Class constructor & destructor // // // /////////////////////////////////////////////////////////////////////////////// tetgenmesh() { bgm = (tetgenmesh *) NULL; in = (tetgenio *) NULL; b = (tetgenbehavior *) NULL; tetrahedrons = (memorypool *) NULL; subfaces = (memorypool *) NULL; subsegs = (memorypool *) NULL; points = (memorypool *) NULL; badsubsegs = (memorypool *) NULL; badsubfaces = (memorypool *) NULL; badtetrahedrons = (memorypool *) NULL; tet2segpool = NULL; tet2subpool = NULL; dummytet = (tetrahedron *) NULL; dummytetbase = (tetrahedron *) NULL; dummysh = (shellface *) NULL; dummyshbase = (shellface *) NULL; facetabovepointarray = (point *) NULL; abovepoint = (point) NULL; dummypoint = NULL; highordertable = (point *) NULL; subpbcgrouptable = (pbcdata *) NULL; segpbcgrouptable = (list *) NULL; idx2segpglist = (int *) NULL; segpglist = (int *) NULL; cavetetlist = NULL; cavebdrylist = NULL; caveoldtetlist = NULL; caveshlist = caveshbdlist = NULL; subsegstack = subfacstack = NULL; elemfliplist = (arraypool *) NULL; fixededgelist = (arraypool *) NULL; xmax = xmin = ymax = ymin = zmax = zmin = 0.0; longest = 0.0; hullsize = 0l; insegments = 0l; meshedges = 0l; pointmtrindex = 0; pointmarkindex = 0; point2simindex = 0; point2pbcptindex = 0; highorderindex = 0; elemattribindex = 0; volumeboundindex = 0; shmarkindex = 0; areaboundindex = 0; checksubfaces = 0; checksubsegs = 0; checkpbcs = 0; varconstraint = 0; nonconvex = 0; dupverts = 0; unuverts = 0; relverts = 0; suprelverts = 0; collapverts = 0; unsupverts = 0; jettisoninverts = 0; samples = 0l; randomseed = 1l; macheps = 0.0; minfaceang = minfacetdihed = PI; b_steinerflag = false; ptloc_count = ptloc_max_count = 0l; orient3dcount = 0l; inspherecount = insphere_sos_count = 0l; flip14count = flip26count = flipn2ncount = 0l; flip22count = 0l; inserthullcount = 0l; maxbowatcavsize = totalbowatcavsize = totaldeadtets = 0l; across_face_count = across_edge_count = across_max_count = 0l; maxcavsize = maxregionsize = 0l; ndelaunayedgecount = cavityexpcount = 0l; opt_tet_peels = opt_face_flips = opt_edge_flips = 0l; maxcavfaces = maxcavverts = 0; abovecount = 0l; bowatvolcount = bowatsubcount = bowatsegcount = 0l; updvolcount = updsubcount = updsegcount = 0l; outbowatcircumcount = 0l; failvolcount = failsubcount = failsegcount = 0l; r1count = r2count = r3count = 0l; cdtenforcesegpts = 0l; rejsegpts = rejsubpts = rejtetpts = 0l; flip23s = flip32s = flip22s = flip44s = 0l; } // tetgenmesh() ~tetgenmesh() { bgm = (tetgenmesh *) NULL; in = (tetgenio *) NULL; b = (tetgenbehavior *) NULL; if (tetrahedrons != (memorypool *) NULL) { delete tetrahedrons; } if (subfaces != (memorypool *) NULL) { delete subfaces; } if (subsegs != (memorypool *) NULL) { delete subsegs; } if (points != (memorypool *) NULL) { delete points; } if (tet2segpool != NULL) { delete tet2segpool; } if (tet2subpool != NULL) { delete tet2subpool; } if (dummytetbase != (tetrahedron *) NULL) { delete [] dummytetbase; } if (dummyshbase != (shellface *) NULL) { delete [] dummyshbase; } if (facetabovepointarray != (point *) NULL) { delete [] facetabovepointarray; } if (dummypoint != NULL) { delete [] dummypoint; } if (highordertable != (point *) NULL) { delete [] highordertable; } if (subpbcgrouptable != (pbcdata *) NULL) { delete [] subpbcgrouptable; } if (segpbcgrouptable != (list *) NULL) { delete segpbcgrouptable; delete [] idx2segpglist; delete [] segpglist; } if (cavetetlist != NULL) { delete cavetetlist; delete cavebdrylist; delete caveoldtetlist; } if (subsegstack != NULL) { delete subsegstack; } if (subfacstack != NULL) { delete subfacstack; } } // ~tetgenmesh() }; // End of class tetgenmesh. /////////////////////////////////////////////////////////////////////////////// // // // tetrahedralize() Interface for using TetGen's library to generate // // Delaunay tetrahedralizations, constrained Delaunay // // tetrahedralizations, quality tetrahedral meshes. // // // // 'in' is an object of 'tetgenio' which contains a PLC you want to tetrahed-// // ralize or a previously generated tetrahedral mesh you want to refine. It // // must not be a NULL. 'out' is another object of 'tetgenio' for storing the // // generated tetrahedral mesh. It can be a NULL. If so, the output will be // // saved to file(s). If 'bgmin' != NULL, it contains a background mesh which // // defines a mesh size distruction function. // // // /////////////////////////////////////////////////////////////////////////////// void tetrahedralize(tetgenbehavior *b, tetgenio *in, tetgenio *out, tetgenio *addin = NULL, tetgenio *bgmin = NULL); #ifdef TETLIBRARY void tetrahedralize(char *switches, tetgenio *in, tetgenio *out, tetgenio *addin = NULL, tetgenio *bgmin = NULL); #endif // #ifdef TETLIBRARY /////////////////////////////////////////////////////////////////////////////// // // // terminatetetgen() Terminate TetGen with a given exit code. // // // /////////////////////////////////////////////////////////////////////////////// inline void terminatetetgen(int x) { #ifdef TETLIBRARY throw x; #else switch (x) { case 1: // Out of memory. printf("Error: Out of memory.\n"); break; case 2: // Encounter an internal error. printf(" Please report this bug to sihang@mail.berlios.de. Include\n"); printf(" the message above, your input data set, and the exact\n"); printf(" command line you used to run this program, thank you.\n"); break; default: printf("Program stopped.\n"); } // switch (x) exit(x); #endif // #ifdef TETLIBRARY } /////////////////////////////////////////////////////////////////////////////// // // // Geometric predicates // // // // Return one of the values +1, 0, and -1 on basic geometric questions such // // as the orientation of point sets, in-circle, and in-sphere tests. They // // are basic units for implmenting geometric algorithms. TetGen uses two 3D // // geometric predicates: the orientation and in-sphere tests. // // // // Orientation test: let a, b, c be a sequence of 3 non-collinear points in // // R^3. They defines a unique hypeplane H. Let H+ and H- be the two spaces // // separated by H, which are defined as follows (using the left-hand rule): // // make a fist using your left hand in such a way that your fingers follow // // the order of a, b and c, then your thumb is pointing to H+. Given any // // point d in R^3, the orientation test returns +1 if d lies in H+, -1 if d // // lies in H-, or 0 if d lies on H. // // // // In-sphere test: let a, b, c, d be 4 non-coplanar points in R^3. They // // defines a unique circumsphere S. Given any point e in R^3, the in-sphere // // test returns +1 if e lies inside S, or -1 if e lies outside S, or 0 if e // // lies on S. // // // // The following routines use arbitrary precision floating-point arithmetic. // // They are provided by J. R. Schewchuk in public domain (http://www.cs.cmu. // // edu/~quake/robust.html). The source code are in "predicates.cxx". // // // /////////////////////////////////////////////////////////////////////////////// REAL exactinit(); REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd); REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe); /////////////////////////////////////////////////////////////////////////////// // // // Inline functions of mesh data structures // // // /////////////////////////////////////////////////////////////////////////////// // Some macros for convenience #define Div2 >> 1 #define Mod2 & 01 // NOTE: These bit operators should only be used in macros below. // Get orient(Range from 0 to 2) from face version(Range from 0 to 5). #define Orient(V) ((V) Div2) // Determine edge ring(0 or 1) from face version(Range from 0 to 5). #define EdgeRing(V) ((V) Mod2) // // Begin of primitives for tetrahedra // // Each tetrahedron contains four pointers to its neighboring tetrahedra, // with face indices. To save memory, both information are kept in a // single pointer. To make this possible, all tetrahedra are aligned to // eight-byte boundaries, so that the last three bits of each pointer are // zeros. A face index (in the range 0 to 3) is compressed into the last // two bits of each pointer by the function 'encode()'. The function // 'decode()' decodes a pointer, extracting a face index and a pointer to // the beginning of a tetrahedron. inline void tetgenmesh::decode(tetrahedron ptr, triface& t) { t.loc = (int) ((uintptr_t) (ptr) & (uintptr_t) 3); t.tet = (tetrahedron *) ((uintptr_t) (ptr) & ~(uintptr_t) 7); } inline tetgenmesh::tetrahedron tetgenmesh::encode(triface& t) { return (tetrahedron) ((uintptr_t) t.tet | (uintptr_t) t.loc); } // sym() finds the abutting tetrahedron on the same face. inline void tetgenmesh::sym(triface& t1, triface& t2) { tetrahedron ptr = t1.tet[t1.loc]; decode(ptr, t2); } inline void tetgenmesh::symself(triface& t) { tetrahedron ptr = t.tet[t.loc]; decode(ptr, t); } // Bond two tetrahedra together at their faces. inline void tetgenmesh::bond(triface& t1, triface& t2) { t1.tet[t1.loc] = encode(t2); t2.tet[t2.loc] = encode(t1); } // Dissolve a bond (from one side). Note that the other tetrahedron will // still think it is connected to this tetrahedron. Usually, however, // the other tetrahedron is being deleted entirely, or bonded to another // tetrahedron, so it doesn't matter. inline void tetgenmesh::dissolve(triface& t) { t.tet[t.loc] = (tetrahedron) dummytet; } // These primitives determine or set the origin, destination, apex or // opposition of a tetrahedron with respect to 'loc' and 'ver'. inline tetgenmesh::point tetgenmesh::org(triface& t) { return (point) t.tet[locver2org[t.loc][t.ver] + 4]; } inline tetgenmesh::point tetgenmesh::dest(triface& t) { return (point) t.tet[locver2dest[t.loc][t.ver] + 4]; } inline tetgenmesh::point tetgenmesh::apex(triface& t) { return (point) t.tet[locver2apex[t.loc][t.ver] + 4]; } inline tetgenmesh::point tetgenmesh::oppo(triface& t) { return (point) t.tet[loc2oppo[t.loc] + 4]; } inline void tetgenmesh::setorg(triface& t, point pointptr) { t.tet[locver2org[t.loc][t.ver] + 4] = (tetrahedron) pointptr; } inline void tetgenmesh::setdest(triface& t, point pointptr) { t.tet[locver2dest[t.loc][t.ver] + 4] = (tetrahedron) pointptr; } inline void tetgenmesh::setapex(triface& t, point pointptr) { t.tet[locver2apex[t.loc][t.ver] + 4] = (tetrahedron) pointptr; } inline void tetgenmesh::setoppo(triface& t, point pointptr) { t.tet[loc2oppo[t.loc] + 4] = (tetrahedron) pointptr; } // These primitives were drived from Mucke's triangle-edge data structure // to change face-edge relation in a tetrahedron (esym, enext and enext2) // or between two tetrahedra (fnext). // If e0 = e(i, j), e1 = e(j, i), that is e0 and e1 are the two directions // of the same undirected edge of a face. e0.sym() = e1 and vice versa. inline void tetgenmesh::esym(triface& t1, triface& t2) { t2.tet = t1.tet; t2.loc = t1.loc; t2.ver = t1.ver + (EdgeRing(t1.ver) ? -1 : 1); } inline void tetgenmesh::esymself(triface& t) { t.ver += (EdgeRing(t.ver) ? -1 : 1); } // If e0 and e1 are both in the same edge ring of a face, e1 = e0.enext(). inline void tetgenmesh::enext(triface& t1, triface& t2) { t2.tet = t1.tet; t2.loc = t1.loc; t2.ver = ve[t1.ver]; } inline void tetgenmesh::enextself(triface& t) { t.ver = ve[t.ver]; } // enext2() is equal to e2 = e0.enext().enext() inline void tetgenmesh::enext2(triface& t1, triface& t2) { t2.tet = t1.tet; t2.loc = t1.loc; t2.ver = ve[ve[t1.ver]]; } inline void tetgenmesh::enext2self(triface& t) { t.ver = ve[ve[t.ver]]; } // If f0 and f1 are both in the same face ring of a face, f1 = f0.fnext(). // If f1 exists, return true. Otherwise, return false, i.e., f0 is a // boundary or hull face. inline bool tetgenmesh::fnext(triface& t1, triface& t2) { // Get the next face. t2.loc = locver2nextf[t1.loc][t1.ver][0]; // Is the next face in the same tet? if (t2.loc != -1) { // It's in the same tet. Get the edge version. t2.ver = locver2nextf[t1.loc][t1.ver][1]; t2.tet = t1.tet; } else { // The next face is in the neigbhour of 't1'. sym(t1, t2); if (t2.tet != dummytet) { // Find the corresponding edge in t2. point torg; int tloc, tver, i; t2.ver = 0; torg = org(t1); for (i = 0; (i < 3) && (org(t2) != torg); i++) { enextself(t2); } // Go to the next face in t2. tloc = t2.loc; tver = t2.ver; t2.loc = locver2nextf[tloc][tver][0]; t2.ver = locver2nextf[tloc][tver][1]; } } return t2.tet != dummytet; } inline bool tetgenmesh::fnextself(triface& t1) { triface t2; // Get the next face. t2.loc = locver2nextf[t1.loc][t1.ver][0]; // Is the next face in the same tet? if (t2.loc != -1) { // It's in the same tet. Get the edge version. t2.ver = locver2nextf[t1.loc][t1.ver][1]; t1.loc = t2.loc; t1.ver = t2.ver; } else { // The next face is in the neigbhour of 't1'. sym(t1, t2); if (t2.tet != dummytet) { // Find the corresponding edge in t2. point torg; int i; t2.ver = 0; torg = org(t1); for (i = 0; (i < 3) && (org(t2) != torg); i++) { enextself(t2); } t1.loc = locver2nextf[t2.loc][t2.ver][0]; t1.ver = locver2nextf[t2.loc][t2.ver][1]; t1.tet = t2.tet; } } return t2.tet != dummytet; } // Given a face t1, find the face f2 in the adjacent tet. If t2 is not // a dummytet, then t1 and t2 refer to the same edge. Moreover, t2's // edge must be in 0th edge ring, e.g., t2.ver is one of {0, 2, 4}. // No matter what edge version t1 is. inline void tetgenmesh::symedge(triface& t1, triface& t2) { decode(t1.tet[t1.loc], t2); if (t2.tet != dummytet) { // Search the edge of t1 in t2. point tapex = apex(t1); if ((point) (t2.tet[locver2apex[t2.loc][0] + 4]) == tapex) { t2.ver = 0; } else if ((point) (t2.tet[locver2apex[t2.loc][2] + 4]) == tapex) { t2.ver = 2; } else { assert((point) (t2.tet[locver2apex[t2.loc][4] + 4]) == tapex); t2.ver = 4; } } } inline void tetgenmesh::symedgeself(triface& t) { tetrahedron ptr; point tapex; ptr = t.tet[t.loc]; tapex = apex(t); decode(ptr, t); if (t.tet != dummytet) { // Search the edge of t1 in t2. if ((point) (t.tet[locver2apex[t.loc][0] + 4]) == tapex) { t.ver = 0; } else if ((point) (t.tet[locver2apex[t.loc][2] + 4]) == tapex) { t.ver = 2; } else { assert((point) (t.tet[locver2apex[t.loc][4] + 4]) == tapex); t.ver = 4; } } } // Given a face t1, find the next face t2 in the face ring, t1 and t2 // are in two different tetrahedra. If the next face is a hull face, // t2 is dummytet. inline void tetgenmesh::tfnext(triface& t1, triface& t2) { int *iptr; if ((t1.ver & 1) == 0) { t2.tet = t1.tet; iptr = locver2nextf[t1.loc][t1.ver]; t2.loc = iptr[0]; t2.ver = iptr[1]; symedgeself(t2); // t2.tet may be dummytet. } else { symedge(t1, t2); if (t2.tet != dummytet) { iptr = locver2nextf[t2.loc][t2.ver]; t2.loc = iptr[0]; t2.ver = iptr[1]; } } } inline void tetgenmesh::tfnextself(triface& t) { int *iptr; if ((t.ver & 1) == 0) { iptr = locver2nextf[t.loc][t.ver]; t.loc = iptr[0]; t.ver = iptr[1]; symedgeself(t); // t.tet may be dummytet. } else { symedgeself(t); if (t.tet != dummytet) { iptr = locver2nextf[t.loc][t.ver]; t.loc = iptr[0]; t.ver = iptr[1]; } } } // enextfnext() and enext2fnext() are combination primitives of enext(), // enext2() and fnext(). inline void tetgenmesh::enextfnext(triface& t1, triface& t2) { enext(t1, t2); fnextself(t2); } inline void tetgenmesh::enextfnextself(triface& t) { enextself(t); fnextself(t); } inline void tetgenmesh::enext2fnext(triface& t1, triface& t2) { enext2(t1, t2); fnextself(t2); } inline void tetgenmesh::enext2fnextself(triface& t) { enext2self(t); fnextself(t); } // Check or set a tetrahedron's attributes. inline REAL tetgenmesh::elemattribute(tetrahedron* ptr, int attnum) { return ((REAL *) (ptr))[elemattribindex + attnum]; } inline void tetgenmesh:: setelemattribute(tetrahedron* ptr, int attnum, REAL value){ ((REAL *) (ptr))[elemattribindex + attnum] = value; } // Check or set a tetrahedron's maximum volume bound. inline REAL tetgenmesh::volumebound(tetrahedron* ptr) { return ((REAL *) (ptr))[volumeboundindex]; } inline void tetgenmesh::setvolumebound(tetrahedron* ptr, REAL value) { ((REAL *) (ptr))[volumeboundindex] = value; } // Check or set a tetrahedron's marker. inline int tetgenmesh::getelemmarker(tetrahedron* ptr) { return ((int *) (ptr))[elemmarkerindex]; } inline void tetgenmesh::setelemmarker(tetrahedron* ptr, int value) { ((int *) (ptr))[elemmarkerindex] = value; } // infect(), infected(), uninfect() -- primitives to flag or unflag a // tetrahedron. The last bit of the element marker is flagged (1) // or unflagged (0). inline void tetgenmesh::infect(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= (int) 1; } inline void tetgenmesh::uninfect(triface& t) { ((int *) (t.tet))[elemmarkerindex] &= ~(int) 1; } // Test a tetrahedron for viral infection. inline bool tetgenmesh::infected(triface& t) { return (((int *) (t.tet))[elemmarkerindex] & (int) 1) != 0; } // marktest(), marktested(), unmarktest() -- primitives to flag or unflag a // tetrahedron. The last second bit of the element marker is marked (1) // or unmarked (0). // One needs them in forming Bowyer-Watson cavity, to mark a tetrahedron if // it has been checked (for Delaunay case) so later check can be avoided. inline void tetgenmesh::marktest(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= (int) 2; } inline void tetgenmesh::unmarktest(triface& t) { ((int *) (t.tet))[elemmarkerindex] &= ~(int) 2; } inline bool tetgenmesh::marktested(triface& t) { return (((int *) (t.tet))[elemmarkerindex] & (int) 2) != 0; } // markface(), unmarkface(), facemarked() -- primitives to flag or unflag a // face of a tetrahedron. From the last 3rd to 6th bits are used for // face markers, e.g., the last third bit corresponds to loc = 0. // One use of the face marker is in flip algorithm. Each queued face (check // for locally Delaunay) is marked. inline void tetgenmesh::markface(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= (int) (4<<(t).loc); } inline void tetgenmesh::unmarkface(triface& t) { ((int *) (t.tet))[elemmarkerindex] &= ~(int) (4<<(t).loc); } inline bool tetgenmesh::facemarked(triface& t) { return (((int *) (t.tet))[elemmarkerindex] & (int) (4<<(t).loc)) != 0; } // markedge(), unmarkedge(), edgemarked() -- primitives to flag or unflag an // edge of a tetrahedron. From the last 7th to 12th bits are used for // edge markers, e.g., the last 7th bit corresponds to the 0th edge, etc. // Remark: The last 7th bit is marked by 2^6 = 64. inline void tetgenmesh::markedge(triface& t) { ((int *) (t.tet))[elemmarkerindex] |= (int) (64<> (int) 2; // return ((int *) (s.sh))[shmarkindex]; } inline void tetgenmesh::setshellmark(face& s, int value) { ((int *) ((s).sh))[shmarkindex] = (value << (int) 2) + ((((int *) ((s).sh))[shmarkindex]) & (int) 3); // ((int *) (s.sh))[shmarkindex] = value; } // These two primitives set or read the type of the subface or subsegment. inline enum tetgenmesh::shestype tetgenmesh::shelltype(face& s) { return (enum shestype) ((int *) (s.sh))[shmarkindex + 1]; } inline void tetgenmesh::setshelltype(face& s, enum shestype value) { ((int *) (s.sh))[shmarkindex + 1] = (int) value; } // These two primitives set or read the pbc group of the subface. inline int tetgenmesh::shellpbcgroup(face& s) { return ((int *) (s.sh))[shmarkindex + 2]; } inline void tetgenmesh::setshellpbcgroup(face& s, int value) { ((int *) (s.sh))[shmarkindex + 2] = value; } // sinfect(), sinfected(), suninfect() -- primitives to flag or unflag a // subface. The last bit of ((int *) ((s).sh))[shmarkindex] is flaged. inline void tetgenmesh::sinfect(face& s) { ((int *) ((s).sh))[shmarkindex] = (((int *) ((s).sh))[shmarkindex] | (int) 1); // s.sh[6] = (shellface) ((unsigned long) s.sh[6] | (unsigned long) 4l); } inline void tetgenmesh::suninfect(face& s) { ((int *) ((s).sh))[shmarkindex] = (((int *) ((s).sh))[shmarkindex] & ~(int) 1); // s.sh[6] = (shellface)((unsigned long) s.sh[6] & ~(unsigned long) 4l); } // Test a subface for viral infection. inline bool tetgenmesh::sinfected(face& s) { return (((int *) ((s).sh))[shmarkindex] & (int) 1) != 0; } // smarktest(), smarktested(), sunmarktest() -- primitives to flag or unflag // a subface. The last 2nd bit of ((int *) ((s).sh))[shmarkindex] is flaged. #define smarktest(s) \ ((int *) ((s).sh))[shmarkindex] = (((int *)((s).sh))[shmarkindex] | (int) 2) #define sunmarktest(s) \ ((int *) ((s).sh))[shmarkindex] = (((int *)((s).sh))[shmarkindex] & ~(int) 2) #define smarktested(s) ((((int *) ((s).sh))[shmarkindex] & (int) 2) != 0) // // End of primitives for subfaces/subsegments // // // Begin of primitives for interacting between tetrahedra and subfaces // // tspivot() finds a subface abutting on this tetrahdera. inline void tetgenmesh::tspivot(triface& t, face& s) { if ((t).tet[9] != NULL) { sdecode(((shellface *) (t).tet[9])[(t).loc], s); } else { (s).sh = dummysh; } //shellface sptr = (shellface) t.tet[8 + t.loc]; //sdecode(sptr, s); } // stpivot() finds a tetrahedron abutting a subface. inline void tetgenmesh::stpivot(face& s, triface& t) { tetrahedron ptr = (tetrahedron) s.sh[6 + EdgeRing(s.shver)]; decode(ptr, t); } // tsbond() bond a tetrahedron to a subface. inline void tetgenmesh::tsbond(triface& t, face& s) { if ((t).tet[9] == NULL) { // Allocate space for this tet. (t).tet[9] = (tetrahedron) tet2subpool->alloc(); // NULL all fields in this space. for (int i = 0; i < 4; i++) { ((shellface *) (t).tet[9])[i] = (shellface) dummysh; } } // Bond t <==> s. ((shellface *) (t).tet[9])[(t).loc] = sencode(s); //t.tet[8 + t.loc] = (tetrahedron) sencode(s); s.sh[6 + EdgeRing(s.shver)] = (shellface) encode(t); } // tsdissolve() dissolve a bond (from the tetrahedron side). inline void tetgenmesh::tsdissolve(triface& t) { if ((t).tet[9] != NULL) { ((shellface *) (t).tet[9])[(t).loc] = (shellface) dummysh; } // t.tet[8 + t.loc] = (tetrahedron) dummysh; } // stdissolve() dissolve a bond (from the subface side). inline void tetgenmesh::stdissolve(face& s) { s.sh[6 + EdgeRing(s.shver)] = (shellface) dummytet; } // // End of primitives for interacting between tetrahedra and subfaces // // // Begin of primitives for interacting between subfaces and subsegs // // sspivot() finds a subsegment abutting a subface. inline void tetgenmesh::sspivot(face& s, face& edge) { shellface sptr = (shellface) s.sh[8 + Orient(s.shver)]; sdecode(sptr, edge); } // ssbond() bond a subface to a subsegment. inline void tetgenmesh::ssbond(face& s, face& edge) { s.sh[8 + Orient(s.shver)] = sencode(edge); edge.sh[0] = sencode(s); } // ssdisolve() dissolve a bond (from the subface side) inline void tetgenmesh::ssdissolve(face& s) { s.sh[8 + Orient(s.shver)] = (shellface) dummysh; } // // End of primitives for interacting between subfaces and subsegs // // // Begin of primitives for interacting between tet and subsegs. // inline void tetgenmesh::tsspivot1(triface& t, face& s) { if ((t).tet[8] != NULL) { sdecode(((shellface *) (t).tet[8])[locver2edge[(t).loc][(t).ver]], s); } else { (s).sh = dummysh; } // shellface sptr = (shellface) t.tet[8 + locver2edge[t.loc][t.ver]]; // sdecode(sptr, seg); } // Only bond/dissolve at tet's side, but not vice versa. inline void tetgenmesh::tssbond1(triface& t, face& s) { if ((t).tet[8] == NULL) { // Allocate space for this tet. (t).tet[8] = (tetrahedron) tet2segpool->alloc(); // NULL all fields in this space. for (int i = 0; i < 6; i++) { ((shellface *) (t).tet[8])[i] = (shellface) dummysh; } } // Bond the segment. ((shellface *) (t).tet[8])[locver2edge[(t).loc][(t).ver]] = sencode((s)); // t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) sencode(seg); } inline void tetgenmesh::tssdissolve1(triface& t) { if ((t).tet[8] != NULL) { ((shellface *) (t).tet[8])[locver2edge[(t).loc][(t).ver]] = (shellface) dummysh; } // t.tet[8 + locver2edge[t.loc][t.ver]] = (tetrahedron) dummysh; } // // End of primitives for interacting between tet and subsegs. // // // Begin of primitives for points // inline int tetgenmesh::pointmark(point pt) { return ((int *) (pt))[pointmarkindex]; } inline void tetgenmesh::setpointmark(point pt, int value) { ((int *) (pt))[pointmarkindex] = value; } // These two primitives set and read the type of the point. // The last significant bit of this integer is used by pinfect/puninfect. inline enum tetgenmesh::verttype tetgenmesh::pointtype(point pt) { return (enum verttype) (((int *) (pt))[pointmarkindex + 1] >> (int) 1); } inline void tetgenmesh::setpointtype(point pt, enum verttype value) { ((int *) (pt))[pointmarkindex + 1] = ((int) value << 1) + (((int *) (pt))[pointmarkindex + 1] & (int) 1); } // pinfect(), puninfect(), pinfected() -- primitives to flag or unflag // a point. The last bit of the integer '[pointindex+1]' is flaged. inline void tetgenmesh::pinfect(point pt) { ((int *) (pt))[pointmarkindex + 1] |= (int) 1; } inline void tetgenmesh::puninfect(point pt) { ((int *) (pt))[pointmarkindex + 1] &= ~(int) 1; } inline bool tetgenmesh::pinfected(point pt) { return (((int *) (pt))[pointmarkindex + 1] & (int) 1) != 0; } // These following primitives set and read a pointer to a tetrahedron // a subface/subsegment, a point, or a tet of background mesh. inline tetgenmesh::tetrahedron tetgenmesh::point2tet(point pt) { return ((tetrahedron *) (pt))[point2simindex]; } inline void tetgenmesh::setpoint2tet(point pt, tetrahedron value) { ((tetrahedron *) (pt))[point2simindex] = value; } inline tetgenmesh::shellface tetgenmesh::point2sh(point pt) { return (shellface) ((tetrahedron *) (pt))[point2simindex + 1]; } inline void tetgenmesh::setpoint2sh(point pt, shellface value) { ((tetrahedron *) (pt))[point2simindex + 1] = (tetrahedron) value; } inline tetgenmesh::shellface tetgenmesh::point2seg(point pt) { return (shellface) ((tetrahedron *) (pt))[point2simindex + 2]; } inline void tetgenmesh::setpoint2seg(point pt, shellface value) { ((tetrahedron *) (pt))[point2simindex + 2] = (tetrahedron) value; } inline tetgenmesh::point tetgenmesh::point2ppt(point pt) { return (point) ((tetrahedron *) (pt))[point2simindex + 3]; } inline void tetgenmesh::setpoint2ppt(point pt, point value) { ((tetrahedron *) (pt))[point2simindex + 3] = (tetrahedron) value; } inline tetgenmesh::tetrahedron tetgenmesh::point2bgmtet(point pt) { return ((tetrahedron *) (pt))[point2simindex + 4]; } inline void tetgenmesh::setpoint2bgmtet(point pt, tetrahedron value) { ((tetrahedron *) (pt))[point2simindex + 4] = value; } // These primitives set and read a pointer to its pbc point. inline tetgenmesh::point tetgenmesh::point2pbcpt(point pt) { return (point) ((tetrahedron *) (pt))[point2pbcptindex]; } inline void tetgenmesh::setpoint2pbcpt(point pt, point value) { ((tetrahedron *) (pt))[point2pbcptindex] = (tetrahedron) value; } // // End of primitives for points // // // Begin of advanced primitives // // adjustedgering() adjusts the edge version so that it belongs to the // indicated edge ring. The 'direction' only can be 0(CCW) or 1(CW). // If the edge is not in the wanted edge ring, reverse it. inline void tetgenmesh::adjustedgering(triface& t, int direction) { if (EdgeRing(t.ver) != direction) { esymself(t); } } inline void tetgenmesh::adjustedgering(face& s, int direction) { if (EdgeRing(s.shver) != direction) { sesymself(s); } } // isdead() returns TRUE if the tetrahedron or subface has been dealloced. inline bool tetgenmesh::isdead(triface* t) { if (t->tet == (tetrahedron *) NULL) return true; else return t->tet[4] == (tetrahedron) NULL; } inline bool tetgenmesh::isdead(face* s) { if (s->sh == (shellface *) NULL) return true; else return s->sh[3] == (shellface) NULL; } // isfacehaspoint() returns TRUE if the 'testpoint' is one of the vertices // of the tetface 't' subface 's'. inline bool tetgenmesh::isfacehaspoint(triface* t, point testpoint) { return ((org(*t) == testpoint) || (dest(*t) == testpoint) || (apex(*t) == testpoint)); } inline bool tetgenmesh::isfacehaspoint(face* s, point testpoint) { return (s->sh[3] == (shellface) testpoint) || (s->sh[4] == (shellface) testpoint) || (s->sh[5] == (shellface) testpoint); } // isfacehasedge() returns TRUE if the edge (given by its two endpoints) is // one of the three edges of the subface 's'. inline bool tetgenmesh::isfacehasedge(face* s, point tend1, point tend2) { return (isfacehaspoint(s, tend1) && isfacehaspoint(s, tend2)); } // issymexist() returns TRUE if the adjoining tetrahedron is not 'duumytet'. inline bool tetgenmesh::issymexist(triface* t) { tetrahedron *ptr = (tetrahedron *) ((unsigned long)(t->tet[t->loc]) & ~(unsigned long)7l); return ptr != dummytet; } // dot() returns the dot product: v1 dot v2. inline REAL tetgenmesh::dot(REAL* v1, REAL* v2) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } // cross() computes the cross product: n = v1 cross v2. inline void tetgenmesh::cross(REAL* v1, REAL* v2, REAL* n) { n[0] = v1[1] * v2[2] - v2[1] * v1[2]; n[1] = -(v1[0] * v2[2] - v2[0] * v1[2]); n[2] = v1[0] * v2[1] - v2[0] * v1[1]; } // distance() computs the Euclidean distance between two points. inline REAL tetgenmesh::distance(REAL* p1, REAL* p2) { return sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]) + (p2[2] - p1[2]) * (p2[2] - p1[2])); } // Linear algebra operators. #define NORM2(x, y, z) ((x) * (x) + (y) * (y) + (z) * (z)) #define DIST(p1, p2) \ sqrt(NORM2((p2)[0] - (p1)[0], (p2)[1] - (p1)[1], (p2)[2] - (p1)[2])) #define DOT(v1, v2) \ ((v1)[0] * (v2)[0] + (v1)[1] * (v2)[1] + (v1)[2] * (v2)[2]) #define CROSS(v1, v2, n) \ (n)[0] = (v1)[1] * (v2)[2] - (v2)[1] * (v1)[2];\ (n)[1] = -((v1)[0] * (v2)[2] - (v2)[0] * (v1)[2]);\ (n)[2] = (v1)[0] * (v2)[1] - (v2)[0] * (v1)[1] #define SETVECTOR3(V, a0, a1, a2) (V)[0] = (a0); (V)[1] = (a1); (V)[2] = (a2) #define SWAP2(a0, a1, tmp) (tmp) = (a0); (a0) = (a1); (a1) = (tmp) /////////////////////////////////////////////////////////////////////////////// // // // Two inline functions used in read/write VTK files. // // // /////////////////////////////////////////////////////////////////////////////// inline void swapBytes(unsigned char* var, int size) { int i = 0; int j = size - 1; char c; while (i < j) { c = var[i]; var[i] = var[j]; var[j] = c; i++, j--; } } inline bool testIsBigEndian() { short word = 0x4321; if((*(char *)& word) != 0x21) return true; else return false; } #endif // #ifndef tetgenH vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/example.poly0000664000175000017500000001051311757446472021002 0ustar lucaluca# # example.poly - Sample file of TetGen. # # A .poly file describes a piecewise linear complex (PLC) # This file represents a compensated magic tee junction. # # The source file is from: Vali Catina # # Part 1 - node list 54 3 0 0 1 -13.716000000000001 -5.0800000000000001 0 2 -13.716000000000001 5.0800000000000001 0 3 -11.43 5.0800000000000001 0 4 11.43 -5.0800000000000001 0 5 11.43 7.3659999999999997 0 6 -11.43 7.3659999999999997 0 7 0.95105651629515364 -0.37999999999999989 0 8 -0.95105651629515364 -0.37999999999999989 0 9 -0.95105651629515364 4.6200000000000001 0 10 0.95105651629515364 4.6200000000000001 0 11 -0.95105651629515353 4.6200000000000001 -0.30901699437494756 12 -0.58778525229247303 4.6200000000000001 -0.80901699437494756 13 1.2246063538223773e-16 4.6200000000000001 -1 14 0.58778525229247325 4.6200000000000001 -0.80901699437494734 15 0.95105651629515364 4.6200000000000001 -0.30901699437494734 16 -0.95105651629515353 -0.37999999999999989 -0.30901699437494756 17 -0.58778525229247303 -0.37999999999999989 -0.80901699437494756 18 1.2246063538223773e-16 -0.37999999999999989 -1 19 0.58778525229247325 -0.37999999999999989 -0.80901699437494734 20 0.95105651629515364 -0.37999999999999989 -0.30901699437494734 21 -1.5874999999999999 -0.37999999999999989 -2.9160938800395356e-16 22 -1.5098022196185561 -0.37999999999999989 -0.49056447857022928 23 -1.2843144785702287 -0.37999999999999989 -0.93310908801430126 24 -0.93310908801430081 -0.37999999999999989 -1.2843144785702292 25 -0.49056447857022878 -0.37999999999999989 -1.5098022196185563 26 1.9440625866930238e-16 -0.37999999999999989 -1.5874999999999999 27 0.49056447857022917 -0.37999999999999989 -1.5098022196185561 28 0.93310908801430115 -0.37999999999999989 -1.284314478570229 29 1.284314478570229 -0.37999999999999989 -0.93310908801430092 30 1.5098022196185563 -0.37999999999999989 -0.49056447857022889 31 1.5874999999999999 -0.37999999999999989 9.7203129334651192e-17 32 -1.5874999999999999 -5.0800000000000001 -2.9160938800395356e-16 33 -1.5098022196185561 -5.0800000000000001 -0.49056447857022928 34 -1.2843144785702287 -5.0800000000000001 -0.93310908801430126 35 -0.93310908801430081 -5.0800000000000001 -1.2843144785702292 36 -0.49056447857022878 -5.0800000000000001 -1.5098022196185563 37 1.9440625866930238e-16 -5.0800000000000001 -1.5874999999999999 38 0.49056447857022917 -5.0800000000000001 -1.5098022196185561 39 0.93310908801430115 -5.0800000000000001 -1.284314478570229 40 1.284314478570229 -5.0800000000000001 -0.93310908801430092 41 1.5098022196185563 -5.0800000000000001 -0.49056447857022889 42 1.5874999999999999 -5.0800000000000001 9.7203129334651192e-17 43 -11.43 7.3659999999999997 -5.0800000000000001 44 11.43 7.3659999999999997 -5.0800000000000001 45 -11.43 5.0800000000000001 -5.0800000000000001 46 11.43 5.0800000000000001 -5.0800000000000001 47 -13.716000000000001 5.0800000000000001 -11.43 48 -13.716000000000001 -5.0800000000000001 -11.43 49 -11.43 -5.0800000000000001 -11.43 50 -11.43 5.0800000000000001 -11.43 51 -11.43 -5.0800000000000001 -13.715999999999999 52 11.43 -5.0800000000000001 -13.715999999999999 53 11.43 5.0800000000000001 -13.715999999999999 54 -11.43 5.0800000000000001 -13.715999999999999 # Part 2 - facet list 29 1 1 0 1 14 1 2 3 6 5 4 42 31 7 10 9 8 21 32 1 0 1 7 9 10 15 14 13 12 11 1 0 1 4 8 9 11 16 1 0 1 4 11 12 17 16 1 0 1 4 12 13 18 17 1 0 1 4 13 14 19 18 1 0 1 4 14 15 20 19 1 0 1 4 10 7 20 15 1 0 1 18 7 31 30 29 28 27 26 25 24 23 22 21 8 16 17 18 19 20 1 0 1 4 21 22 33 32 1 0 1 4 22 23 34 33 1 0 1 4 23 24 35 34 1 0 1 4 24 25 36 35 1 0 1 4 25 26 37 36 1 0 1 4 26 27 38 37 1 0 1 4 27 28 39 38 1 0 1 4 28 29 40 39 1 0 1 4 29 30 41 40 1 0 1 4 30 31 42 41 1 0 1 4 43 45 46 44 1 0 1 4 5 6 43 44 1 0 1 6 4 5 44 46 53 52 1 0 1 4 6 3 45 43 1 0 1 4 47 48 49 50 1 0 1 8 3 2 47 50 54 53 46 45 1 0 1 17 42 4 52 51 49 48 1 32 33 34 35 36 37 38 39 40 41 1 0 1 4 2 1 48 47 1 0 1 4 50 49 51 54 1 0 1 4 54 51 52 53 # Part 3 - hole list 0 # Part 4 - region list 0 vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/CMakeLists.txt0000664000175000017500000000053211757446472021202 0ustar lucalucaPROJECT (TETGEN) SET (TETGEN_SRCS tetgen.cxx predicates.cxx ) ADD_DEFINITIONS (-DTETLIBRARY) INCLUDE_DIRECTORIES(${TETGEN_SOURCE_DIR}) ADD_LIBRARY (tet STATIC ${TETGEN_SRCS}) SET_TARGET_PROPERTIES(tet PROPERTIES COMPILE_FLAGS "-O0") IF(NOT WIN32) SET_TARGET_PROPERTIES(tet PROPERTIES COMPILE_FLAGS "-O0 -fPIC") ENDIF(NOT WIN32) vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/README0000664000175000017500000000067211757446472017327 0ustar lucalucaThis is TetGen version 1.4.3 (released on September 6, 2009) Please see the documentation of TetGen for compiling and using TetGen. It is available at the following link: http://tetgen.berlios.de/index.html TetGen may be freely copied, modified, and redistributed under the copyright notices stated in the file LICENSE. Please send bugs/comments to Hang Si Thank you and enjoy! Hang Si September 6, 2009 vmtk-1.0.1/vtkVmtk/Utilities/tetgen1.4.3/predicates.cxx0000664000175000017500000052021411757446472021315 0ustar lucaluca/*****************************************************************************/ /* */ /* Routines for Arbitrary Precision Floating-point Arithmetic */ /* and Fast Robust Geometric Predicates */ /* (predicates.c) */ /* */ /* May 18, 1996 */ /* */ /* Placed in the public domain by */ /* Jonathan Richard Shewchuk */ /* School of Computer Science */ /* Carnegie Mellon University */ /* 5000 Forbes Avenue */ /* Pittsburgh, Pennsylvania 15213-3891 */ /* jrs@cs.cmu.edu */ /* */ /* This file contains C implementation of algorithms for exact addition */ /* and multiplication of floating-point numbers, and predicates for */ /* robustly performing the orientation and incircle tests used in */ /* computational geometry. The algorithms and underlying theory are */ /* described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- */ /* Point Arithmetic and Fast Robust Geometric Predicates." Technical */ /* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ /* University, Pittsburgh, Pennsylvania, May 1996. (Submitted to */ /* Discrete & Computational Geometry.) */ /* */ /* This file, the paper listed above, and other information are available */ /* from the Web page http://www.cs.cmu.edu/~quake/robust.html . */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* */ /* Using this code: */ /* */ /* First, read the short or long version of the paper (from the Web page */ /* above). */ /* */ /* Be sure to call exactinit() once, before calling any of the arithmetic */ /* functions or geometric predicates. Also be sure to turn on the */ /* optimizer when compiling this file. */ /* */ /* */ /* Several geometric predicates are defined. Their parameters are all */ /* points. Each point is an array of two or three floating-point */ /* numbers. The geometric predicates, described in the papers, are */ /* */ /* orient2d(pa, pb, pc) */ /* orient2dfast(pa, pb, pc) */ /* orient3d(pa, pb, pc, pd) */ /* orient3dfast(pa, pb, pc, pd) */ /* incircle(pa, pb, pc, pd) */ /* incirclefast(pa, pb, pc, pd) */ /* insphere(pa, pb, pc, pd, pe) */ /* inspherefast(pa, pb, pc, pd, pe) */ /* */ /* Those with suffix "fast" are approximate, non-robust versions. Those */ /* without the suffix are adaptive precision, robust versions. There */ /* are also versions with the suffices "exact" and "slow", which are */ /* non-adaptive, exact arithmetic versions, which I use only for timings */ /* in my arithmetic papers. */ /* */ /* */ /* An expansion is represented by an array of floating-point numbers, */ /* sorted from smallest to largest magnitude (possibly with interspersed */ /* zeros). The length of each expansion is stored as a separate integer, */ /* and each arithmetic function returns an integer which is the length */ /* of the expansion it created. */ /* */ /* Several arithmetic functions are defined. Their parameters are */ /* */ /* e, f Input expansions */ /* elen, flen Lengths of input expansions (must be >= 1) */ /* h Output expansion */ /* b Input scalar */ /* */ /* The arithmetic functions are */ /* */ /* grow_expansion(elen, e, b, h) */ /* grow_expansion_zeroelim(elen, e, b, h) */ /* expansion_sum(elen, e, flen, f, h) */ /* expansion_sum_zeroelim1(elen, e, flen, f, h) */ /* expansion_sum_zeroelim2(elen, e, flen, f, h) */ /* fast_expansion_sum(elen, e, flen, f, h) */ /* fast_expansion_sum_zeroelim(elen, e, flen, f, h) */ /* linear_expansion_sum(elen, e, flen, f, h) */ /* linear_expansion_sum_zeroelim(elen, e, flen, f, h) */ /* scale_expansion(elen, e, b, h) */ /* scale_expansion_zeroelim(elen, e, b, h) */ /* compress(elen, e, h) */ /* */ /* All of these are described in the long version of the paper; some are */ /* described in the short version. All return an integer that is the */ /* length of h. Those with suffix _zeroelim perform zero elimination, */ /* and are recommended over their counterparts. The procedure */ /* fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on */ /* processors that do not use the round-to-even tiebreaking rule) is */ /* recommended over expansion_sum_zeroelim(). Each procedure has a */ /* little note next to it (in the code below) that tells you whether or */ /* not the output expansion may be the same array as one of the input */ /* expansions. */ /* */ /* */ /* If you look around below, you'll also find macros for a bunch of */ /* simple unrolled arithmetic operations, and procedures for printing */ /* expansions (commented out because they don't work with all C */ /* compilers) and for generating random floating-point numbers whose */ /* significand bits are all random. Most of the macros have undocumented */ /* requirements that certain of their parameters should not be the same */ /* variable; for safety, better to make sure all the parameters are */ /* distinct variables. Feel free to send email to jrs@cs.cmu.edu if you */ /* have questions. */ /* */ /*****************************************************************************/ #include #include #include #ifdef CPU86 #include #endif /* CPU86 */ #ifdef LINUX #include #endif /* LINUX */ #include "tetgen.h" // Defines the symbol REAL (float or double). /* 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 great solution, though, as it slows the arithmetic 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 */ /* #define REAL double */ /* float or double */ #define REALPRINT doubleprint #define REALRAND doublerand #define NARROWRAND narrowdoublerand #define UNIFORMRAND uniformdoublerand /* 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, but that's difficult to do in C. */ #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 = (REAL) (a + b); \ Fast_Two_Sum_Tail(a, b, x, y) #define Fast_Two_Diff_Tail(a, b, x, y) \ bvirt = a - x; \ y = bvirt - b #define Fast_Two_Diff(a, b, x, y) \ x = (REAL) (a - b); \ Fast_Two_Diff_Tail(a, b, x, y) #define Two_Sum_Tail(a, b, x, y) \ bvirt = (REAL) (x - a); \ avirt = x - bvirt; \ bround = b - bvirt; \ around = a - avirt; \ y = around + bround #define Two_Sum(a, b, x, y) \ x = (REAL) (a + b); \ Two_Sum_Tail(a, b, x, y) #define Two_Diff_Tail(a, b, x, y) \ bvirt = (REAL) (a - x); \ avirt = x + bvirt; \ bround = bvirt - b; \ around = a - avirt; \ y = around + bround #define Two_Diff(a, b, x, y) \ x = (REAL) (a - b); \ Two_Diff_Tail(a, b, x, y) #define Split(a, ahi, alo) \ c = (REAL) (splitter * a); \ abig = (REAL) (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 = (REAL) (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 = (REAL) (a * b); \ Split(a, ahi, alo); \ err1 = x - (ahi * bhi); \ err2 = err1 - (alo * bhi); \ err3 = err2 - (ahi * blo); \ y = (alo * blo) - err3 /* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ /* already been split. Avoids redundant splitting. */ #define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ x = (REAL) (a * b); \ 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 = (REAL) (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) /* Macros for multiplying expansions of various fixed lengths. */ #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) #define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, 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, _i, x2); \ Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, x3); \ Fast_Two_Sum(_j, _k, _i, x4); \ Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, x5); \ Fast_Two_Sum(_j, _k, x7, x6) #define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ Split(a0, a0hi, a0lo); \ Split(b0, bhi, blo); \ Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ Split(a1, a1hi, a1lo); \ Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _k, _1); \ Fast_Two_Sum(_j, _k, _l, _2); \ Split(b1, bhi, blo); \ Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ Two_Sum(_1, _0, _k, x1); \ Two_Sum(_2, _k, _j, _1); \ Two_Sum(_l, _j, _m, _2); \ Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ Two_Sum(_i, _0, _n, _0); \ Two_Sum(_1, _0, _i, x2); \ Two_Sum(_2, _i, _k, _1); \ Two_Sum(_m, _k, _l, _2); \ Two_Sum(_j, _n, _k, _0); \ Two_Sum(_1, _0, _j, x3); \ Two_Sum(_2, _j, _i, _1); \ Two_Sum(_l, _i, _m, _2); \ Two_Sum(_1, _k, _i, x4); \ Two_Sum(_2, _i, _k, x5); \ Two_Sum(_m, _k, x7, x6) /* An expansion of length two can be squared more quickly than finding the */ /* product of two different expansions of length two, and the result is */ /* guaranteed to have no more than six (rather than eight) components. */ #define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ Square(a0, _j, x0); \ _0 = a0 + a0; \ Two_Product(a1, _0, _k, _1); \ Two_One_Sum(_k, _1, _j, _l, _2, x1); \ Square(a1, _j, _1); \ Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) /* splitter = 2^ceiling(p / 2) + 1. Used to split floats in half. */ static REAL splitter; static REAL epsilon; /* = 2^(-p). Used to estimate roundoff errors. */ /* A set of coefficients used to calculate maximum roundoff errors. */ static REAL resulterrbound; static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; static REAL o3derrboundA, o3derrboundB, o3derrboundC; static REAL iccerrboundA, iccerrboundB, iccerrboundC; static REAL isperrboundA, isperrboundB, isperrboundC; /*****************************************************************************/ /* */ /* doubleprint() Print the bit representation of a double. */ /* */ /* Useful for debugging exact arithmetic routines. */ /* */ /*****************************************************************************/ /* void doubleprint(number) double number; { unsigned long long no; unsigned long long sign, expo; int exponent; int i, bottomi; no = *(unsigned long long *) &number; sign = no & 0x8000000000000000ll; expo = (no >> 52) & 0x7ffll; exponent = (int) expo; exponent = exponent - 1023; if (sign) { printf("-"); } else { printf(" "); } if (exponent == -1023) { printf( "0.0000000000000000000000000000000000000000000000000000_ ( )"); } else { printf("1."); bottomi = -1; for (i = 0; i < 52; i++) { if (no & 0x0008000000000000ll) { printf("1"); bottomi = i; } else { printf("0"); } no <<= 1; } printf("_%d (%d)", exponent, exponent - 1 - bottomi); } } */ /*****************************************************************************/ /* */ /* floatprint() Print the bit representation of a float. */ /* */ /* Useful for debugging exact arithmetic routines. */ /* */ /*****************************************************************************/ /* void floatprint(number) float number; { unsigned no; unsigned sign, expo; int exponent; int i, bottomi; no = *(unsigned *) &number; sign = no & 0x80000000; expo = (no >> 23) & 0xff; exponent = (int) expo; exponent = exponent - 127; if (sign) { printf("-"); } else { printf(" "); } if (exponent == -127) { printf("0.00000000000000000000000_ ( )"); } else { printf("1."); bottomi = -1; for (i = 0; i < 23; i++) { if (no & 0x00400000) { printf("1"); bottomi = i; } else { printf("0"); } no <<= 1; } printf("_%3d (%3d)", exponent, exponent - 1 - bottomi); } } */ /*****************************************************************************/ /* */ /* expansion_print() Print the bit representation of an expansion. */ /* */ /* Useful for debugging exact arithmetic routines. */ /* */ /*****************************************************************************/ /* void expansion_print(elen, e) int elen; REAL *e; { int i; for (i = elen - 1; i >= 0; i--) { REALPRINT(e[i]); if (i > 0) { printf(" +\n"); } else { printf("\n"); } } } */ /*****************************************************************************/ /* */ /* doublerand() Generate a double with random 53-bit significand and a */ /* random exponent in [0, 511]. */ /* */ /*****************************************************************************/ /* double doublerand() { double result; double expo; long a, b, c; long i; a = random(); b = random(); c = random(); result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* narrowdoublerand() Generate a double with random 53-bit significand */ /* and a random exponent in [0, 7]. */ /* */ /*****************************************************************************/ /* double narrowdoublerand() { double result; double expo; long a, b, c; long i; a = random(); b = random(); c = random(); result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* uniformdoublerand() Generate a double with random 53-bit significand. */ /* */ /*****************************************************************************/ /* double uniformdoublerand() { double result; long a, b; a = random(); b = random(); result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); return result; } */ /*****************************************************************************/ /* */ /* floatrand() Generate a float with random 24-bit significand and a */ /* random exponent in [0, 63]. */ /* */ /*****************************************************************************/ /* float floatrand() { float result; float expo; long a, c; long i; a = random(); c = random(); result = (float) ((a - 1073741824) >> 6); for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* narrowfloatrand() Generate a float with random 24-bit significand and */ /* a random exponent in [0, 7]. */ /* */ /*****************************************************************************/ /* float narrowfloatrand() { float result; float expo; long a, c; long i; a = random(); c = random(); result = (float) ((a - 1073741824) >> 6); for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { if (c & i) { result *= expo; } } return result; } */ /*****************************************************************************/ /* */ /* uniformfloatrand() Generate a float with random 24-bit significand. */ /* */ /*****************************************************************************/ /* float uniformfloatrand() { float result; long a; a = random(); result = (float) ((a - 1073741824) >> 6); return result; } */ /*****************************************************************************/ /* */ /* exactinit() 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 fully understand it. */ /* */ /*****************************************************************************/ REAL exactinit() { REAL half; REAL 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 this library will work on such machines anyway. */ 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 incircle tests. */ resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; ccwerrboundC = (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; iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon; iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon; iccerrboundC = (44.0 + 576.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; return epsilon; /* Added by H. Si 30 Juli, 2004. */ } /*****************************************************************************/ /* */ /* grow_expansion() Add a scalar to an expansion. */ /* */ /* Sets h = e + b. See the long version of my paper for details. */ /* */ /* 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 grow_expansion(int elen, REAL *e, REAL b, REAL *h) /* e and h can be the same. */ { REAL Q; INEXACT REAL Qnew; int eindex; REAL enow; INEXACT REAL bvirt; REAL avirt, bround, around; Q = b; for (eindex = 0; eindex < elen; eindex++) { enow = e[eindex]; Two_Sum(Q, enow, Qnew, h[eindex]); Q = Qnew; } h[eindex] = Q; return eindex + 1; } /*****************************************************************************/ /* */ /* grow_expansion_zeroelim() Add a scalar to an expansion, eliminating */ /* zero components from the output expansion. */ /* */ /* Sets h = e + b. See the long version of my paper for details. */ /* */ /* 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 grow_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) /* e and h can be the same. */ { REAL Q, hh; INEXACT REAL Qnew; int eindex, hindex; REAL enow; INEXACT REAL bvirt; REAL avirt, bround, around; hindex = 0; Q = b; for (eindex = 0; eindex < elen; eindex++) { enow = e[eindex]; Two_Sum(Q, enow, Qnew, hh); Q = Qnew; if (hh != 0.0) { h[hindex++] = hh; } } if ((Q != 0.0) || (hindex == 0)) { h[hindex++] = Q; } return hindex; } /*****************************************************************************/ /* */ /* expansion_sum() Sum two expansions. */ /* */ /* Sets h = e + f. See the long version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. If round-to-even is used (as */ /* with IEEE 754), maintains the nonadjacent property as well. (That is, */ /* if e has one of these properties, so will h.) Does NOT maintain the */ /* strongly nonoverlapping property. */ /* */ /*****************************************************************************/ int expansion_sum(int elen, REAL *e, int flen, REAL *f, REAL *h) /* e and h can be the same, but f and h cannot. */ { REAL Q; INEXACT REAL Qnew; int findex, hindex, hlast; REAL hnow; INEXACT REAL bvirt; REAL avirt, bround, around; Q = f[0]; for (hindex = 0; hindex < elen; hindex++) { hnow = e[hindex]; Two_Sum(Q, hnow, Qnew, h[hindex]); Q = Qnew; } h[hindex] = Q; hlast = hindex; for (findex = 1; findex < flen; findex++) { Q = f[findex]; for (hindex = findex; hindex <= hlast; hindex++) { hnow = h[hindex]; Two_Sum(Q, hnow, Qnew, h[hindex]); Q = Qnew; } h[++hlast] = Q; } return hlast + 1; } /*****************************************************************************/ /* */ /* expansion_sum_zeroelim1() Sum two expansions, eliminating zero */ /* components from the output expansion. */ /* */ /* Sets h = e + f. See the long version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. If round-to-even is used (as */ /* with IEEE 754), maintains the nonadjacent property as well. (That is, */ /* if e has one of these properties, so will h.) Does NOT maintain the */ /* strongly nonoverlapping property. */ /* */ /*****************************************************************************/ int expansion_sum_zeroelim1(int elen, REAL *e, int flen, REAL *f, REAL *h) /* e and h can be the same, but f and h cannot. */ { REAL Q; INEXACT REAL Qnew; int index, findex, hindex, hlast; REAL hnow; INEXACT REAL bvirt; REAL avirt, bround, around; Q = f[0]; for (hindex = 0; hindex < elen; hindex++) { hnow = e[hindex]; Two_Sum(Q, hnow, Qnew, h[hindex]); Q = Qnew; } h[hindex] = Q; hlast = hindex; for (findex = 1; findex < flen; findex++) { Q = f[findex]; for (hindex = findex; hindex <= hlast; hindex++) { hnow = h[hindex]; Two_Sum(Q, hnow, Qnew, h[hindex]); Q = Qnew; } h[++hlast] = Q; } hindex = -1; for (index = 0; index <= hlast; index++) { hnow = h[index]; if (hnow != 0.0) { h[++hindex] = hnow; } } if (hindex == -1) { return 1; } else { return hindex + 1; } } /*****************************************************************************/ /* */ /* expansion_sum_zeroelim2() Sum two expansions, eliminating zero */ /* components from the output expansion. */ /* */ /* Sets h = e + f. See the long version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. If round-to-even is used (as */ /* with IEEE 754), maintains the nonadjacent property as well. (That is, */ /* if e has one of these properties, so will h.) Does NOT maintain the */ /* strongly nonoverlapping property. */ /* */ /*****************************************************************************/ int expansion_sum_zeroelim2(int elen, REAL *e, int flen, REAL *f, REAL *h) /* e and h can be the same, but f and h cannot. */ { REAL Q, hh; INEXACT REAL Qnew; int eindex, findex, hindex, hlast; REAL enow; INEXACT REAL bvirt; REAL avirt, bround, around; hindex = 0; Q = f[0]; for (eindex = 0; eindex < elen; eindex++) { enow = e[eindex]; Two_Sum(Q, enow, Qnew, hh); Q = Qnew; if (hh != 0.0) { h[hindex++] = hh; } } h[hindex] = Q; hlast = hindex; for (findex = 1; findex < flen; findex++) { hindex = 0; Q = f[findex]; for (eindex = 0; eindex <= hlast; eindex++) { enow = h[eindex]; Two_Sum(Q, enow, Qnew, hh); Q = Qnew; if (hh != 0) { h[hindex++] = hh; } } h[hindex] = Q; hlast = hindex; } return hlast + 1; } /*****************************************************************************/ /* */ /* fast_expansion_sum() Sum two expansions. */ /* */ /* Sets h = e + f. See the long version of my paper for details. */ /* */ /* 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(int elen, REAL *e, int flen, REAL *f, REAL *h) /* h cannot be e or f. */ { REAL Q; INEXACT REAL Qnew; INEXACT REAL bvirt; REAL avirt, bround, around; int eindex, findex, hindex; REAL 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, h[0]); enow = e[++eindex]; } else { Fast_Two_Sum(fnow, Q, Qnew, h[0]); fnow = f[++findex]; } Q = Qnew; hindex = 1; while ((eindex < elen) && (findex < flen)) { if ((fnow > enow) == (fnow > -enow)) { Two_Sum(Q, enow, Qnew, h[hindex]); enow = e[++eindex]; } else { Two_Sum(Q, fnow, Qnew, h[hindex]); fnow = f[++findex]; } Q = Qnew; hindex++; } } while (eindex < elen) { Two_Sum(Q, enow, Qnew, h[hindex]); enow = e[++eindex]; Q = Qnew; hindex++; } while (findex < flen) { Two_Sum(Q, fnow, Qnew, h[hindex]); fnow = f[++findex]; Q = Qnew; hindex++; } h[hindex] = Q; return hindex + 1; } /*****************************************************************************/ /* */ /* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ /* components from the output expansion. */ /* */ /* Sets h = e + f. See the long version of my paper for details. */ /* */ /* 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, REAL *e, int flen, REAL *f, REAL *h) /* h cannot be e or f. */ { REAL Q; INEXACT REAL Qnew; INEXACT REAL hh; INEXACT REAL bvirt; REAL avirt, bround, around; int eindex, findex, hindex; REAL 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; } /*****************************************************************************/ /* */ /* linear_expansion_sum() Sum two expansions. */ /* */ /* Sets h = e + f. See either version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. (That is, if e is */ /* nonoverlapping, h will be also.) */ /* */ /*****************************************************************************/ int linear_expansion_sum(int elen, REAL *e, int flen, REAL *f, REAL *h) /* h cannot be e or f. */ { REAL Q, q; INEXACT REAL Qnew; INEXACT REAL R; INEXACT REAL bvirt; REAL avirt, bround, around; int eindex, findex, hindex; REAL enow, fnow; REAL g0; enow = e[0]; fnow = f[0]; eindex = findex = 0; if ((fnow > enow) == (fnow > -enow)) { g0 = enow; enow = e[++eindex]; } else { g0 = fnow; fnow = f[++findex]; } if ((eindex < elen) && ((findex >= flen) || ((fnow > enow) == (fnow > -enow)))) { Fast_Two_Sum(enow, g0, Qnew, q); enow = e[++eindex]; } else { Fast_Two_Sum(fnow, g0, Qnew, q); fnow = f[++findex]; } Q = Qnew; for (hindex = 0; hindex < elen + flen - 2; hindex++) { if ((eindex < elen) && ((findex >= flen) || ((fnow > enow) == (fnow > -enow)))) { Fast_Two_Sum(enow, q, R, h[hindex]); enow = e[++eindex]; } else { Fast_Two_Sum(fnow, q, R, h[hindex]); fnow = f[++findex]; } Two_Sum(Q, R, Qnew, q); Q = Qnew; } h[hindex] = q; h[hindex + 1] = Q; return hindex + 2; } /*****************************************************************************/ /* */ /* linear_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ /* components from the output expansion. */ /* */ /* Sets h = e + f. See either version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. (That is, if e is */ /* nonoverlapping, h will be also.) */ /* */ /*****************************************************************************/ int linear_expansion_sum_zeroelim(int elen, REAL *e, int flen, REAL *f, REAL *h) /* h cannot be e or f. */ { REAL Q, q, hh; INEXACT REAL Qnew; INEXACT REAL R; INEXACT REAL bvirt; REAL avirt, bround, around; int eindex, findex, hindex; int count; REAL enow, fnow; REAL g0; enow = e[0]; fnow = f[0]; eindex = findex = 0; hindex = 0; if ((fnow > enow) == (fnow > -enow)) { g0 = enow; enow = e[++eindex]; } else { g0 = fnow; fnow = f[++findex]; } if ((eindex < elen) && ((findex >= flen) || ((fnow > enow) == (fnow > -enow)))) { Fast_Two_Sum(enow, g0, Qnew, q); enow = e[++eindex]; } else { Fast_Two_Sum(fnow, g0, Qnew, q); fnow = f[++findex]; } Q = Qnew; for (count = 2; count < elen + flen; count++) { if ((eindex < elen) && ((findex >= flen) || ((fnow > enow) == (fnow > -enow)))) { Fast_Two_Sum(enow, q, R, hh); enow = e[++eindex]; } else { Fast_Two_Sum(fnow, q, R, hh); fnow = f[++findex]; } Two_Sum(Q, R, Qnew, q); Q = Qnew; if (hh != 0) { h[hindex++] = hh; } } if (q != 0) { h[hindex++] = q; } if ((Q != 0.0) || (hindex == 0)) { h[hindex++] = Q; } return hindex; } /*****************************************************************************/ /* */ /* scale_expansion() Multiply an expansion by a scalar. */ /* */ /* Sets h = be. See either version of my paper for details. */ /* */ /* 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(int elen, REAL *e, REAL b, REAL *h) /* e and h cannot be the same. */ { INEXACT REAL Q; INEXACT REAL sum; INEXACT REAL product1; REAL product0; int eindex, hindex; REAL enow; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; Split(b, bhi, blo); Two_Product_Presplit(e[0], b, bhi, blo, Q, h[0]); hindex = 1; for (eindex = 1; eindex < elen; eindex++) { enow = e[eindex]; Two_Product_Presplit(enow, b, bhi, blo, product1, product0); Two_Sum(Q, product0, sum, h[hindex]); hindex++; Two_Sum(product1, sum, Q, h[hindex]); hindex++; } h[hindex] = Q; return elen + elen; } /*****************************************************************************/ /* */ /* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ /* eliminating zero components from the */ /* output expansion. */ /* */ /* Sets h = be. See either version of my paper for details. */ /* */ /* 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, REAL *e, REAL b, REAL *h) /* e and h cannot be the same. */ { INEXACT REAL Q, sum; REAL hh; INEXACT REAL product1; REAL product0; int eindex, hindex; REAL enow; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL 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; } /*****************************************************************************/ /* */ /* compress() Compress an expansion. */ /* */ /* See the long version of my paper for details. */ /* */ /* Maintains the nonoverlapping property. If round-to-even is used (as */ /* with IEEE 754), then any nonoverlapping expansion is converted to a */ /* nonadjacent expansion. */ /* */ /*****************************************************************************/ int compress(int elen, REAL *e, REAL *h) /* e and h may be the same. */ { REAL Q, q; INEXACT REAL Qnew; int eindex, hindex; INEXACT REAL bvirt; REAL enow, hnow; int top, bottom; bottom = elen - 1; Q = e[bottom]; for (eindex = elen - 2; eindex >= 0; eindex--) { enow = e[eindex]; Fast_Two_Sum(Q, enow, Qnew, q); if (q != 0) { h[bottom--] = Qnew; Q = q; } else { Q = Qnew; } } top = 0; for (hindex = bottom + 1; hindex < elen; hindex++) { hnow = h[hindex]; Fast_Two_Sum(hnow, Q, Qnew, q); if (q != 0) { h[top++] = q; } Q = Qnew; } h[top] = Q; return top + 1; } /*****************************************************************************/ /* */ /* estimate() Produce a one-word estimate of an expansion's value. */ /* */ /* See either version of my paper for details. */ /* */ /*****************************************************************************/ REAL estimate(int elen, REAL *e) { REAL Q; int eindex; Q = e[0]; for (eindex = 1; eindex < elen; eindex++) { Q += e[eindex]; } return Q; } /*****************************************************************************/ /* */ /* orient2dfast() Approximate 2D orientation test. Nonrobust. */ /* orient2dexact() Exact 2D orientation test. Robust. */ /* orient2dslow() Another exact 2D orientation test. Robust. */ /* orient2d() Adaptive exact 2D orientation test. Robust. */ /* */ /* Return a positive value if the points pa, pb, and pc occur */ /* in counterclockwise order; a negative value if they occur */ /* in clockwise order; and zero if they are collinear. The */ /* result is also a rough approximation of twice the signed */ /* area of the triangle defined by the three points. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In orient2d() only, */ /* 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, orient2d() is usually quite */ /* fast, but will run more slowly when the input points are collinear or */ /* nearly so. */ /* */ /*****************************************************************************/ REAL orient2dfast(REAL *pa, REAL *pb, REAL *pc) { REAL acx, bcx, acy, bcy; acx = pa[0] - pc[0]; bcx = pb[0] - pc[0]; acy = pa[1] - pc[1]; bcy = pb[1] - pc[1]; return acx * bcy - acy * bcx; } REAL orient2dexact(REAL *pa, REAL *pb, REAL *pc) { INEXACT REAL axby1, axcy1, bxcy1, bxay1, cxay1, cxby1; REAL axby0, axcy0, bxcy0, bxay0, cxay0, cxby0; REAL aterms[4], bterms[4], cterms[4]; INEXACT REAL aterms3, bterms3, cterms3; REAL v[8], w[12]; int vlength, wlength; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; Two_Product(pa[0], pb[1], axby1, axby0); Two_Product(pa[0], pc[1], axcy1, axcy0); Two_Two_Diff(axby1, axby0, axcy1, axcy0, aterms3, aterms[2], aterms[1], aterms[0]); aterms[3] = aterms3; Two_Product(pb[0], pc[1], bxcy1, bxcy0); Two_Product(pb[0], pa[1], bxay1, bxay0); Two_Two_Diff(bxcy1, bxcy0, bxay1, bxay0, bterms3, bterms[2], bterms[1], bterms[0]); bterms[3] = bterms3; Two_Product(pc[0], pa[1], cxay1, cxay0); Two_Product(pc[0], pb[1], cxby1, cxby0); Two_Two_Diff(cxay1, cxay0, cxby1, cxby0, cterms3, cterms[2], cterms[1], cterms[0]); cterms[3] = cterms3; vlength = fast_expansion_sum_zeroelim(4, aterms, 4, bterms, v); wlength = fast_expansion_sum_zeroelim(vlength, v, 4, cterms, w); return w[wlength - 1]; } REAL orient2dslow(REAL *pa, REAL *pb, REAL *pc) { INEXACT REAL acx, acy, bcx, bcy; REAL acxtail, acytail; REAL bcxtail, bcytail; REAL negate, negatetail; REAL axby[8], bxay[8]; INEXACT REAL axby7, bxay7; REAL deter[16]; int deterlen; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j, _k, _l, _m, _n; REAL _0, _1, _2; Two_Diff(pa[0], pc[0], acx, acxtail); Two_Diff(pa[1], pc[1], acy, acytail); Two_Diff(pb[0], pc[0], bcx, bcxtail); Two_Diff(pb[1], pc[1], bcy, bcytail); Two_Two_Product(acx, acxtail, bcy, bcytail, axby7, axby[6], axby[5], axby[4], axby[3], axby[2], axby[1], axby[0]); axby[7] = axby7; negate = -acy; negatetail = -acytail; Two_Two_Product(bcx, bcxtail, negate, negatetail, bxay7, bxay[6], bxay[5], bxay[4], bxay[3], bxay[2], bxay[1], bxay[0]); bxay[7] = bxay7; deterlen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, deter); return deter[deterlen - 1]; } REAL orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum) { INEXACT REAL acx, acy, bcx, bcy; REAL acxtail, acytail, bcxtail, bcytail; INEXACT REAL detleft, detright; REAL detlefttail, detrighttail; REAL det, errbound; REAL B[4], C1[8], C2[12], D[16]; INEXACT REAL B3; int C1length, C2length, Dlength; REAL u[4]; INEXACT REAL u3; INEXACT REAL s1, t1; REAL s0, t0; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; acx = (REAL) (pa[0] - pc[0]); bcx = (REAL) (pb[0] - pc[0]); acy = (REAL) (pa[1] - pc[1]); bcy = (REAL) (pb[1] - pc[1]); 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 = ccwerrboundB * detsum; if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Diff_Tail(pa[0], pc[0], acx, acxtail); Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); Two_Diff_Tail(pa[1], pc[1], acy, acytail); Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); if ((acxtail == 0.0) && (acytail == 0.0) && (bcxtail == 0.0) && (bcytail == 0.0)) { return det; } errbound = ccwerrboundC * 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]); } REAL orient2d(REAL *pa, REAL *pb, REAL *pc) { REAL detleft, detright, det; REAL detsum, errbound; detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); det = detleft - detright; 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 = ccwerrboundA * detsum; if ((det >= errbound) || (-det >= errbound)) { return det; } return orient2dadapt(pa, pb, pc, detsum); } /*****************************************************************************/ /* */ /* orient3dfast() Approximate 3D orientation test. Nonrobust. */ /* orient3dexact() Exact 3D orientation test. Robust. */ /* orient3dslow() Another exact 3D orientation test. Robust. */ /* orient3d() Adaptive exact 3D orientation test. Robust. */ /* */ /* 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. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In orient3d() only, */ /* 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, orient3d() is usually quite */ /* fast, but will run more slowly when the input points are coplanar or */ /* nearly so. */ /* */ /*****************************************************************************/ REAL orient3dfast(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, bdx, cdx; REAL ady, bdy, cdy; REAL adz, bdz, cdz; 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]; return adx * (bdy * cdz - bdz * cdy) + bdx * (cdy * adz - cdz * ady) + cdx * (ady * bdz - adz * bdy); } REAL orient3dexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1; INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1; REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0; REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0; REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; REAL temp8[8]; int templen; REAL abc[12], bcd[12], cda[12], dab[12]; int abclen, bcdlen, cdalen, dablen; REAL adet[24], bdet[24], cdet[24], ddet[24]; int alen, blen, clen, dlen; REAL abdet[48], cddet[48]; int ablen, cdlen; REAL deter[96]; int deterlen; int i; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _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], 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(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]); templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8); cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda); templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8); dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab); for (i = 0; i < 4; i++) { bd[i] = -bd[i]; ac[i] = -ac[i]; } templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8); abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc); templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8); bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd); alen = scale_expansion_zeroelim(bcdlen, bcd, pa[2], adet); blen = scale_expansion_zeroelim(cdalen, cda, -pb[2], bdet); clen = scale_expansion_zeroelim(dablen, dab, pc[2], cdet); dlen = scale_expansion_zeroelim(abclen, abc, -pd[2], ddet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); return deter[deterlen - 1]; } REAL orient3dslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { INEXACT REAL adx, ady, adz, bdx, bdy, bdz, cdx, cdy, cdz; REAL adxtail, adytail, adztail; REAL bdxtail, bdytail, bdztail; REAL cdxtail, cdytail, cdztail; REAL negate, negatetail; INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7; REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8]; REAL temp16[16], temp32[32], temp32t[32]; int temp16len, temp32len, temp32tlen; REAL adet[64], bdet[64], cdet[64]; int alen, blen, clen; REAL abdet[128]; int ablen; REAL deter[192]; int deterlen; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j, _k, _l, _m, _n; REAL _0, _1, _2; Two_Diff(pa[0], pd[0], adx, adxtail); Two_Diff(pa[1], pd[1], ady, adytail); Two_Diff(pa[2], pd[2], adz, adztail); Two_Diff(pb[0], pd[0], bdx, bdxtail); Two_Diff(pb[1], pd[1], bdy, bdytail); Two_Diff(pb[2], pd[2], bdz, bdztail); Two_Diff(pc[0], pd[0], cdx, cdxtail); Two_Diff(pc[1], pd[1], cdy, cdytail); Two_Diff(pc[2], pd[2], cdz, cdztail); Two_Two_Product(adx, adxtail, bdy, bdytail, axby7, axby[6], axby[5], axby[4], axby[3], axby[2], axby[1], axby[0]); axby[7] = axby7; negate = -ady; negatetail = -adytail; Two_Two_Product(bdx, bdxtail, negate, negatetail, bxay7, bxay[6], bxay[5], bxay[4], bxay[3], bxay[2], bxay[1], bxay[0]); bxay[7] = bxay7; Two_Two_Product(bdx, bdxtail, cdy, cdytail, bxcy7, bxcy[6], bxcy[5], bxcy[4], bxcy[3], bxcy[2], bxcy[1], bxcy[0]); bxcy[7] = bxcy7; negate = -bdy; negatetail = -bdytail; Two_Two_Product(cdx, cdxtail, negate, negatetail, cxby7, cxby[6], cxby[5], cxby[4], cxby[3], cxby[2], cxby[1], cxby[0]); cxby[7] = cxby7; Two_Two_Product(cdx, cdxtail, ady, adytail, cxay7, cxay[6], cxay[5], cxay[4], cxay[3], cxay[2], cxay[1], cxay[0]); cxay[7] = cxay7; negate = -cdy; negatetail = -cdytail; Two_Two_Product(adx, adxtail, negate, negatetail, axcy7, axcy[6], axcy[5], axcy[4], axcy[3], axcy[2], axcy[1], axcy[0]); axcy[7] = axcy7; temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16); temp32len = scale_expansion_zeroelim(temp16len, temp16, adz, temp32); temp32tlen = scale_expansion_zeroelim(temp16len, temp16, adztail, temp32t); alen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, adet); temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16); temp32len = scale_expansion_zeroelim(temp16len, temp16, bdz, temp32); temp32tlen = scale_expansion_zeroelim(temp16len, temp16, bdztail, temp32t); blen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, bdet); temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16); temp32len = scale_expansion_zeroelim(temp16len, temp16, cdz, temp32); temp32tlen = scale_expansion_zeroelim(temp16len, temp16, cdztail, temp32t); clen = fast_expansion_sum_zeroelim(temp32len, temp32, temp32tlen, temp32t, cdet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter); return deter[deterlen - 1]; } REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; REAL det, errbound; INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; REAL bc[4], ca[4], ab[4]; INEXACT REAL bc3, ca3, ab3; REAL adet[8], bdet[8], cdet[8]; int alen, blen, clen; REAL abdet[16]; int ablen; REAL *finnow, *finother, *finswap; REAL fin1[192], fin2[192]; int finlength; //////////////////////////////////////////////////////// // To avoid uninitialized warnings reported by valgrind. int i; for (i = 0; i < 8; i++) { adet[i] = bdet[i] = cdet[i] = 0.0; } for (i = 0; i < 16; i++) { abdet[i] = 0.0; } //////////////////////////////////////////////////////// REAL adxtail, bdxtail, cdxtail; REAL adytail, bdytail, cdytail; REAL adztail, bdztail, cdztail; INEXACT REAL at_blarge, at_clarge; INEXACT REAL bt_clarge, bt_alarge; INEXACT REAL ct_alarge, ct_blarge; REAL 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 REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; REAL bct[8], cat[8], abt[8]; int bctlen, catlen, abtlen; INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; REAL u[4], v[12], w[16]; INEXACT REAL u3; int vlength, wlength; REAL negate; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j, _k; REAL _0; adx = (REAL) (pa[0] - pd[0]); bdx = (REAL) (pb[0] - pd[0]); cdx = (REAL) (pc[0] - pd[0]); ady = (REAL) (pa[1] - pd[1]); bdy = (REAL) (pb[1] - pd[1]); cdy = (REAL) (pc[1] - pd[1]); adz = (REAL) (pa[2] - pd[2]); bdz = (REAL) (pb[2] - pd[2]); cdz = (REAL) (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]; } REAL orient3d(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; REAL det; REAL 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); } /*****************************************************************************/ /* */ /* incirclefast() Approximate 2D incircle test. Nonrobust. */ /* incircleexact() Exact 2D incircle test. Robust. */ /* incircleslow() Another exact 2D incircle test. Robust. */ /* incircle() Adaptive exact 2D incircle test. Robust. */ /* */ /* Return a positive value if the point pd lies inside the */ /* circle passing through pa, pb, and pc; a negative value if */ /* it lies outside; and zero if the four points are cocircular.*/ /* The points pa, pb, and pc must be in counterclockwise */ /* order, or the sign of the result will be reversed. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In incircle() only, */ /* 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, incircle() is usually quite */ /* fast, but will run more slowly when the input points are cocircular or */ /* nearly so. */ /* */ /*****************************************************************************/ REAL incirclefast(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, ady, bdx, bdy, cdx, cdy; REAL abdet, bcdet, cadet; REAL alift, blift, clift; adx = pa[0] - pd[0]; ady = pa[1] - pd[1]; bdx = pb[0] - pd[0]; bdy = pb[1] - pd[1]; cdx = pc[0] - pd[0]; cdy = pc[1] - pd[1]; abdet = adx * bdy - bdx * ady; bcdet = bdx * cdy - cdx * bdy; cadet = cdx * ady - adx * cdy; alift = adx * adx + ady * ady; blift = bdx * bdx + bdy * bdy; clift = cdx * cdx + cdy * cdy; return alift * bcdet + blift * cadet + clift * abdet; } REAL incircleexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { INEXACT REAL axby1, bxcy1, cxdy1, dxay1, axcy1, bxdy1; INEXACT REAL bxay1, cxby1, dxcy1, axdy1, cxay1, dxby1; REAL axby0, bxcy0, cxdy0, dxay0, axcy0, bxdy0; REAL bxay0, cxby0, dxcy0, axdy0, cxay0, dxby0; REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; REAL temp8[8]; int templen; REAL abc[12], bcd[12], cda[12], dab[12]; int abclen, bcdlen, cdalen, dablen; REAL det24x[24], det24y[24], det48x[48], det48y[48]; int xlen, ylen; REAL adet[96], bdet[96], cdet[96], ddet[96]; int alen, blen, clen, dlen; REAL abdet[192], cddet[192]; int ablen, cdlen; REAL deter[384]; int deterlen; int i; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _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], 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(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]); templen = fast_expansion_sum_zeroelim(4, cd, 4, da, temp8); cdalen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, cda); templen = fast_expansion_sum_zeroelim(4, da, 4, ab, temp8); dablen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, dab); for (i = 0; i < 4; i++) { bd[i] = -bd[i]; ac[i] = -ac[i]; } templen = fast_expansion_sum_zeroelim(4, ab, 4, bc, temp8); abclen = fast_expansion_sum_zeroelim(templen, temp8, 4, ac, abc); templen = fast_expansion_sum_zeroelim(4, bc, 4, cd, temp8); bcdlen = fast_expansion_sum_zeroelim(templen, temp8, 4, bd, bcd); xlen = scale_expansion_zeroelim(bcdlen, bcd, pa[0], det24x); xlen = scale_expansion_zeroelim(xlen, det24x, pa[0], det48x); ylen = scale_expansion_zeroelim(bcdlen, bcd, pa[1], det24y); ylen = scale_expansion_zeroelim(ylen, det24y, pa[1], det48y); alen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, adet); xlen = scale_expansion_zeroelim(cdalen, cda, pb[0], det24x); xlen = scale_expansion_zeroelim(xlen, det24x, -pb[0], det48x); ylen = scale_expansion_zeroelim(cdalen, cda, pb[1], det24y); ylen = scale_expansion_zeroelim(ylen, det24y, -pb[1], det48y); blen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, bdet); xlen = scale_expansion_zeroelim(dablen, dab, pc[0], det24x); xlen = scale_expansion_zeroelim(xlen, det24x, pc[0], det48x); ylen = scale_expansion_zeroelim(dablen, dab, pc[1], det24y); ylen = scale_expansion_zeroelim(ylen, det24y, pc[1], det48y); clen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, cdet); xlen = scale_expansion_zeroelim(abclen, abc, pd[0], det24x); xlen = scale_expansion_zeroelim(xlen, det24x, -pd[0], det48x); ylen = scale_expansion_zeroelim(abclen, abc, pd[1], det24y); ylen = scale_expansion_zeroelim(ylen, det24y, -pd[1], det48y); dlen = fast_expansion_sum_zeroelim(xlen, det48x, ylen, det48y, ddet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); return deter[deterlen - 1]; } REAL incircleslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; REAL adxtail, bdxtail, cdxtail; REAL adytail, bdytail, cdytail; REAL negate, negatetail; INEXACT REAL axby7, bxcy7, axcy7, bxay7, cxby7, cxay7; REAL axby[8], bxcy[8], axcy[8], bxay[8], cxby[8], cxay[8]; REAL temp16[16]; int temp16len; REAL detx[32], detxx[64], detxt[32], detxxt[64], detxtxt[64]; int xlen, xxlen, xtlen, xxtlen, xtxtlen; REAL x1[128], x2[192]; int x1len, x2len; REAL dety[32], detyy[64], detyt[32], detyyt[64], detytyt[64]; int ylen, yylen, ytlen, yytlen, ytytlen; REAL y1[128], y2[192]; int y1len, y2len; REAL adet[384], bdet[384], cdet[384], abdet[768], deter[1152]; int alen, blen, clen, ablen, deterlen; int i; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j, _k, _l, _m, _n; REAL _0, _1, _2; Two_Diff(pa[0], pd[0], adx, adxtail); Two_Diff(pa[1], pd[1], ady, adytail); Two_Diff(pb[0], pd[0], bdx, bdxtail); Two_Diff(pb[1], pd[1], bdy, bdytail); Two_Diff(pc[0], pd[0], cdx, cdxtail); Two_Diff(pc[1], pd[1], cdy, cdytail); Two_Two_Product(adx, adxtail, bdy, bdytail, axby7, axby[6], axby[5], axby[4], axby[3], axby[2], axby[1], axby[0]); axby[7] = axby7; negate = -ady; negatetail = -adytail; Two_Two_Product(bdx, bdxtail, negate, negatetail, bxay7, bxay[6], bxay[5], bxay[4], bxay[3], bxay[2], bxay[1], bxay[0]); bxay[7] = bxay7; Two_Two_Product(bdx, bdxtail, cdy, cdytail, bxcy7, bxcy[6], bxcy[5], bxcy[4], bxcy[3], bxcy[2], bxcy[1], bxcy[0]); bxcy[7] = bxcy7; negate = -bdy; negatetail = -bdytail; Two_Two_Product(cdx, cdxtail, negate, negatetail, cxby7, cxby[6], cxby[5], cxby[4], cxby[3], cxby[2], cxby[1], cxby[0]); cxby[7] = cxby7; Two_Two_Product(cdx, cdxtail, ady, adytail, cxay7, cxay[6], cxay[5], cxay[4], cxay[3], cxay[2], cxay[1], cxay[0]); cxay[7] = cxay7; negate = -cdy; negatetail = -cdytail; Two_Two_Product(adx, adxtail, negate, negatetail, axcy7, axcy[6], axcy[5], axcy[4], axcy[3], axcy[2], axcy[1], axcy[0]); axcy[7] = axcy7; temp16len = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, temp16); xlen = scale_expansion_zeroelim(temp16len, temp16, adx, detx); xxlen = scale_expansion_zeroelim(xlen, detx, adx, detxx); xtlen = scale_expansion_zeroelim(temp16len, temp16, adxtail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, adx, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, adxtail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp16len, temp16, ady, dety); yylen = scale_expansion_zeroelim(ylen, dety, ady, detyy); ytlen = scale_expansion_zeroelim(temp16len, temp16, adytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, ady, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, adytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); alen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, adet); temp16len = fast_expansion_sum_zeroelim(8, cxay, 8, axcy, temp16); xlen = scale_expansion_zeroelim(temp16len, temp16, bdx, detx); xxlen = scale_expansion_zeroelim(xlen, detx, bdx, detxx); xtlen = scale_expansion_zeroelim(temp16len, temp16, bdxtail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, bdx, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bdxtail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp16len, temp16, bdy, dety); yylen = scale_expansion_zeroelim(ylen, dety, bdy, detyy); ytlen = scale_expansion_zeroelim(temp16len, temp16, bdytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, bdy, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, bdytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); blen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, bdet); temp16len = fast_expansion_sum_zeroelim(8, axby, 8, bxay, temp16); xlen = scale_expansion_zeroelim(temp16len, temp16, cdx, detx); xxlen = scale_expansion_zeroelim(xlen, detx, cdx, detxx); xtlen = scale_expansion_zeroelim(temp16len, temp16, cdxtail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, cdx, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cdxtail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp16len, temp16, cdy, dety); yylen = scale_expansion_zeroelim(ylen, dety, cdy, detyy); ytlen = scale_expansion_zeroelim(temp16len, temp16, cdytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, cdy, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, cdytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); clen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, cdet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); deterlen = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, deter); return deter[deterlen - 1]; } REAL incircleadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL permanent) { INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; REAL det, errbound; INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; REAL bc[4], ca[4], ab[4]; INEXACT REAL bc3, ca3, ab3; REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; int axbclen, axxbclen, aybclen, ayybclen, alen; REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; int bxcalen, bxxcalen, bycalen, byycalen, blen; REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; int cxablen, cxxablen, cyablen, cyyablen, clen; REAL abdet[64]; int ablen; REAL fin1[1152], fin2[1152]; REAL *finnow, *finother, *finswap; int finlength; REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; REAL aa[4], bb[4], cc[4]; INEXACT REAL aa3, bb3, cc3; INEXACT REAL ti1, tj1; REAL ti0, tj0; REAL u[4], v[4]; INEXACT REAL u3, v3; REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; int temp8len, temp16alen, temp16blen, temp16clen; int temp32alen, temp32blen, temp48len, temp64len; REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; int axtbblen, axtcclen, aytbblen, aytcclen; REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; int bxtaalen, bxtcclen, bytaalen, bytcclen; REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; int cxtaalen, cxtbblen, cytaalen, cytbblen; REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; REAL axtbctt[8], aytbctt[8], bxtcatt[8]; REAL bytcatt[8], cxtabtt[8], cytabtt[8]; int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; REAL abt[8], bct[8], cat[8]; int abtlen, bctlen, catlen; REAL abtt[4], bctt[4], catt[4]; int abttlen, bcttlen, cattlen; INEXACT REAL abtt3, bctt3, catt3; REAL negate; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; adx = (REAL) (pa[0] - pd[0]); bdx = (REAL) (pb[0] - pd[0]); cdx = (REAL) (pc[0] - pd[0]); ady = (REAL) (pa[1] - pd[1]); bdy = (REAL) (pb[1] - pd[1]); cdy = (REAL) (pc[1] - pd[1]); 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; axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, 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; bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, 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; cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, 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 = iccerrboundB * permanent; if ((det >= errbound) || (-det >= errbound)) { return det; } Two_Diff_Tail(pa[0], pd[0], adx, adxtail); Two_Diff_Tail(pa[1], pd[1], ady, adytail); Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { return det; } errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - (bdy * cdxtail + cdx * bdytail)) + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - (cdy * adxtail + adx * cdytail)) + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - (ady * bdxtail + bdx * adytail)) + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); if ((det >= errbound) || (-det >= errbound)) { return det; } finnow = fin1; finother = fin2; if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) { Square(adx, adxadx1, adxadx0); Square(ady, adyady1, adyady0); Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); aa[3] = aa3; } if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) { Square(bdx, bdxbdx1, bdxbdx0); Square(bdy, bdybdy1, bdybdy0); Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); bb[3] = bb3; } if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) { Square(cdx, cdxcdx1, cdxcdx0); Square(cdy, cdycdy1, cdycdy0); Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); cc[3] = cc3; } if (adxtail != 0.0) { axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, temp16a); axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adytail != 0.0) { aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, temp16a); aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdxtail != 0.0) { bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, temp16a); bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdytail != 0.0) { bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, temp16a); bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdxtail != 0.0) { cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, temp16a); cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdytail != 0.0) { cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, temp16a); cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; } if ((adxtail != 0.0) || (adytail != 0.0)) { if ((bdxtail != 0.0) || (bdytail != 0.0) || (cdxtail != 0.0) || (cdytail != 0.0)) { Two_Product(bdxtail, cdy, ti1, ti0); Two_Product(bdx, cdytail, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); u[3] = u3; negate = -bdy; Two_Product(cdxtail, negate, ti1, ti0); negate = -bdytail; Two_Product(cdx, negate, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); v[3] = v3; bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); Two_Product(bdxtail, cdytail, ti1, ti0); Two_Product(cdxtail, bdytail, tj1, tj0); Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); bctt[3] = bctt3; bcttlen = 4; } else { bct[0] = 0.0; bctlen = 1; bctt[0] = 0.0; bcttlen = 1; } if (adxtail != 0.0) { temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; if (bdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, temp32a); axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, temp16a); temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adytail != 0.0) { temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, temp32a); aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, temp16a); temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } } if ((bdxtail != 0.0) || (bdytail != 0.0)) { if ((cdxtail != 0.0) || (cdytail != 0.0) || (adxtail != 0.0) || (adytail != 0.0)) { Two_Product(cdxtail, ady, ti1, ti0); Two_Product(cdx, adytail, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); u[3] = u3; negate = -cdy; Two_Product(adxtail, negate, ti1, ti0); negate = -cdytail; Two_Product(adx, negate, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); v[3] = v3; catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); Two_Product(cdxtail, adytail, ti1, ti0); Two_Product(adxtail, cdytail, tj1, tj0); Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); catt[3] = catt3; cattlen = 4; } else { cat[0] = 0.0; catlen = 1; catt[0] = 0.0; cattlen = 1; } if (bdxtail != 0.0) { temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; if (cdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } if (adytail != 0.0) { temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, temp32a); bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, temp16a); temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdytail != 0.0) { temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, temp32a); bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, temp16a); temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } } if ((cdxtail != 0.0) || (cdytail != 0.0)) { if ((adxtail != 0.0) || (adytail != 0.0) || (bdxtail != 0.0) || (bdytail != 0.0)) { Two_Product(adxtail, bdy, ti1, ti0); Two_Product(adx, bdytail, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); u[3] = u3; negate = -ady; Two_Product(bdxtail, negate, ti1, ti0); negate = -adytail; Two_Product(bdx, negate, tj1, tj0); Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); v[3] = v3; abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); Two_Product(adxtail, bdytail, ti1, ti0); Two_Product(bdxtail, adytail, tj1, tj0); Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); abtt[3] = abtt3; abttlen = 4; } else { abt[0] = 0.0; abtlen = 1; abtt[0] = 0.0; abttlen = 1; } if (cdxtail != 0.0) { temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; if (adytail != 0.0) { temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } if (bdytail != 0.0) { temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, temp16a); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, temp16a, finother); finswap = finnow; finnow = finother; finother = finswap; } temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, temp32a); cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, temp16a); temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } if (cdytail != 0.0) { temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, temp32a); temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp32alen, temp32a, temp48); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, temp48, finother); finswap = finnow; finnow = finother; finother = finswap; temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, temp32a); cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, temp16a); temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, temp16b); temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, temp16blen, temp16b, temp32b); temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64); finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, temp64, finother); finswap = finnow; finnow = finother; finother = finswap; } } return finnow[finlength - 1]; } REAL incircle(REAL *pa, REAL *pb, REAL *pc, REAL *pd) { REAL adx, bdx, cdx, ady, bdy, cdy; REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; REAL alift, blift, clift; REAL det; REAL 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]; bdxcdy = bdx * cdy; cdxbdy = cdx * bdy; alift = adx * adx + ady * ady; cdxady = cdx * ady; adxcdy = adx * cdy; blift = bdx * bdx + bdy * bdy; adxbdy = adx * bdy; bdxady = bdx * ady; clift = cdx * cdx + cdy * cdy; det = alift * (bdxcdy - cdxbdy) + blift * (cdxady - adxcdy) + clift * (adxbdy - bdxady); permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + (Absolute(cdxady) + Absolute(adxcdy)) * blift + (Absolute(adxbdy) + Absolute(bdxady)) * clift; errbound = iccerrboundA * permanent; if ((det > errbound) || (-det > errbound)) { return det; } return incircleadapt(pa, pb, pc, pd, permanent); } /*****************************************************************************/ /* */ /* inspherefast() Approximate 3D insphere test. Nonrobust. */ /* insphereexact() Exact 3D insphere test. Robust. */ /* insphereslow() Another exact 3D insphere test. Robust. */ /* insphere() Adaptive exact 3D insphere test. Robust. */ /* */ /* 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. */ /* */ /* Only the first and last routine should be used; the middle two are for */ /* timings. */ /* */ /* The last three use exact arithmetic to ensure a correct answer. The */ /* result returned is the determinant of a matrix. In insphere() only, */ /* 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, insphere() is usually quite */ /* fast, but will run more slowly when the input points are cospherical or */ /* nearly so. */ /* */ /*****************************************************************************/ REAL inspherefast(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { REAL aex, bex, cex, dex; REAL aey, bey, cey, dey; REAL aez, bez, cez, dez; REAL alift, blift, clift, dlift; REAL ab, bc, cd, da, ac, bd; REAL abc, bcd, cda, dab; 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]; ab = aex * bey - bex * aey; bc = bex * cey - cex * bey; cd = cex * dey - dex * cey; da = dex * aey - aex * dey; ac = aex * cey - cex * aey; bd = bex * dey - dex * bey; 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; return (dlift * abc - clift * dab) + (blift * cda - alift * bcd); } REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1; INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1; REAL axby0, bxcy0, cxdy0, dxey0, exay0; REAL bxay0, cxby0, dxcy0, exdy0, axey0; REAL axcy0, bxdy0, cxey0, dxay0, exby0; REAL cxay0, dxby0, excy0, axdy0, bxey0; REAL ab[4], bc[4], cd[4], de[4], ea[4]; REAL ac[4], bd[4], ce[4], da[4], eb[4]; REAL temp8a[8], temp8b[8], temp16[16]; int temp8alen, temp8blen, temp16len; REAL abc[24], bcd[24], cde[24], dea[24], eab[24]; REAL abd[24], bce[24], cda[24], deb[24], eac[24]; int abclen, bcdlen, cdelen, dealen, eablen; int abdlen, bcelen, cdalen, deblen, eaclen; REAL temp48a[48], temp48b[48]; int temp48alen, temp48blen; REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96]; int abcdlen, bcdelen, cdealen, deablen, eabclen; REAL temp192[192]; REAL det384x[384], det384y[384], det384z[384]; int xlen, ylen, zlen; REAL detxy[768]; int xylen; REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152]; int alen, blen, clen, dlen, elen; REAL abdet[2304], cddet[2304], cdedet[3456]; int ablen, cdlen; REAL deter[5760]; int deterlen; int i; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _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]; } REAL insphereslow(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; REAL aextail, bextail, cextail, dextail; REAL aeytail, beytail, ceytail, deytail; REAL aeztail, beztail, ceztail, deztail; REAL negate, negatetail; INEXACT REAL axby7, bxcy7, cxdy7, dxay7, axcy7, bxdy7; INEXACT REAL bxay7, cxby7, dxcy7, axdy7, cxay7, dxby7; REAL axby[8], bxcy[8], cxdy[8], dxay[8], axcy[8], bxdy[8]; REAL bxay[8], cxby[8], dxcy[8], axdy[8], cxay[8], dxby[8]; REAL ab[16], bc[16], cd[16], da[16], ac[16], bd[16]; int ablen, bclen, cdlen, dalen, aclen, bdlen; REAL temp32a[32], temp32b[32], temp64a[64], temp64b[64], temp64c[64]; int temp32alen, temp32blen, temp64alen, temp64blen, temp64clen; REAL temp128[128], temp192[192]; int temp128len, temp192len; REAL detx[384], detxx[768], detxt[384], detxxt[768], detxtxt[768]; int xlen, xxlen, xtlen, xxtlen, xtxtlen; REAL x1[1536], x2[2304]; int x1len, x2len; REAL dety[384], detyy[768], detyt[384], detyyt[768], detytyt[768]; int ylen, yylen, ytlen, yytlen, ytytlen; REAL y1[1536], y2[2304]; int y1len, y2len; REAL detz[384], detzz[768], detzt[384], detzzt[768], detztzt[768]; int zlen, zzlen, ztlen, zztlen, ztztlen; REAL z1[1536], z2[2304]; int z1len, z2len; REAL detxy[4608]; int xylen; REAL adet[6912], bdet[6912], cdet[6912], ddet[6912]; int alen, blen, clen, dlen; REAL abdet[13824], cddet[13824], deter[27648]; int deterlen; int i; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL a0hi, a0lo, a1hi, a1lo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j, _k, _l, _m, _n; REAL _0, _1, _2; Two_Diff(pa[0], pe[0], aex, aextail); Two_Diff(pa[1], pe[1], aey, aeytail); Two_Diff(pa[2], pe[2], aez, aeztail); Two_Diff(pb[0], pe[0], bex, bextail); Two_Diff(pb[1], pe[1], bey, beytail); Two_Diff(pb[2], pe[2], bez, beztail); Two_Diff(pc[0], pe[0], cex, cextail); Two_Diff(pc[1], pe[1], cey, ceytail); Two_Diff(pc[2], pe[2], cez, ceztail); Two_Diff(pd[0], pe[0], dex, dextail); Two_Diff(pd[1], pe[1], dey, deytail); Two_Diff(pd[2], pe[2], dez, deztail); Two_Two_Product(aex, aextail, bey, beytail, axby7, axby[6], axby[5], axby[4], axby[3], axby[2], axby[1], axby[0]); axby[7] = axby7; negate = -aey; negatetail = -aeytail; Two_Two_Product(bex, bextail, negate, negatetail, bxay7, bxay[6], bxay[5], bxay[4], bxay[3], bxay[2], bxay[1], bxay[0]); bxay[7] = bxay7; ablen = fast_expansion_sum_zeroelim(8, axby, 8, bxay, ab); Two_Two_Product(bex, bextail, cey, ceytail, bxcy7, bxcy[6], bxcy[5], bxcy[4], bxcy[3], bxcy[2], bxcy[1], bxcy[0]); bxcy[7] = bxcy7; negate = -bey; negatetail = -beytail; Two_Two_Product(cex, cextail, negate, negatetail, cxby7, cxby[6], cxby[5], cxby[4], cxby[3], cxby[2], cxby[1], cxby[0]); cxby[7] = cxby7; bclen = fast_expansion_sum_zeroelim(8, bxcy, 8, cxby, bc); Two_Two_Product(cex, cextail, dey, deytail, cxdy7, cxdy[6], cxdy[5], cxdy[4], cxdy[3], cxdy[2], cxdy[1], cxdy[0]); cxdy[7] = cxdy7; negate = -cey; negatetail = -ceytail; Two_Two_Product(dex, dextail, negate, negatetail, dxcy7, dxcy[6], dxcy[5], dxcy[4], dxcy[3], dxcy[2], dxcy[1], dxcy[0]); dxcy[7] = dxcy7; cdlen = fast_expansion_sum_zeroelim(8, cxdy, 8, dxcy, cd); Two_Two_Product(dex, dextail, aey, aeytail, dxay7, dxay[6], dxay[5], dxay[4], dxay[3], dxay[2], dxay[1], dxay[0]); dxay[7] = dxay7; negate = -dey; negatetail = -deytail; Two_Two_Product(aex, aextail, negate, negatetail, axdy7, axdy[6], axdy[5], axdy[4], axdy[3], axdy[2], axdy[1], axdy[0]); axdy[7] = axdy7; dalen = fast_expansion_sum_zeroelim(8, dxay, 8, axdy, da); Two_Two_Product(aex, aextail, cey, ceytail, axcy7, axcy[6], axcy[5], axcy[4], axcy[3], axcy[2], axcy[1], axcy[0]); axcy[7] = axcy7; negate = -aey; negatetail = -aeytail; Two_Two_Product(cex, cextail, negate, negatetail, cxay7, cxay[6], cxay[5], cxay[4], cxay[3], cxay[2], cxay[1], cxay[0]); cxay[7] = cxay7; aclen = fast_expansion_sum_zeroelim(8, axcy, 8, cxay, ac); Two_Two_Product(bex, bextail, dey, deytail, bxdy7, bxdy[6], bxdy[5], bxdy[4], bxdy[3], bxdy[2], bxdy[1], bxdy[0]); bxdy[7] = bxdy7; negate = -bey; negatetail = -beytail; Two_Two_Product(dex, dextail, negate, negatetail, dxby7, dxby[6], dxby[5], dxby[4], dxby[3], dxby[2], dxby[1], dxby[0]); dxby[7] = dxby7; bdlen = fast_expansion_sum_zeroelim(8, bxdy, 8, dxby, bd); temp32alen = scale_expansion_zeroelim(cdlen, cd, -bez, temp32a); temp32blen = scale_expansion_zeroelim(cdlen, cd, -beztail, temp32b); temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64a); temp32alen = scale_expansion_zeroelim(bdlen, bd, cez, temp32a); temp32blen = scale_expansion_zeroelim(bdlen, bd, ceztail, temp32b); temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64b); temp32alen = scale_expansion_zeroelim(bclen, bc, -dez, temp32a); temp32blen = scale_expansion_zeroelim(bclen, bc, -deztail, temp32b); temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64c); temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, temp64blen, temp64b, temp128); temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, temp128len, temp128, temp192); xlen = scale_expansion_zeroelim(temp192len, temp192, aex, detx); xxlen = scale_expansion_zeroelim(xlen, detx, aex, detxx); xtlen = scale_expansion_zeroelim(temp192len, temp192, aextail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, aex, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, aextail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp192len, temp192, aey, dety); yylen = scale_expansion_zeroelim(ylen, dety, aey, detyy); ytlen = scale_expansion_zeroelim(temp192len, temp192, aeytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, aey, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, aeytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); zlen = scale_expansion_zeroelim(temp192len, temp192, aez, detz); zzlen = scale_expansion_zeroelim(zlen, detz, aez, detzz); ztlen = scale_expansion_zeroelim(temp192len, temp192, aeztail, detzt); zztlen = scale_expansion_zeroelim(ztlen, detzt, aez, detzzt); for (i = 0; i < zztlen; i++) { detzzt[i] *= 2.0; } ztztlen = scale_expansion_zeroelim(ztlen, detzt, aeztail, detztzt); z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); alen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, adet); temp32alen = scale_expansion_zeroelim(dalen, da, cez, temp32a); temp32blen = scale_expansion_zeroelim(dalen, da, ceztail, temp32b); temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64a); temp32alen = scale_expansion_zeroelim(aclen, ac, dez, temp32a); temp32blen = scale_expansion_zeroelim(aclen, ac, deztail, temp32b); temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64b); temp32alen = scale_expansion_zeroelim(cdlen, cd, aez, temp32a); temp32blen = scale_expansion_zeroelim(cdlen, cd, aeztail, temp32b); temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64c); temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, temp64blen, temp64b, temp128); temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, temp128len, temp128, temp192); xlen = scale_expansion_zeroelim(temp192len, temp192, bex, detx); xxlen = scale_expansion_zeroelim(xlen, detx, bex, detxx); xtlen = scale_expansion_zeroelim(temp192len, temp192, bextail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, bex, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, bextail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp192len, temp192, bey, dety); yylen = scale_expansion_zeroelim(ylen, dety, bey, detyy); ytlen = scale_expansion_zeroelim(temp192len, temp192, beytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, bey, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, beytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); zlen = scale_expansion_zeroelim(temp192len, temp192, bez, detz); zzlen = scale_expansion_zeroelim(zlen, detz, bez, detzz); ztlen = scale_expansion_zeroelim(temp192len, temp192, beztail, detzt); zztlen = scale_expansion_zeroelim(ztlen, detzt, bez, detzzt); for (i = 0; i < zztlen; i++) { detzzt[i] *= 2.0; } ztztlen = scale_expansion_zeroelim(ztlen, detzt, beztail, detztzt); z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); blen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, bdet); temp32alen = scale_expansion_zeroelim(ablen, ab, -dez, temp32a); temp32blen = scale_expansion_zeroelim(ablen, ab, -deztail, temp32b); temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64a); temp32alen = scale_expansion_zeroelim(bdlen, bd, -aez, temp32a); temp32blen = scale_expansion_zeroelim(bdlen, bd, -aeztail, temp32b); temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64b); temp32alen = scale_expansion_zeroelim(dalen, da, -bez, temp32a); temp32blen = scale_expansion_zeroelim(dalen, da, -beztail, temp32b); temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64c); temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, temp64blen, temp64b, temp128); temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, temp128len, temp128, temp192); xlen = scale_expansion_zeroelim(temp192len, temp192, cex, detx); xxlen = scale_expansion_zeroelim(xlen, detx, cex, detxx); xtlen = scale_expansion_zeroelim(temp192len, temp192, cextail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, cex, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, cextail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp192len, temp192, cey, dety); yylen = scale_expansion_zeroelim(ylen, dety, cey, detyy); ytlen = scale_expansion_zeroelim(temp192len, temp192, ceytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, cey, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, ceytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); zlen = scale_expansion_zeroelim(temp192len, temp192, cez, detz); zzlen = scale_expansion_zeroelim(zlen, detz, cez, detzz); ztlen = scale_expansion_zeroelim(temp192len, temp192, ceztail, detzt); zztlen = scale_expansion_zeroelim(ztlen, detzt, cez, detzzt); for (i = 0; i < zztlen; i++) { detzzt[i] *= 2.0; } ztztlen = scale_expansion_zeroelim(ztlen, detzt, ceztail, detztzt); z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); clen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, cdet); temp32alen = scale_expansion_zeroelim(bclen, bc, aez, temp32a); temp32blen = scale_expansion_zeroelim(bclen, bc, aeztail, temp32b); temp64alen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64a); temp32alen = scale_expansion_zeroelim(aclen, ac, -bez, temp32a); temp32blen = scale_expansion_zeroelim(aclen, ac, -beztail, temp32b); temp64blen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64b); temp32alen = scale_expansion_zeroelim(ablen, ab, cez, temp32a); temp32blen = scale_expansion_zeroelim(ablen, ab, ceztail, temp32b); temp64clen = fast_expansion_sum_zeroelim(temp32alen, temp32a, temp32blen, temp32b, temp64c); temp128len = fast_expansion_sum_zeroelim(temp64alen, temp64a, temp64blen, temp64b, temp128); temp192len = fast_expansion_sum_zeroelim(temp64clen, temp64c, temp128len, temp128, temp192); xlen = scale_expansion_zeroelim(temp192len, temp192, dex, detx); xxlen = scale_expansion_zeroelim(xlen, detx, dex, detxx); xtlen = scale_expansion_zeroelim(temp192len, temp192, dextail, detxt); xxtlen = scale_expansion_zeroelim(xtlen, detxt, dex, detxxt); for (i = 0; i < xxtlen; i++) { detxxt[i] *= 2.0; } xtxtlen = scale_expansion_zeroelim(xtlen, detxt, dextail, detxtxt); x1len = fast_expansion_sum_zeroelim(xxlen, detxx, xxtlen, detxxt, x1); x2len = fast_expansion_sum_zeroelim(x1len, x1, xtxtlen, detxtxt, x2); ylen = scale_expansion_zeroelim(temp192len, temp192, dey, dety); yylen = scale_expansion_zeroelim(ylen, dety, dey, detyy); ytlen = scale_expansion_zeroelim(temp192len, temp192, deytail, detyt); yytlen = scale_expansion_zeroelim(ytlen, detyt, dey, detyyt); for (i = 0; i < yytlen; i++) { detyyt[i] *= 2.0; } ytytlen = scale_expansion_zeroelim(ytlen, detyt, deytail, detytyt); y1len = fast_expansion_sum_zeroelim(yylen, detyy, yytlen, detyyt, y1); y2len = fast_expansion_sum_zeroelim(y1len, y1, ytytlen, detytyt, y2); zlen = scale_expansion_zeroelim(temp192len, temp192, dez, detz); zzlen = scale_expansion_zeroelim(zlen, detz, dez, detzz); ztlen = scale_expansion_zeroelim(temp192len, temp192, deztail, detzt); zztlen = scale_expansion_zeroelim(ztlen, detzt, dez, detzzt); for (i = 0; i < zztlen; i++) { detzzt[i] *= 2.0; } ztztlen = scale_expansion_zeroelim(ztlen, detzt, deztail, detztzt); z1len = fast_expansion_sum_zeroelim(zzlen, detzz, zztlen, detzzt, z1); z2len = fast_expansion_sum_zeroelim(z1len, z1, ztztlen, detztzt, z2); xylen = fast_expansion_sum_zeroelim(x2len, x2, y2len, y2, detxy); dlen = fast_expansion_sum_zeroelim(z2len, z2, xylen, detxy, ddet); ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, deter); return deter[deterlen - 1]; } REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, REAL permanent) { INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; REAL det, errbound; INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1; INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1; INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1; REAL aexbey0, bexaey0, bexcey0, cexbey0; REAL cexdey0, dexcey0, dexaey0, aexdey0; REAL aexcey0, cexaey0, bexdey0, dexbey0; REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3; REAL abeps, bceps, cdeps, daeps, aceps, bdeps; REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48]; int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len; REAL xdet[96], ydet[96], zdet[96], xydet[192]; int xlen, ylen, zlen, xylen; REAL adet[288], bdet[288], cdet[288], ddet[288]; int alen, blen, clen, dlen; REAL abdet[576], cddet[576]; int ablen, cdlen; REAL fin1[1152]; int finlength; REAL aextail, bextail, cextail, dextail; REAL aeytail, beytail, ceytail, deytail; REAL aeztail, beztail, ceztail, deztail; INEXACT REAL bvirt; REAL avirt, bround, around; INEXACT REAL c; INEXACT REAL abig; REAL ahi, alo, bhi, blo; REAL err1, err2, err3; INEXACT REAL _i, _j; REAL _0; aex = (REAL) (pa[0] - pe[0]); bex = (REAL) (pb[0] - pe[0]); cex = (REAL) (pc[0] - pe[0]); dex = (REAL) (pd[0] - pe[0]); aey = (REAL) (pa[1] - pe[1]); bey = (REAL) (pb[1] - pe[1]); cey = (REAL) (pc[1] - pe[1]); dey = (REAL) (pd[1] - pe[1]); aez = (REAL) (pa[2] - pe[2]); bez = (REAL) (pb[2] - pe[2]); cez = (REAL) (pc[2] - pe[2]); dez = (REAL) (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); } REAL insphere(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) { REAL aex, bex, cex, dex; REAL aey, bey, cey, dey; REAL aez, bez, cez, dez; REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; REAL aexcey, cexaey, bexdey, dexbey; REAL alift, blift, clift, dlift; REAL ab, bc, cd, da, ac, bd; REAL abc, bcd, cda, dab; REAL aezplus, bezplus, cezplus, dezplus; REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; REAL det; REAL permanent, errbound; 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); 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); } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/0000775000175000017500000000000011757446472016554 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/makefile0000664000175000017500000000636311757446472020264 0ustar lucaluca# makefile for Stellar # # Type "make" to compile Stellar on a Mac system. # Type "make linux" to compile Stellar on a Linux-like system. # Type "make showme" to compile Show Me on a system with X Windows. # # Type "make clean" to delete all executable and object files. # location of the Stellar source files SRC = ./src/ # location of the produced executables BIN = ./ # CC should be set to the name of your favorite C compiler. CC = cc # RM should be set to the name of your favorite rm (file deletion program). RM = /bin/rm # Switches for C compiler. -DNDEBUG suppresses assertions from assert.h CSWITCHES = -g -pg -DSELF_CHECK -DLINUX -Wall -Wconversion -Wstrict-prototypes -Wno-strict-aliasing -fno-strict-aliasing -I$(SRC) -I/usr/X11R6/include -L/usr/X11R6/lib CSWITCHESFAST = -DSELF_CHECK -g -DLINUX -O3 -Wall -Wconversion -Wstrict-prototypes -Wno-strict-aliasing -fno-strict-aliasing -I$(SRC) -I/usr/X11R6/include -L/usr/X11R6/lib CSWITCHESMAC = -arch i386 -arch ppc -g -pg -fast -DSELF_CHECK -Wall -Wno-strict-aliasing -fno-strict-aliasing -Wconversion -Wstrict-prototypes -I$(SRC) -I/usr/X11R6/include -L/usr/X11R6/lib CSWITCHESSTELLARMAC = -pedantic -g -pg -DSELF_CHECK -Wall -Wno-strict-aliasing -fno-strict-aliasing -Wconversion -Wstrict-prototypes -I$(SRC) CSWITCHESSTELLARMACFAST = -arch i386 -arch ppc -pedantic -fast -Wall -Wno-strict-aliasing -fno-strict-aliasing -Wconversion -Wstrict-prototypes -I$(SRC) # Where to find the basic X Windows (X11) #include files and libraries SHOWMESWITCHES = -I/usr/X11R6/include -L/usr/X11R6/lib STARLIBDEFS = -DNOMAIN # sources for Stellar STELLARSRCS = $(SRC)Stellar.c $(SRC)arraypoolstack.c $(SRC)classify.c $(SRC)insertion.c $(SRC)interact.c $(SRC)journal.c $(SRC)main.c $(SRC)output.c $(SRC)print.c $(SRC)quadric.c $(SRC)anisotropy.c $(SRC)quality.c $(SRC)size.c $(SRC)smoothing.c $(SRC)top.c $(SRC)topological.c $(SRC)vector.c $(SRC)improve.c $(SRC)Starbase.c all: mac mac: $(BIN)Stellarmac macdebug: $(BIN)Stellarmacdebug macshowme: $(BIN)showmemac linux: $(BIN)Stellarlinux linuxdebug: $(BIN)Stellarlinuxdebug linuxshowme: $(BIN)showmelinux $(BIN)Stellarlinux: $(BIN)Starbase.o $(STELLARSRCS) $(CC) $(CSWITCHESFAST) -o $(BIN)Stellar $(SRC)Stellar.c \ $(BIN)Starbase.o -lm $(BIN)Stellarlinuxdebug: $(BIN)Starbase.o $(STELLARSRCS) $(CC) $(CSWITCHES) -o $(BIN)Stellardebug $(SRC)Stellar.c \ $(BIN)Starbase.o -lm $(BIN)Stellarmac: $(BIN)Starbasemac.o $(STELLARSRCS) $(CC) $(CSWITCHESSTELLARMACFAST) -o $(BIN)Stellar $(SRC)Stellar.c \ $(BIN)Starbasemac.o -lm $(BIN)Stellarmacdebug: $(BIN)Starbasemac.o $(STELLARSRCS) $(CC) $(CSWITCHESSTELLARMAC) -o $(BIN)Stellardebug $(SRC)Stellar.c \ $(BIN)Starbasemac.o -lm $(BIN)Starbasemac.o: $(SRC)Starbase.c $(SRC)Starbase.h $(CC) $(CSWITCHESMAC) $(STARLIBDEFS) -c -o $(BIN)Starbasemac.o \ $(SRC)Starbase.c $(BIN)Starbase.o: $(SRC)Starbase.c $(SRC)Starbase.h $(CC) $(CSWITCHESFAST) $(STARLIBDEFS) -c -o $(BIN)Starbase.o \ $(SRC)Starbase.c $(BIN)showmelinux: $(SRC)showme.c $(CC) $(CSWITCHESFAST) $(SHOWMESWITCHES) -o $(BIN)showme \ $(SRC)showme.c -lX11 -lm $(BIN)showmemac: $(SRC)showme.c $(CC) $(CSWITCHESMACFAST) $(SHOWMESWITCHES) -o $(BIN)showme \ $(SRC)showme.c -lX11 -lm clean: -$(RM) $(BIN)Starbase.o $(BIN)Starbasemac.o $(BIN)Stellar $(BIN)Stellardebug $(BIN)showme vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/meshconvert.py0000775000175000017500000006626011757446472021500 0ustar lucaluca#!/usr/bin/env python # encoding: utf-8 """ meshconvert.py A script to convert between tetrahedral mesh formats. Created by Bryan Klingner (stellar.b@overt.org) on 2006-12-07. """ import sys import getopt import os help_message = \ ''' meshconvert.py - a script to convert between tetrahedral mesh formats. Usage: meshconvert.py [-s scale] input_file output_file input_file the input tetrahedral (or trianglar surface) mesh file. This file must be in one of the following formats: .node - Jonathan Shewchuk's node file format. .node files must be accompanied by a .ele file that contains tetrahedra. .mesh - NETGEN's tetrahedral mesh format. .vmesh - GRUMMP's tetrahedral mesh format. .tet - AIM@SHAPE repository's tetrahedral mesh format. .off - A common surface mesh format. If the input file is in .off format, only boundary triangles will be read and available for output. .surf - NETGEN's triangle surface mesh format. If the input file is in .surf format, only boundary triangles will be read and available for output. output_file the output tetrahedral (or triangular surface) mesh file. This file must be in one of the following formats: .node - Jonathan Shewchuk's mesh file format. An additional .ele file will also be output that contains tetrahedra. .mesh - NETGEN's tetrahedral mesh format. .obj - A common surface mesh format. If the output file is in .obj format, only boundary triangles will be written to it. .off - A common surface mesh format. If the output file is in .off format, only boundary triangles will be written to it. .surf - NETGEN's tetrahedral mesh format. If the output file is in .surf format, only boundary triangles will be written to it. -s scale optional vertex scale argument. All vertices geometric positions will be multiplied by scale in the output file. NOTE: As part of the conversion process, all tetrahedra will be adjusted to have consistent, right-handed orientation: That is, for a tetrahedron with vertices ordered (1, 2, 3, 4), 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. ''' class Usage(Exception): def __init__(self, msg): self.msg = msg def main(argv=None): # functions for reading readDict = {} readDict['.node'] = readNodeEle readDict['.mesh'] = readMesh readDict['.vmesh'] = readVmesh readDict['.tet'] = readTet readDict['.surf'] = readSurfTets readDict['.off'] = ReadOFFTets # functions for writing writeDict = {} writeDict['.node'] = writeNodeEle writeDict['.mesh'] = writeMesh writeDict['.obj'] = writeOBJTets writeDict['.off'] = writeOFFTets writeDict['.surf'] = writeSurfTets if argv is None: argv = sys.argv doscale = False # if they invoke with arguments, parse them if len(argv) > 1: try: try: opts, args = getopt.getopt(argv[1:], "hs:", ["help",]) except getopt.error, msg: raise Usage(msg) # option processing for option, value in opts: if option == "-s": doscale = True scale = float(value) if option in ("-h", "--help"): print help_message return 1 except Usage, err: print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg) print >> sys.stderr, "\t for help use --help" return 2 else: print help_message return 1 if len(argv) < 3: print "Not enough arguments. For help, use --help." # determine the input and output formats, and check that they make sense inFileName = argv[-2] outFileName = argv[-1] inFileNameBase, inType = os.path.splitext(inFileName) outFileNameBase, outType = os.path.splitext(outFileName) if inType not in readDict.keys(): print "Don't know how to read input format '%s'; invoke with --help for a list of supported formats." % (inType) return 2 if outType not in writeDict.keys(): print "Don't know how to write output format '%s'; invoke with --help for a list of supported formats." % (outType) return 2 # read the input mesh points, tets, boundFaces = readDict[inType](inFileNameBase) if doscale: print "Scaling vertices by %g", scale points = [vscale(scale, point) for point in points] # write the output mesh writeDict[outType](points, tets, boundFaces, outFileNameBase) #### # Functions to READ tet mesh formats #### def readTet(meshFileName): """Read .tet format... I don't actually remember who uses this""" # append .mesh to file stem meshFileName += '.tet' # open input .tet file infile = open(meshFileName) # fetch the number of points numpoints = int(infile.readline().split()[0]) # fetch the number of tets numtets = int(infile.readline().split()[0]) points = [] # read in all the points for iter in range(0,numpoints): points.append(map(float,infile.readline().strip().split())) tets = [] # read in the tets for iter in range(0,numtets): tets.append(vaddscalar(1,map(int,infile.readline().strip().split()[1:]))) # correct orientation of tets for tetNum, tet in enumerate(tets): a = points[tet[0]-1] b = points[tet[1]-1] c = points[tet[2]-1] d = points[tet[3]-1] # if tet is negative orientation, flip two verts if orient3d(a,b,c,d) == 0: print "WHOA! input zero-volume tet...\n" if orient3d(a,b,c,d) < 0: temp = tet[0] tets[tetNum][0] = tet[1] tets[tetNum][1] = temp # this function doesn't attempt to recover boundary faces boundFaces = [] infile.close() return points, tets, boundFaces def readMesh(meshFileName): """Read .mesh files, as output by NETGEN""" # append .mesh to file stem meshFileName += '.mesh' # open input .mesh file infile = open(meshFileName) # fetch the number of points numpoints = int(infile.readline()) points = [] # read in all the points for iter in range(0,numpoints): points.append(map(float,infile.readline().strip().split())) # fetch the number of tets numtets = int(infile.readline()) tets = [] # read in the tets for iter in range(0,numtets): tets.append(map(int,infile.readline().strip().split()[1:])) # correct orientation of tets for tetNum, tet in enumerate(tets): a = points[tet[0]-1] b = points[tet[1]-1] c = points[tet[2]-1] d = points[tet[3]-1] # if tet is negative orientation, flip two verts if orient3d(a,b,c,d) == 0: print "WHOA! input zero-volume tet...\n" sys.exit(1) if orient3d(a,b,c,d) < 0: temp = tet[0] tets[tetNum][0] = tet[1] tets[tetNum][1] = temp # fetch the number of boundary faces numfaces = int(infile.readline()) boundFaces = [] # read in the boundary faces for iter in range(0,numfaces): boundFaces.append(map(int,infile.readline().strip().split()[1:])) infile.close() # fix tets to reference points starting at 0 for index, tet in enumerate(tets): tets[index] = vsubscalar(1,tet) return points, tets, boundFaces def readVmesh(meshFileName): """Read in .vmesh file... again, I can't recall who uses this format""" # append .vmesh to file stem meshFileName += '.vmesh' # open input .vmesh file infile = open(meshFileName) # first line: #tets #faces #boundFaces #verts firstLine = map(int,infile.readline().strip().split()) numTets = firstLine[0] numFaces = firstLine[1] numBoundFaces = firstLine[2] numPoints = firstLine[3] points = [] # read in all the points for iter in range(0,numPoints): points.append(map(float,infile.readline().strip().split())) faces = [] face2tet = [] for iter in range(0,numFaces): line = map(int,infile.readline().strip().split()) face2tet.append(line[0:2]) faces.append(line[2:]) boundFaces = [] for iter in range(0,numBoundFaces): boundFaces.append(map(int,infile.readline().strip().split()[2:])) boundFaces[-1][0] = boundFaces[-1][0] + 1 boundFaces[-1][1] = boundFaces[-1][1] + 1 boundFaces[-1][2] = boundFaces[-1][2] + 1 boundFaces[-1].reverse() tets = [[]] * numTets mintet = 100 maxtet = 0 # reconstruct tets from face and face2tet information # for each face for faceNum, face in enumerate(faces): # for each vertex in the face for vert in face: # for each tet that has this face for tetNum in face2tet[faceNum]: # if this is a legit tet index if tetNum >= 0: # use tetNum - 1 because .vmesh starts with tet 1 if (vert+1 in tets[tetNum]) == False: tets[tetNum] = tets[tetNum] + [vert+1] # correct orientation of tets for tetNum, tet in enumerate(tets): a = points[tet[0]-1] b = points[tet[1]-1] c = points[tet[2]-1] d = points[tet[3]-1] # if tet is negative orientation, flip two verts if orient3d(a,b,c,d) == 0: print "WHOA! input zero-volume tet...\n" if orient3d(a,b,c,d) < 0: temp = tet[0] tets[tetNum][0] = tet[1] tets[tetNum][1] = temp return points, tets, boundFaces def readNodeEle(filename, computeTopo=True): """Read a tetrahedral mesh in .node/.ele format, Jonathan Shewchuk's format. The .node file specifies the vertex locations and the .ele format specfies the tetrahedra. The .node file might start with an index of one or zero.""" points, startFromZero = ReadNode(filename) tets = ReadEle(filename, startFromZero) # correct orientation of tets for tetNum, tet in enumerate(tets): a = points[tet[0]] b = points[tet[1]] c = points[tet[2]] d = points[tet[3]] # if tet is negative orientation, flip two verts if orient3d(a,b,c,d) == 0.0: print "WHOA! input zero-volume tet#%d...", tetNum print "a=", ' '.join(['%0.18g' % x for x in a]) print "b=", ' '.join(['%0.18g' % x for x in b]) print "c=", ' '.join(['%0.18g' % x for x in c]) print "d=", ' '.join(['%0.18g' % x for x in d]) if orient3d(a,b,c,d) < 0.0: print "correcting inverted tet #%d", tetNum temp = tet[0] tets[tetNum][0] = tet[1] tets[tetNum][1] = temp # build face topology information if computeTopo: faces, boundFaces, face2tet = GetFaceTopo(tets) else: boundFaces = None return points, tets, boundFaces def GetFaceTopo(tets): """Recover topological information about faces""" # first, build list of all passible faces faces = [] for tet in tets: # append each (outward oriented) face of the tet faces.append([tet[0], tet[1], tet[2]]) faces.append([tet[0], tet[2], tet[3]]) faces.append([tet[0], tet[3], tet[1]]) faces.append([tet[1], tet[3], tet[2]]) # sort the faces so the indices are in consistent order sortedFaces = [sorted(face) for face in faces] # get the unique faces uniqueFaces = unique(sortedFaces) uFaceDict = {} # build a dictionary of unique faces to speed lookup for facenum, face in enumerate(uniqueFaces): uFaceDict[tuple(face)] = facenum # build the tet -> face mapping by finding the index # into the unique face list for each face of each tet tet2face = [] for tetNum in range(0, len(tets)): tet2face.append([uFaceDict[tuple(sortedFaces[tetNum*4])], uFaceDict[tuple(sortedFaces[tetNum*4+1])], uFaceDict[tuple(sortedFaces[tetNum*4+2])], uFaceDict[tuple(sortedFaces[tetNum*4+3])]]) # build the face -> tet mapping by finding the one or two tets # that contain each face in the unique face list face2tet = [] for face in uniqueFaces: face2tet.append([-1, -1]) for tetNum, tetfaces in enumerate(tet2face): for face in tetfaces: #print "creating face2tet, tetnum = %d, face = %d" % (tetNum, face) # if no tets have been recorded for this face, put it # in the first face if face2tet[face][0] == -1: face2tet[face][0] = tetNum else: # the second entry must not have a tet yet if (face2tet[face][1] != -1): print "whoa, fount more than two tets for a face?" print "tetnum is %d, face2tet[face] is" % tetNum, face2tet[face] assert(face2tet[face][1] == -1) face2tet[face][1] = tetNum #print "built face2tet." boundaryFaces = [] # finally, get the list of boundary faces by building # list of all faces with just one tet for faceNum, facetets in enumerate(face2tet): if facetets[1] == -1: # this face has just one tet; it's a boundary face tet = tets[facetets[0]] tetfaces = [[tet[0], tet[1], tet[2]], [tet[0], tet[2], tet[3]], [tet[0], tet[3], tet[1]], [tet[1], tet[3], tet[2]]] # find the properly oriented face foundface = False for face in tetfaces: if (uniqueFaces[faceNum] == sorted(face)): #print "found correct oriented face [%d %d %d] corresponding to unique face [%d %d %d]" % (face[0], face[1], face[2], uniqueFaces[faceNum][0], uniqueFaces[faceNum][1], uniqueFaces[faceNum][2]) boundaryFaces.append(face) foundface = True assert(foundface) foundface = False #print "there are %d boundary faces" % len(boundaryFaces) return uniqueFaces, boundaryFaces, face2tet def readSurfTets(fileName): """A stub function to read surface faces from a .surf file, as output by NETGEN, as though it is a tet format""" points, tris = readSurf(fileName) return points, None, tris def readSurf(fileName): """read .surf file format, containing the surface faces of a tet mesh as output by NETGEN""" inFileName = fileName + '.surf' # open input .surf file infile = open(inFileName) # read first line, make sure it's right header = infile.readline().strip() assert(header == 'surfacemesh') # read second line, number of vertices numPoints = int(infile.readline().strip()) # read in all the points points = [] for iter in range(0,numPoints): points.append(map(float,infile.readline().strip().split())) # read number of faces numTris = int(infile.readline().strip()) # read in all the faces tris = [] for iter in range(0,numTris): tri = map(int,infile.readline().strip().split()) tri[0] = tri[0] - 1 tri[1] = tri[1] - 1 tri[2] = tri[2] - 1 tris.append(tri) return points, tris def ReadOFF(fileName): """Read OFF surface mesh format""" inFileName = fileName + '.off' # read input .off file infile = open(inFileName) # check for proper header header = infile.readline().strip() assert(header == 'OFF') # read second line "numverts numfaces 0" numPoints, numTris, blah = map(int, infile.readline().strip().split()) print "reading OFF numPoints is %d numTris is %d" % (numPoints, numTris) # read in points points = [] for iter in range(0,numPoints): points.append(map(float,infile.readline().strip().split())) # read in triangles tris = [] for iter in range(0,numTris): tri = map(int,infile.readline().strip().split()[1:]) tris.append(tri) return points, tris def ReadOFFTets(fileName): """docstring for ReadOFFTet""" points, tris = ReadOFF(fileName) return points, None, tris # read in a .node file (JRS' Pyramid format) def ReadNode(fileName): inFileName = fileName + '.node' # open input .node file infile = open(inFileName) # fetch the number of points firstline = map(int,infile.readline().strip().split()) numPoints = firstline[0] numMarkers = firstline[-1] # read in all the points points = [] for iter in range(0,numPoints): # check whether point numbering starts at 1 (instead of 0) if iter == 0: firstline = infile.readline().strip().split() if firstline[0] == '1': startFromZero = False else: startFromZero = True # now put in the actual first point if numMarkers != 0: points.append(map(float,firstline[1:-numMarkers])) else: points.append(map(float,firstline[1:])) else: if numMarkers != 0: points.append(map(float,infile.readline().strip().split()[1:-numMarkers])) else: points.append(map(float,infile.readline().strip().split()[1:])) #print "in ReadNode startfrom zero is", startFromZero, "len(points) is", len(points) return points, startFromZero # read tets from a .ele file (pyramid format) def ReadEle(fileName, startFromZero=True): inFileName = fileName + '.ele' # open input .ele file infile = open(inFileName) # fetch the number of tets firstline = map(int,infile.readline().strip().split()) numTets = firstline[0] numMarkers = firstline[-1] #print "in readele num markers is", numMarkers # read in all the tets tets = [] for iter in range(0,numTets): # skip the tet number line = map(int,infile.readline().strip().split()) if numMarkers == 0: tets.append(line[1:]) else: tets.append(line[1:-numMarkers]) # if vert indices started at one, decrement all the indices if startFromZero == False: for index, tet in enumerate(tets): tets[index] = vsubscalar(1,tet) #print "len(tets) is", len(tets) #maxpoint = max([max(tet) for tet in tets]) #print "in readele max vertex index is", maxpoint return tets def ReadTPoly(fileName): """read in tpoly output from adaptive skeleton climbing""" infile = open(fileName) meshString = infile.read() infile.close() triString = meshString[2:].split('\n3\n') vertCount = 0 verts = [] norms = [] tris = [] for tri in triString: trisplit = tri.split() verts.append(tuple(map(float,trisplit[0:3]))) norms.append(tuple(map(float,trisplit[3:6]))) verts.append(tuple(map(float,trisplit[6:9]))) norms.append(tuple(map(float,trisplit[9:12]))) verts.append(tuple(map(float,trisplit[12:15]))) norms.append(tuple(map(float,trisplit[15:18]))) tris.append((vertCount, vertCount+1, vertCount+2)) vertCount += 3 #print "verts:", verts #print "norms:", norms #print "tris:", tris return verts, tris #### # Functions to WRITE meshes out to various formats #### def writeMesh(points, tets, boundFaces, outFileName): outFileName += '.mesh' outfile = open(outFileName, 'w') # number of points outfile.write("%d\n" % len(points)) # points for point in points: outfile.write(' ' + ' '.join(map(str,point)) + '\n') # number of tets outfile.write("%d\n" % len(tets)) # tets for tet in tets: # add one because .mesh numbers verts from 1 tet = [x + 1 for x in tet] outfile.write(" 1 " + ' '.join(map(str,tet)) + '\n') # number of boundary faces outfile.write("%d\n" % len(boundFaces)) # boundary faces for face in boundFaces: # add one because .mesh numbers verts from 1 face = [x + 1 for x in face] outfile.write(" 1 " + ' '.join(map(str,face)) + '\n') def writeNode(points, outFileName): if outFileName.find('.node') == -1: outFileName += '.node' outfile = open(outFileName, 'w') # boilerplate first line outfile.write('%s 3 0 0\n' % len(points)) # write out the points for iter in range(0,len(points)): outfile.write(str(iter+1) + ' ' + ' '.join(['%.18g' % x for x in points[iter]]) + '\n') pass outfile.close() def writeEle(tets, outFileName): outFileName += '.ele' outfile = open(outFileName, 'w') # boilerplate first line outfile.write('%s 4 0 \n' % len(tets)) for iter in range(0,len(tets)): tets[iter] = vaddscalar(1,tets[iter]) outfile.write(str(iter+1) + ' ' + ' '.join(map(str,tets[iter])) + '\n') pass outfile.close() def writeNodeEle(points, tets, boundFaces, outFileName): writeNode(points, outFileName) writeEle(tets, outFileName) def writeOBJTets(points, tets, tris, outFileName): """docstring for writOBJTets""" writeOBJ(points, tris, outFileName) pass def writeOBJ(verts, tris, outFileName): """write out an OBJ file from a list of vertices and triangles""" outFileName += '.obj' outfile = open(outFileName, 'w') for vert in verts: #print "vert:", vert outfile.write('v %.18g %.18g %.18g\n' % (vert[0], vert[1], vert[2])) for tri in tris: outfile.write('f %d %d %d\n' % (tri[0]+1, tri[1]+1, tri[2]+1)) outfile.close() def writeSurfTets(points, tets, tris, outFileName): """docstring for writOBJTets""" writeSurf(points, tris, outFileName) pass # surf surface mesh format def writeSurf(verts, tris, outFileName): """write out an surf file from a list of vertices and triangles""" outFileName += '.surf' outfile = open(outFileName, 'w') # write header lines outfile.write('surfacemesh\n') outfile.write('%d\n' % (len(verts))) for vert in verts: #print "vert:", vert outfile.write('%g %g %g\n' % (vert[0], vert[1], vert[2])) outfile.write('%d\n' % (len(tris))) for tri in tris: outfile.write('%d %d %d\n' % (tri[0], tri[1], tri[2])) outfile.close() def writeOFFTets(points, tets, tris, outFileName): """docstring for writOBJTets""" writeOFF(points, tris, outFileName) pass # OFF surface mesh format def writeOFF(verts, tris, outFileName): """write out an OFF file from a list of vertices and triangles""" outFileName += '.off' outfile = open(outFileName, 'w') # write header lines outfile.write('OFF\n') outfile.write('%d %d 0\n' % (len(verts), len(tris))) for vert in verts: #print "vert:", vert outfile.write('%g %g %g\n' % (vert[0], vert[1], vert[2])) for tri in tris: outfile.write('3 %d %d %d\n' % (tri[0], tri[1], tri[2])) outfile.close() ## END file I/O functions ## Convenience math functions # some simple geometry functions def vadd(v1, v2): v3 = [] # assumes vectors are of equal length for i in range(0,len(v1)): v3.append(v1[i] + v2[i]) return v3 def vsub(v1, v2): v3 = [] # assumes vectors are of equal length for i in range(0,len(v1)): v3.append(v1[i] - v2[i]) return v3 def vlength(v): length = 0 for ele in v: length += ele * ele return math.sqrt(length) def vscale(scale, v): return [x * scale for x in v] def vnorm(v): length = vlength(v) vscale(1/length,v) return v def vaddscalar(scalar, v): return [x + scalar for x in v] def vsubscalar(scalar, v): return [x - scalar for x in v] def orient3d(a,b,c,d): """Compute the orientation of 4 points in 3D""" m11 = a[0] - d[0] m12 = a[1] - d[1] m13 = a[2] - d[2] m21 = b[0] - d[0] m22 = b[1] - d[1] m23 = b[2] - d[2] m31 = c[0] - d[0] m32 = c[1] - d[1] m33 = c[2] - d[2] det = (m11 * m22 * m33) + (m12 * m23 * m31) + (m13 * m21 * m32) - (m11 * m23 * m32) - (m12 * m21 * m33) - (m13 * m22 * m31) return det # return all the unique items in a list def unique(s): """Return a list of the elements in s, but without duplicates. For example, unique([1,2,3,1,2,3]) is some permutation of [1,2,3], unique("abcabc") some permutation of ["a", "b", "c"], and unique(([1, 2], [2, 3], [1, 2])) some permutation of [[2, 3], [1, 2]]. For best speed, all sequence elements should be hashable. Then unique() will usually work in linear time. If not possible, the sequence elements should enjoy a total ordering, and if list(s).sort() doesn't raise TypeError it's assumed that they do enjoy a total ordering. Then unique() will usually work in O(N*log2(N)) time. If that's not possible either, the sequence elements must support equality-testing. Then unique() will usually work in quadratic time. """ n = len(s) if n == 0: return [] # Try using a dict first, as that's the fastest and will usually # work. If it doesn't work, it will usually fail quickly, so it # usually doesn't cost much to *try* it. It requires that all the # sequence elements be hashable, and support equality comparison. u = {} try: for x in s: u[x] = 1 except TypeError: del u # move on to the next method else: return u.keys() # We can't hash all the elements. Second fastest is to sort, # which brings the equal elements together; then duplicates are # easy to weed out in a single pass. # NOTE: Python's list.sort() was designed to be efficient in the # presence of many duplicate elements. This isn't true of all # sort functions in all languages or libraries, so this approach # is more effective in Python than it may be elsewhere. try: t = list(s) t.sort() except TypeError: del t # move on to the next method else: assert n > 0 last = t[0] lasti = i = 1 while i < n: if t[i] != last: t[lasti] = last = t[i] lasti += 1 i += 1 return t[:lasti] # Brute force is all that's left. u = [] for x in s: if x not in u: u.append(x) return u if __name__ == "__main__": sys.exit(main())vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/CMakeLists.txt0000664000175000017500000000102611757446472021313 0ustar lucalucaCMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT (STELLAR) SET (STARBASE_SRCS src/Starbase.c ) SET (STELLAR_SRCS src/Stellar.c ) INCLUDE_DIRECTORIES(${STELLAR_SOURCE_DIR}/src) #ADD_DEFINITIONS(-DSTARLIBRARY) ADD_DEFINITIONS(-DNOMAIN) ADD_LIBRARY(starbase STATIC ${STARBASE_SRCS}) ADD_EXECUTABLE(Stellar ${STELLAR_SRCS}) TARGET_LINK_LIBRARIES(Stellar starbase m) IF(NOT WIN32) SET_TARGET_PROPERTIES(starbase PROPERTIES COMPILE_FLAGS -fPIC) SET_TARGET_PROPERTIES(Stellar PROPERTIES COMPILE_FLAGS -fPIC) ENDIF(NOT WIN32) vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/EXAMPLE_CONFIG0000664000175000017500000001352711757446472020627 0ustar lucaluca#################################### # Stellar mesh improvement options # #################################### # This file contains all the possible options that can currently be set for # mesh improvement. Lines that begin with '#' are comments and are ignored. # Other lines take the form 'option intval floatval stringval', where option # is the name of the option, and intval floatval and stringval are the possible # fields that can be used to set that option. If an option takes an int, only # a value for int needs to be given. If it's a float, a dummy int should be # inserted before the float. If it's a string, a dummy int and a dummy float # should be inserted before the string. This clumsiness is because I don't like # coding string processing in C, and this is the easiest way. Any unset options # will assume their default values. # verbosity: bigger number means more verbose output of improvement. # default = 1 verbosity 0 # use color in verbose improvement output. default = 0 usecolor 1 # just output the mesh unchanged and quit. default = 0 outputandquit 0 ## quality measure options # qualmeasure: selects which quality measure to use as an objective function # for optimizing the tetrahedra. The quality measures are described in # Chapter 2 of Bryan's dissertation. default = 0 # 0 = minimum sine of the dihedral angles (default) # 1 = square root of radius ratio (circumradius divided by inradius) # 2 = V / l_rms^3 (volume divided by cube of root-mean-squared edge length) # 5 = minimum sine with biased obtuse angles qualmeasure 5 # sinewarpfactor: float. for qualmeasure 5 only; sets the factor by which # obtuse angles are scaled relative to acute angles. Default is 0.75 sinewarpfactor 0 0.75 ## termination options # BOTH goal angles must be reached to terminate improvement # goalanglemin: float. terminates improvement early if minimum angle reaches # this value. default = 90.0 (which precludes early termination) goalanglemin 0 90.0 # goalanglemax: float. terminates improvement early if maximum angle reaches # this value. default = 90.0 goalanglemax 0 90.0 ## smoothing options # nonsmooth: enable optimization-based smoothing. default = 1 nonsmooth 1 # facetsmooth: enable smoothing of facet vertices. default = 1 facetsmooth 1 # segmentsmooth: enable smoothing of segment vertices. default = 1 segmentsmooth 1 # usequadrics: enable use of surface quadric error for smoothing fixed boundary # vertices. WARNING: this will allow the domain shape to change slightly. But # even a little play sometimes yields much better meshes. default = 0 usequadrics 0 # quadricoffset: amount to start quadric error at before subtracting. # See alpha in Section 3.2.5 of Bryan's dissertation. default = 0.8 quadricoffset 0 0.8 # quadricscale: amount to scale quadric error before subtracting from offset. # See beta in Section 3.2.5 of Bryan's dissertation. default = 300.0 quadricscale 0 300.0 ## topological transformation options # flip22: enable 2-2 flips (for boundary tets). default = 1 flip22 1 # multifaceremoval: enable multi-face removal. singlefaceremoval might still # be on. default = 1 multifaceremoval 1 # singlefaceremoval: enable single face removal (2-3 and 2-2 flips). Has # no effect when multifaceremoval is enabled. default = 1 singlefaceremoval 1 # edgeremoval: enable edge removal. default = 1 edgeremoval 1 ## edge contraction options # edgecontraction: enable edge contraction. default = 1 edgecontraction 1 ## vertex insertion options # enableinsert: enable ALL vertex insertion (overrides others). default = 1 enableinsert 1 # insertbody: enable just vertex insertion in body (interior). default = 1 insertbody 1 # insertfacet: enable just insertion on facets. default = 1 insertfacet 1 # insertsegment: enable just insertion on segments. default = 1 insertsegment 1 # insertthreshold: on each insertion pass, try vertex insertion in this fraction of the tetrahedra. default = 0.031 (the worst 3.1%) insertthreshold 0 0.031 ## size control options # (See Chapter 6 of Bryan's dissertation.) # sizing: enable control of element sizes. default = 0 sizing 0 # sizingpass: enable edge length correction before quality improvement. # default = 0 sizingpass 0 # targetedgelength: the target edge length for this mesh. If set to 0.0, the # target edge length is initialized automatically to the initial mean edge # length. default = 0.0 targetedgelength 0 0.0 # longerfactor: factor by which an edge can be longer than the target edge # length before being considered "too long". default = 3.0 longerfactor 0 2.0 # shorterfactor: factor by which an edge can be shorter than the target edge # length before being considered "too short" default = 0.33 shorterfactor 0 0.50 ## anisotropy options # (See Chapter 7 of Bryan's dissertation.) # anisotropic: enable anisotropic meshing. default = 0 anisotropic 0 # tensor: which size/anisotropy tensor to use. default = 0 # 0 = identity # 1 = stretch x # 2 = stretch y # 3 = sink # 4 = swirl # 5 = center # 6 = perimeter # 7 = right # 8 = sine tensor 6 ## quality file output options # These files list, for each tetrahedron, the values of the quality measures # minsineout: enable output of .minsine quality file. default = 1 minsineout 1 # minangout: enable output of .minang quality file. default = 0 minangout 0 # maxangout: enable output of .maxang quality file. default = 0 maxangout 0 # vlrmsout: enable output of .vlrms quality file. default = 0 vlrmsout 0 # nrrout: enable output of the .nrr quality file. default = 0 nrrout 0 ## animation options # animate: activate animation file output (a set of output files after each # pass). default = 0 animate 0 # timeseries: when animate = 1, only output .stats. default = 0 timeseries 0 ## output filename option # fileprefix: filename prefix that distinguishes the output files from the # input files. If none specified, an iteration number is appended to the input # filenames. #fileprefix 0 5 ../output/testprefix vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/0000775000175000017500000000000011757446472017343 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/top.c0000664000175000017500000013546211757446472020324 0ustar lucaluca/*****************************************************************************/ /* */ /* ,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 Bryan Klingner, 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 Bryan Klingner 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," Bryan M. Klingner, Jonathan R. */ /* Shewchuk, Proceedings of the 16th International Meshing Roundtable */ /* and the (more complete) dissertation: */ /* "Tetrahedral Mesh Improvement," Bryan Klingner, */ /* 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 #include /*****************************************************************************/ /* */ /* 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 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]); } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/quality.c0000664000175000017500000026552011757446472021211 0ustar lucaluca/*****************************************************************************/ /* */ /* 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; icoord, 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 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 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; } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/Starbase.c0000664000175000017500000267164711757446472021302 0ustar lucaluca/*****************************************************************************/ /* */ /* ,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 */ /* Jonathan Richard Shewchuk */ /* 965 Sutter Street #815 */ /* San Francisco, California 94109-6082 */ /* jrs@cs.berkeley.edu */ /* */ /* 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 Jonathan Shewchuk 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 Daniel K. Blandford, Guy E. Blelloch, David E. */ /* Cardoze, and Clemens Kadow, "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 Jonathan Richard Shewchuk, "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 Jonathan Richard Shewchuk, "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 */ /* Douglas M. Priest, "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 Steven Fortune */ /* and Christopher J. Van Wyk, "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 #include #include #include #include #include #ifdef STARTIMER #include #endif /* not STARTIMER */ #ifdef CPU86 #include #endif /* CPU86 */ #ifdef LINUX #include #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 jrs@cs.berkeley.edu\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 Jonathan Richard Shewchuk\n"); printf("2360 Woolsey #H / Berkeley, California 94705-1927\n"); printf("Bugs/comments to jrs@cs.berkeley.edu\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 Bryan Klingner\n"); printf("Bugs/comments to stellar.b@overt.org\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 *********/ vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/showme.c0000664000175000017500000077216711757446472021035 0ustar lucaluca/*****************************************************************************/ /* */ /* ,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 */ /* Jonathan Richard Shewchuk */ /* 965 Sutter Street #815 */ /* San Francisco, California 94109-6082 */ /* jrs@cs.berkeley.edu */ /* */ /* 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 Jonathan Shewchuk 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 #include #include #include #include #include #include #ifdef CPU86 #include #endif /* CPU86 */ #ifdef LINUX #include #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 Jonathan Richard Shewchuk\n"); printf("965 Sutter Street #815 / San Francisco, California 94109-6082\n"); printf("Bugs/comments to jrs@cs.berkeley.edu\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> <# of attributes>\n"); printf( " <# of boundary markers (0 or 1)>\n" ); printf( " Remaining lines: [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> <# of attributes>\n"); printf( " <# of boundary markers (0 or 1)>\n" ); printf( " Following lines: [attributes] [boundary marker]\n"); printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); printf( " Following lines: [boundary marker]\n"); printf(" One line: <# of holes>\n"); printf(" Following lines: \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> <# of attributes>\n"); printf( " Remaining lines: ... [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: [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(" -1 \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: \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: \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 jrs@cs.berkeley.edu) 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 = ¢er[i * 2]; point2 = ¢er[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 = ¢er[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 = ¢er[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 = ¢er[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 = ¢er[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 = ¢er[i * 2]; point2 = ¢er[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 = ¢er[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 = ¢er[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 = ¢er[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 = ¢er[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, ¢roid); */ 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); } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/arraypoolstack.c0000664000175000017500000007534111757446472022557 0ustar lucaluca/*****************************************************************************/ /* */ /* 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; iquality = 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 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; iverts[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; jtop; 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 5) { printf("non-existent tets: %d / %lu\n", nonexist, tetstack->top+1); } *minqual = worstqual; /* compute thresholded means */ for (i=0; itop; 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"); } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/smoothing.c0000664000175000017500000026231211757446472021524 0ustar lucaluca/*****************************************************************************/ /* */ /* 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 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 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 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 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 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 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; ivec); /* 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; ikind, 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 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 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 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; ikind != 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; ikind, 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 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; iverts[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; } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/output.c0000664000175000017500000004656111757446472021063 0ustar lucaluca/*****************************************************************************/ /* */ /* 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; inumber, (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); } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/topological.c0000664000175000017500000036147511757446472022043 0ustar lucaluca/*****************************************************************************/ /* */ /* 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 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 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= 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 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; icoord; 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 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 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 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 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; icoord; 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 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 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 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 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= 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); } } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/quadric.c0000664000175000017500000005017411757446472021146 0ustar lucaluca/* 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; icoord, 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; icoord 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); } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/improve.c0000664000175000017500000005557311757446472021207 0ustar lucaluca/*****************************************************************************/ /* */ /* 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 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 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 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 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); } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/print.c0000664000175000017500000003654511757446472020660 0ustar lucaluca/*****************************************************************************/ /* */ /* 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; iverts[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; itype) { 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; inumverts; 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; iverts[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; itop != 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; itop - 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; jnumverts; 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 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; jnumverts; 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); } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/Starbase.h0000664000175000017500000007453311757446472021274 0ustar lucaluca/* This file was automatically generated. Do not edit! */ #include #include #include #include #include #include #if !defined(NO_TIMER) #include #endif #if defined(CPU86) #include #endif #if defined(LINUX) #include #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 vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/vector.c0000664000175000017500000000517511757446472021021 0ustar lucaluca/*****************************************************************************/ /* */ /* 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); }vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/insertion.c0000664000175000017500000034276311757446472021540 0ustar lucaluca/*****************************************************************************/ /* */ /* 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; iverts[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; inumoutfaces; 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; inumoutfaces; for (i=0; ioutfaces[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 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= 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 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 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 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; iqual > ((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 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 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 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 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= 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 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 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 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 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; iquality = 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 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 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 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); } } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/classify.c0000664000175000017500000005064011757446472021331 0ustar lucaluca/*****************************************************************************/ /* */ /* 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 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; jcoord; 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 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; jcoord; 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]); } } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/main.c0000664000175000017500000000421411757446472020434 0ustar lucaluca/*****************************************************************************/ /* */ /* 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; } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/interact.c0000664000175000017500000003174111757446472021326 0ustar lucaluca/*****************************************************************************/ /* 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 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]); } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/Stellar.c0000664000175000017500000000064011757446472021115 0ustar lucaluca/* 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" vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/src/size.c0000664000175000017500000007375111757446472020476 0ustar lucaluca/* 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 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); } vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/house2.ele0000664000175000017500000012417311757446472020460 0ustar lucaluca1389 4 0 1 1 75 175 52 2 1 75 52 360 3 1 11 46 174 4 1 11 174 57 5 1 11 57 175 6 1 11 175 75 7 1 11 75 130 8 1 11 130 129 9 1 11 129 46 10 2 8 398 47 11 2 8 47 54 12 2 8 54 158 13 2 8 158 164 14 2 8 164 168 15 2 8 168 36 16 2 36 163 363 17 2 36 363 31 18 2 36 168 163 19 2 152 71 158 20 3 233 361 239 21 3 233 239 243 22 3 233 243 240 23 3 233 240 234 24 3 233 234 361 25 3 29 241 198 26 3 29 198 33 27 3 29 33 76 28 3 29 76 241 29 3 33 197 49 30 3 33 49 361 31 3 33 361 76 32 3 33 198 197 33 3 49 197 196 34 3 49 196 239 35 3 49 239 361 36 3 197 243 196 37 3 5 240 243 38 3 5 243 197 39 3 5 197 198 40 3 5 198 241 41 3 5 241 240 42 4 42 109 54 43 4 42 54 152 44 4 42 152 44 45 4 42 44 67 46 4 42 67 399 47 4 42 399 109 48 4 54 153 158 49 4 54 158 152 50 4 54 109 399 51 4 10 396 153 52 4 10 153 16 53 4 10 16 399 54 4 10 399 396 55 5 243 377 240 56 5 51 248 18 57 5 51 18 63 58 5 51 63 241 59 5 51 241 240 60 5 51 240 248 61 5 63 18 198 62 5 63 198 241 63 5 227 208 248 64 5 227 248 377 65 5 227 377 243 66 6 8 36 394 67 6 8 394 398 68 6 36 31 358 69 6 36 358 367 70 6 36 367 89 71 6 36 89 394 72 6 2 398 47 73 6 2 47 58 74 6 2 58 26 75 6 2 26 36 76 6 2 36 8 77 6 2 8 398 78 7 145 126 400 79 7 145 400 171 80 7 145 171 122 81 8 54 153 364 82 8 54 398 47 83 8 54 158 153 84 8 158 164 364 85 8 158 364 153 86 8 394 398 53 87 8 62 394 53 88 8 62 53 364 89 8 62 364 392 90 8 62 392 394 91 9 67 396 44 92 9 67 44 378 93 9 359 378 180 94 10 16 399 110 95 10 16 110 111 96 10 16 111 56 97 10 16 56 395 98 10 16 395 154 99 10 16 154 153 100 10 56 191 395 101 11 57 175 174 102 11 129 50 367 103 11 129 367 92 104 11 129 92 130 105 11 25 146 130 106 11 25 130 92 107 11 89 92 367 108 11 89 367 50 109 11 41 394 89 110 11 41 89 36 111 11 41 36 50 112 11 41 50 174 113 11 41 174 175 114 12 366 377 227 115 12 18 209 205 116 12 18 205 248 117 12 18 248 397 118 12 18 397 209 119 13 255 68 385 120 13 255 385 259 121 13 259 385 70 122 13 259 70 265 123 13 259 265 228 124 14 24 215 362 125 14 24 362 373 126 14 24 373 214 127 14 24 214 215 128 15 369 394 62 129 15 89 394 369 130 15 89 369 92 131 15 11 146 175 132 15 11 175 41 133 15 11 41 394 134 15 11 394 89 135 15 11 89 92 136 15 11 92 25 137 15 11 25 146 138 15 41 175 392 139 15 41 392 394 140 15 25 92 369 141 15 25 369 123 142 15 25 123 146 143 15 121 62 392 144 15 121 392 144 145 15 121 144 123 146 15 121 123 369 147 16 4 399 54 148 16 4 54 153 149 16 110 111 73 150 16 154 155 395 151 16 154 153 364 152 16 154 364 155 153 16 54 110 73 154 16 54 73 371 155 16 54 364 153 156 16 54 399 110 157 18 248 397 51 158 18 200 63 245 159 18 200 245 222 160 18 200 222 199 161 20 194 224 384 162 20 194 384 181 163 21 259 228 275 164 21 259 275 269 165 21 255 259 269 166 21 255 269 30 167 21 255 30 388 168 21 219 269 229 169 21 219 229 192 170 21 219 192 382 171 21 219 382 218 172 21 219 218 388 173 21 13 228 259 174 21 13 259 255 175 21 13 255 388 176 21 13 388 217 177 21 13 217 218 178 21 13 218 382 179 21 13 382 228 180 22 280 279 302 181 22 280 302 306 182 22 280 306 267 183 23 317 312 343 184 23 317 343 348 185 23 317 348 379 186 23 317 379 316 187 24 362 373 374 188 24 362 374 189 189 24 214 215 173 190 24 374 373 400 191 24 46 173 189 192 24 46 189 374 193 24 46 374 173 194 25 123 146 131 195 25 131 146 130 196 25 91 123 131 197 25 91 131 97 198 25 91 97 92 199 25 91 92 369 200 25 91 369 123 201 26 2 363 31 202 26 2 31 36 203 26 2 58 71 204 26 2 71 163 205 26 2 163 363 206 26 6 36 31 207 26 6 31 358 208 26 6 358 370 209 26 6 370 58 210 26 88 370 383 211 26 88 383 393 212 27 181 56 395 213 27 181 395 156 214 27 149 56 181 215 27 141 149 181 216 27 141 181 156 217 27 141 156 386 218 27 141 386 64 219 28 230 268 213 220 28 214 223 254 221 28 214 254 230 222 28 214 230 213 223 29 191 396 76 224 29 191 76 381 225 29 191 381 384 226 29 191 384 395 227 29 191 395 184 228 29 199 184 395 229 29 199 395 384 230 29 63 199 384 231 29 63 384 381 232 29 63 381 241 233 29 63 241 198 234 29 63 198 199 235 29 183 184 198 236 30 368 65 388 237 30 368 388 251 238 30 316 289 317 239 30 72 317 312 240 30 72 312 390 241 30 72 390 284 242 30 72 284 251 243 30 72 251 311 244 30 72 311 316 245 30 72 316 317 246 30 312 249 390 247 30 312 317 65 248 30 284 390 251 249 31 173 36 363 250 31 173 363 172 251 31 7 48 172 252 31 7 172 393 253 31 7 393 383 254 31 7 383 358 255 31 7 358 376 256 31 7 376 48 257 32 16 54 364 258 32 16 364 64 259 32 16 64 35 260 32 16 35 73 261 32 16 73 371 262 32 16 371 54 263 32 54 371 398 264 32 8 398 364 265 32 8 364 54 266 32 8 54 398 267 33 29 198 183 268 33 29 183 396 269 33 29 396 76 270 33 183 4 396 271 33 183 198 197 272 33 183 197 182 273 33 9 361 396 274 33 9 396 44 275 33 9 44 182 276 33 9 182 49 277 33 9 49 361 278 34 26 86 55 279 34 26 55 59 280 34 26 59 71 281 34 26 71 161 282 34 26 161 393 283 34 26 393 88 284 34 26 88 86 285 34 88 393 120 286 34 88 120 118 287 34 120 393 143 288 35 73 16 111 289 35 73 111 80 290 35 81 80 111 291 35 81 111 112 292 35 81 112 84 293 36 8 164 41 294 36 8 41 394 295 36 8 168 164 296 36 50 173 31 297 36 50 31 358 298 36 50 358 367 299 36 50 367 89 300 36 50 89 11 301 36 50 41 174 302 36 50 174 168 303 36 50 168 173 304 37 215 385 216 305 37 215 216 362 306 37 215 362 14 307 37 263 264 260 308 39 19 66 246 309 39 19 246 250 310 39 19 250 253 311 39 19 253 252 312 39 19 252 66 313 39 253 285 40 314 39 253 250 285 315 39 285 310 313 316 39 285 313 40 317 39 285 250 310 318 39 309 252 314 319 39 309 314 344 320 39 309 344 313 321 39 309 313 310 322 39 309 310 298 323 39 313 344 40 324 40 28 252 253 325 40 28 253 254 326 40 28 254 230 327 40 28 230 268 328 40 28 268 252 329 40 254 285 315 330 40 254 315 318 331 40 254 318 293 332 40 254 293 292 333 40 254 253 285 334 40 230 292 268 335 40 230 254 292 336 40 314 318 315 337 40 314 315 313 338 40 314 313 344 339 40 314 344 39 340 41 175 392 164 341 42 44 108 140 342 42 44 140 151 343 42 44 151 152 344 42 44 67 108 345 42 140 59 151 346 42 108 59 140 347 42 108 67 109 348 42 108 109 43 349 42 2 54 71 350 42 2 71 58 351 42 2 58 54 352 42 60 59 108 353 42 60 108 43 354 43 109 54 371 355 43 73 79 109 356 43 73 109 371 357 44 4 396 33 358 44 4 33 152 359 44 4 67 396 360 45 255 258 68 361 45 251 255 68 362 45 251 68 397 363 46 48 50 128 364 46 48 128 374 365 46 48 374 173 366 46 48 173 50 367 47 43 55 59 368 47 43 59 42 369 47 43 42 54 370 47 43 54 371 371 48 50 128 367 372 48 50 367 358 373 48 50 358 31 374 48 50 31 173 375 48 374 400 127 376 48 358 376 31 377 48 24 173 172 378 48 24 172 374 379 48 24 374 173 380 49 33 197 196 381 49 33 196 182 382 49 239 361 232 383 49 9 180 359 384 49 9 359 361 385 49 9 182 180 386 49 195 196 226 387 49 195 226 180 388 49 195 180 196 389 50 168 173 174 390 50 128 367 129 391 50 46 174 173 392 50 46 128 129 393 50 46 129 11 394 50 46 11 174 395 51 245 247 18 396 52 218 217 382 397 52 186 175 217 398 52 186 217 218 399 52 186 218 382 400 53 87 62 369 401 54 2 152 71 402 54 2 58 47 403 54 2 158 152 404 54 42 47 58 405 54 42 71 152 406 54 42 109 43 407 55 43 60 59 408 55 47 59 58 409 55 47 58 370 410 56 16 111 27 411 56 16 27 155 412 56 16 155 395 413 56 20 191 395 414 56 20 395 181 415 56 20 181 149 416 57 1 360 189 417 57 1 189 46 418 57 1 46 174 419 57 1 175 52 420 57 1 52 360 421 57 175 217 52 422 57 175 174 216 423 57 175 216 217 424 57 37 189 70 425 57 37 70 385 426 57 37 385 189 427 57 13 217 385 428 57 13 385 70 429 57 13 70 360 430 57 13 360 52 431 57 13 52 217 432 58 6 370 47 433 58 26 55 370 434 58 26 71 59 435 58 26 59 55 436 58 42 47 59 437 58 42 59 71 438 59 55 86 115 439 59 55 115 83 440 59 55 83 60 441 59 55 34 86 442 59 43 60 42 443 59 69 34 71 444 59 69 71 151 445 59 69 151 140 446 59 69 140 115 447 59 69 115 86 448 59 69 86 34 449 60 78 77 108 450 60 78 108 43 451 60 82 83 107 452 60 82 107 77 453 61 37 256 14 454 61 37 14 215 455 61 37 215 385 456 61 37 385 256 457 61 215 14 223 458 61 215 223 12 459 61 215 12 391 460 61 215 391 216 461 61 215 216 385 462 61 223 14 254 463 61 223 254 366 464 61 223 366 12 465 61 45 12 366 466 61 45 366 256 467 61 45 256 257 468 61 45 257 258 469 61 45 258 385 470 61 45 385 68 471 61 45 68 12 472 62 364 365 53 473 62 364 392 386 474 62 392 394 15 475 62 160 386 392 476 62 160 392 119 477 62 64 364 386 478 62 64 386 365 479 62 64 365 364 480 62 144 119 392 481 62 144 392 121 482 63 51 18 245 483 63 51 245 242 484 63 51 242 241 485 63 241 242 236 486 63 245 200 384 487 63 245 384 242 488 63 381 242 384 489 63 237 242 381 490 63 237 381 236 491 63 237 236 242 492 64 16 364 155 493 64 16 155 27 494 64 16 27 111 495 64 16 111 35 496 64 32 35 365 497 64 32 365 364 498 64 114 27 116 499 65 21 219 269 500 65 21 269 30 501 65 21 30 388 502 65 21 388 219 503 65 219 388 210 504 66 252 39 309 505 66 38 303 389 506 66 38 389 387 507 66 38 387 226 508 66 38 226 195 509 67 109 399 42 510 68 258 385 255 511 68 258 45 385 512 68 12 45 397 513 68 12 397 209 514 68 12 209 391 515 68 12 391 61 516 68 222 209 397 517 68 222 397 251 518 68 222 251 388 519 68 222 388 211 520 69 71 161 34 521 69 71 151 161 522 69 151 150 161 523 69 115 86 118 524 69 115 118 150 525 69 115 150 140 526 70 264 385 37 527 70 260 385 264 528 70 260 264 265 529 70 260 265 259 530 70 228 360 13 531 70 228 13 265 532 71 59 151 42 533 71 161 26 163 534 73 79 110 80 535 73 79 109 110 536 74 256 262 263 537 74 256 263 37 538 74 14 256 37 539 74 14 37 362 540 74 14 362 373 541 74 14 373 17 542 74 14 17 262 543 74 14 262 256 544 75 11 175 146 545 75 11 146 130 546 76 234 361 3 547 76 234 3 235 548 77 107 108 100 549 77 107 60 108 550 77 99 98 107 551 77 99 107 100 552 78 108 43 109 553 78 108 109 101 554 78 100 77 108 555 78 100 108 101 556 79 109 110 102 557 79 43 109 78 558 79 101 78 109 559 79 101 109 102 560 80 110 73 111 561 80 110 111 103 562 80 102 79 110 563 80 102 110 103 564 81 111 112 104 565 81 103 80 111 566 81 103 111 104 567 83 55 115 86 568 83 59 140 115 569 83 59 60 140 570 84 64 116 114 571 84 64 114 112 572 84 64 112 35 573 84 64 35 365 574 84 64 365 116 575 85 87 119 62 576 85 53 87 62 577 85 53 62 365 578 86 26 88 370 579 86 26 370 55 580 86 34 69 118 581 86 34 118 88 582 87 121 369 123 583 87 15 369 121 584 87 15 121 62 585 87 15 62 369 586 88 90 383 122 587 89 41 394 36 588 89 53 398 394 589 89 53 394 369 590 90 124 125 126 591 90 124 126 7 592 90 376 383 7 593 91 87 369 123 594 93 127 376 126 595 93 127 126 134 596 93 127 134 94 597 93 127 94 376 598 94 128 376 127 599 94 128 127 134 600 94 128 134 135 601 94 128 135 95 602 94 128 95 367 603 94 128 367 376 604 95 129 128 135 605 95 129 135 136 606 95 129 136 96 607 95 129 96 367 608 95 129 367 128 609 96 130 129 136 610 96 130 136 137 611 96 130 137 97 612 96 92 367 129 613 96 92 129 130 614 96 92 130 97 615 97 131 130 138 616 97 25 92 130 617 97 25 130 131 618 105 81 113 104 619 106 98 107 77 620 106 82 77 107 621 106 82 107 83 622 106 140 107 378 623 106 140 378 148 624 106 140 148 150 625 106 140 150 115 626 107 83 140 106 627 107 83 60 140 628 108 44 67 378 629 108 44 378 140 630 108 60 59 140 631 108 60 140 107 632 109 73 54 371 633 109 73 110 54 634 110 54 399 109 635 111 35 112 64 636 111 27 64 112 637 111 27 112 56 638 112 84 113 114 639 112 84 81 113 640 112 104 113 81 641 112 64 114 27 642 112 114 113 141 643 112 114 141 27 644 112 56 27 139 645 113 139 112 141 646 114 116 141 27 647 115 83 106 140 648 116 64 141 27 649 116 64 365 85 650 116 64 85 117 651 116 64 117 386 652 116 64 386 141 653 116 84 85 365 654 116 142 157 386 655 116 142 386 117 656 117 85 119 62 657 117 85 62 386 658 117 85 386 64 659 117 119 142 386 660 117 119 386 62 661 118 34 69 162 662 118 34 162 143 663 118 34 143 120 664 119 87 121 62 665 119 121 144 62 666 120 88 393 383 667 120 88 383 122 668 120 122 383 393 669 120 122 393 143 670 122 90 7 124 671 122 90 383 7 672 122 124 7 145 673 123 15 146 144 674 124 126 7 145 675 124 126 145 125 676 125 93 90 126 677 125 93 126 132 678 126 90 7 376 679 126 90 376 93 680 126 132 93 133 681 127 7 376 126 682 127 7 126 400 683 127 7 400 48 684 127 7 48 376 685 128 48 367 358 686 128 48 358 376 687 128 48 376 127 688 128 48 127 374 689 128 358 367 376 690 131 123 146 177 691 131 177 146 179 692 131 75 179 146 693 131 75 146 130 694 133 93 126 134 695 137 97 130 138 696 139 27 141 149 697 139 27 149 56 698 139 27 112 141 699 140 44 378 151 700 140 108 107 378 701 140 150 69 151 702 140 150 151 180 703 142 160 119 165 704 142 160 165 159 705 142 160 159 386 706 142 62 386 119 707 142 62 119 160 708 142 62 160 386 709 142 156 386 159 710 142 156 159 157 711 142 156 157 386 712 144 146 176 15 713 144 146 123 177 714 144 146 177 176 715 144 166 392 15 716 144 166 15 176 717 144 166 176 169 718 144 166 169 165 719 145 171 170 188 720 145 171 188 400 721 145 125 126 147 722 145 147 126 400 723 145 147 400 178 724 146 176 75 179 725 146 176 179 177 726 148 140 180 150 727 148 140 378 180 728 148 150 180 193 729 149 141 157 181 730 150 118 69 162 731 150 180 195 196 732 150 180 196 151 733 150 180 193 195 734 151 71 42 152 735 151 71 152 163 736 151 71 163 161 737 152 158 163 71 738 152 4 153 158 739 152 4 33 183 740 152 4 183 153 741 152 44 151 182 742 152 44 182 33 743 152 182 183 33 744 153 183 396 4 745 153 191 10 396 746 153 29 191 396 747 153 29 396 183 748 153 29 183 184 749 153 29 184 191 750 154 10 153 191 751 154 10 191 395 752 154 184 155 395 753 154 184 395 191 754 154 184 191 153 755 154 164 153 364 756 154 164 364 155 757 155 27 156 64 758 155 27 56 395 759 155 27 395 156 760 155 181 395 200 761 155 181 200 201 762 155 181 201 156 763 155 181 156 395 764 156 64 27 386 765 156 64 386 155 766 157 141 116 386 767 157 141 386 156 768 157 141 156 181 769 157 149 181 194 770 158 2 164 168 771 158 2 168 163 772 158 2 163 71 773 158 164 364 153 774 160 144 119 165 775 160 144 165 166 776 160 144 166 392 777 160 144 392 119 778 160 156 159 386 779 160 156 386 155 780 161 69 162 150 781 161 69 34 162 782 161 163 363 26 783 161 363 172 393 784 161 363 393 26 785 161 167 162 393 786 161 167 393 171 787 161 171 393 172 788 162 34 161 393 789 162 34 393 167 790 162 34 167 143 791 164 8 364 392 792 164 8 392 41 793 164 36 41 168 794 164 174 41 175 795 164 160 166 392 796 164 160 392 364 797 164 160 364 155 798 164 166 175 392 799 167 143 34 393 800 167 143 393 171 801 167 143 171 170 802 168 164 174 41 803 168 36 173 363 804 168 36 363 163 805 168 36 41 174 806 170 188 213 220 807 170 188 171 213 808 170 122 143 171 809 170 122 171 145 810 171 7 122 393 811 171 7 393 172 812 171 7 172 400 813 171 143 393 122 814 171 213 188 214 815 172 48 374 400 816 172 48 400 7 817 172 48 31 173 818 172 24 173 214 819 172 24 214 188 820 172 24 188 400 821 172 24 400 374 822 174 46 57 189 823 174 46 189 185 824 174 46 185 173 825 175 75 146 176 826 175 75 176 52 827 175 15 392 166 828 175 15 166 176 829 175 15 176 146 830 176 144 169 177 831 176 52 382 186 832 176 52 186 175 833 176 52 75 179 834 176 52 179 382 835 176 186 382 179 836 176 186 179 192 837 176 186 192 177 838 177 179 192 176 839 177 187 186 192 840 178 188 220 373 841 178 188 373 400 842 178 188 400 145 843 178 170 220 188 844 178 170 188 145 845 179 75 190 382 846 179 75 382 52 847 180 182 49 196 848 180 182 196 151 849 180 140 378 151 850 180 148 359 378 851 180 148 193 359 852 180 44 378 9 853 180 44 9 182 854 180 44 182 151 855 180 44 151 378 856 181 149 20 194 857 181 157 194 202 858 181 157 202 201 859 181 157 201 156 860 182 196 197 33 861 184 198 199 29 862 185 173 24 215 863 185 173 46 189 864 185 173 189 24 865 185 215 24 362 866 185 215 362 216 867 185 57 189 174 868 185 57 174 216 869 185 57 216 189 870 186 192 187 219 871 186 192 219 218 872 186 192 218 382 873 188 214 213 230 874 188 214 230 17 875 188 214 17 373 876 188 24 214 373 877 188 24 373 400 878 188 172 400 171 879 188 172 171 214 880 189 57 70 360 881 189 57 216 385 882 189 37 216 362 883 189 37 385 216 884 189 185 24 362 885 189 185 362 216 886 190 360 221 382 887 190 360 382 75 888 190 192 382 221 889 190 186 382 192 890 190 186 192 179 891 190 186 179 382 892 191 381 384 20 893 192 218 382 219 894 193 195 180 226 895 193 195 226 231 896 193 231 226 232 897 193 49 359 361 898 193 49 361 232 899 193 49 232 226 900 193 49 226 180 901 193 49 180 359 902 194 224 384 201 903 196 226 387 244 904 196 226 244 239 905 196 226 239 49 906 196 226 195 387 907 196 206 208 227 908 196 206 227 387 909 196 206 387 195 910 197 5 243 227 911 197 5 227 205 912 197 5 205 198 913 197 227 243 196 914 198 18 205 199 915 198 18 199 63 916 198 18 5 205 917 199 63 18 200 918 199 63 200 384 919 199 205 209 18 920 199 209 200 222 921 199 209 222 18 922 200 222 203 380 923 200 222 380 245 924 200 184 199 395 925 200 184 395 155 926 201 181 200 384 927 201 181 384 194 928 201 181 194 202 929 201 203 202 380 930 201 203 380 200 931 202 194 201 224 932 202 194 224 225 933 202 224 201 380 934 202 224 380 225 935 202 204 249 380 936 202 204 380 203 937 203 209 211 222 938 203 209 222 200 939 204 210 249 368 940 204 210 368 203 941 205 5 227 208 942 205 5 208 248 943 205 5 248 18 944 205 197 208 227 945 206 208 227 223 946 206 208 223 214 947 206 212 214 223 948 206 212 223 19 949 207 19 252 28 950 207 19 28 212 951 207 19 212 206 952 207 19 206 387 953 207 19 387 66 954 207 19 66 252 955 207 195 66 387 956 207 195 387 206 957 207 213 28 252 958 208 196 227 197 959 208 214 215 223 960 208 12 391 205 961 208 12 205 248 962 208 12 248 227 963 208 12 227 366 964 208 12 366 223 965 208 12 223 391 966 209 205 391 12 967 209 211 222 68 968 209 211 68 217 969 210 368 211 388 970 210 368 388 65 971 211 203 222 368 972 211 203 368 210 973 211 217 218 388 974 211 217 388 68 975 212 28 207 213 976 212 28 213 214 977 212 28 214 223 978 212 28 223 19 979 214 14 215 223 980 214 14 223 254 981 214 14 254 230 982 214 14 230 17 983 214 14 17 373 984 216 68 385 217 985 216 68 217 209 986 216 68 209 391 987 216 68 391 61 988 216 68 61 385 989 217 13 255 68 990 217 13 68 385 991 217 13 52 382 992 217 13 382 218 993 217 13 388 255 994 217 21 218 388 995 217 57 385 216 996 217 255 388 68 997 219 211 218 388 998 219 211 388 210 999 220 188 230 17 1000 220 188 17 373 1001 220 188 213 230 1002 220 230 261 17 1003 220 230 213 261 1004 221 21 192 382 1005 221 21 382 229 1006 221 21 229 192 1007 222 18 209 397 1008 222 18 397 247 1009 222 18 247 245 1010 222 368 380 247 1011 222 368 251 388 1012 222 368 388 211 1013 222 368 203 380 1014 223 215 208 391 1015 223 215 391 12 1016 223 19 28 253 1017 223 19 253 250 1018 223 19 250 206 1019 223 253 28 254 1020 223 253 254 366 1021 223 253 366 250 1022 224 20 384 381 1023 224 238 237 242 1024 224 238 242 267 1025 224 238 267 225 1026 224 242 384 380 1027 224 242 380 267 1028 224 242 237 384 1029 225 267 224 380 1030 225 267 380 202 1031 226 38 389 281 1032 226 38 281 231 1033 226 38 231 195 1034 226 38 387 389 1035 226 66 195 387 1036 226 232 231 281 1037 226 232 281 239 1038 226 232 239 49 1039 226 244 389 387 1040 226 244 239 389 1041 227 223 208 366 1042 227 223 366 250 1043 227 223 250 206 1044 228 266 21 275 1045 229 21 382 228 1046 229 21 228 266 1047 229 21 266 269 1048 229 221 228 382 1049 230 268 261 292 1050 230 14 254 262 1051 230 14 262 17 1052 231 281 299 38 1053 231 281 232 299 1054 233 239 232 361 1055 234 240 3 241 1056 234 240 241 283 1057 234 240 283 276 1058 234 276 283 277 1059 235 3 76 241 1060 235 3 241 234 1061 235 241 277 234 1062 235 241 76 381 1063 235 63 236 241 1064 235 63 241 381 1065 235 63 381 236 1066 239 3 243 196 1067 239 281 244 304 1068 239 281 304 300 1069 239 281 300 232 1070 239 281 226 389 1071 239 281 389 244 1072 241 29 76 381 1073 242 238 237 279 1074 242 238 279 267 1075 242 380 245 384 1076 242 22 267 279 1077 242 22 279 278 1078 242 22 278 305 1079 242 22 305 245 1080 242 22 245 267 1081 243 239 196 244 1082 243 227 377 244 1083 243 227 244 196 1084 244 196 227 387 1085 244 246 304 389 1086 244 246 389 387 1087 244 246 387 227 1088 244 246 227 377 1089 245 247 222 380 1090 245 247 380 390 1091 245 247 390 284 1092 245 267 390 380 1093 245 267 380 242 1094 245 267 22 390 1095 246 66 389 387 1096 246 66 387 19 1097 246 66 39 389 1098 246 206 387 227 1099 246 206 227 250 1100 246 206 250 19 1101 246 206 19 387 1102 247 51 18 397 1103 247 249 390 251 1104 247 249 251 368 1105 247 249 368 380 1106 247 249 380 390 1107 248 240 5 377 1108 248 12 397 45 1109 248 12 45 366 1110 248 12 366 377 1111 248 12 377 227 1112 249 251 368 30 1113 249 251 30 390 1114 249 65 312 30 1115 249 65 30 368 1116 249 65 368 210 1117 249 267 202 380 1118 249 267 380 390 1119 249 267 390 308 1120 250 246 377 227 1121 250 246 39 298 1122 250 246 298 310 1123 251 247 284 390 1124 251 247 368 222 1125 251 247 222 397 1126 252 28 19 253 1127 252 28 268 213 1128 252 40 39 314 1129 252 40 314 268 1130 252 40 253 39 1131 254 230 262 292 1132 254 14 61 256 1133 254 14 256 262 1134 254 256 61 366 1135 255 269 30 289 1136 255 251 311 30 1137 255 251 30 388 1138 255 251 388 68 1139 255 289 30 316 1140 256 270 263 271 1141 257 61 385 256 1142 257 61 258 385 1143 257 37 260 263 1144 257 37 263 256 1145 257 37 256 385 1146 257 37 385 260 1147 257 263 260 273 1148 257 263 273 271 1149 257 263 271 256 1150 257 271 273 258 1151 258 70 385 259 1152 258 70 259 260 1153 258 70 260 385 1154 258 260 273 257 1155 258 260 257 385 1156 258 272 271 273 1157 259 255 289 269 1158 259 255 385 258 1159 259 265 228 275 1160 259 265 275 289 1161 259 269 289 275 1162 261 17 230 262 1163 261 213 268 230 1164 261 291 292 268 1165 262 254 292 293 1166 262 230 261 292 1167 263 273 294 274 1168 263 273 274 264 1169 264 260 385 37 1170 264 260 263 273 1171 265 275 289 296 1172 268 40 314 292 1173 269 275 266 297 1174 269 275 297 320 1175 269 275 320 289 1176 269 21 266 275 1177 269 65 30 317 1178 271 263 273 294 1179 271 263 294 270 1180 271 273 272 288 1181 271 273 288 287 1182 271 273 287 294 1183 273 287 290 288 1184 273 287 294 290 1185 275 289 323 319 1186 275 289 319 320 1187 275 289 296 323 1188 275 297 320 324 1189 276 240 283 282 1190 277 241 283 234 1191 278 22 301 305 1192 278 22 279 301 1193 278 242 237 279 1194 279 267 238 280 1195 279 267 280 22 1196 279 301 22 302 1197 281 299 303 375 1198 281 299 375 326 1199 281 299 326 300 1200 281 299 300 232 1201 281 299 38 303 1202 281 303 389 298 1203 281 303 298 304 1204 281 303 304 375 1205 281 303 38 389 1206 284 72 390 311 1207 284 72 311 251 1208 286 270 271 294 1209 287 271 294 286 1210 289 269 30 317 1211 289 269 317 320 1212 289 319 320 316 1213 292 268 291 321 1214 292 268 321 314 1215 292 40 318 293 1216 292 40 314 318 1217 292 314 321 318 1218 292 318 321 322 1219 292 318 322 293 1220 294 274 273 295 1221 294 290 295 273 1222 298 246 389 304 1223 298 246 304 310 1224 298 246 39 389 1225 298 250 310 39 1226 298 304 389 281 1227 298 304 303 375 1228 298 304 375 336 1229 298 304 336 310 1230 298 336 375 303 1231 298 66 39 309 1232 298 66 309 303 1233 298 66 303 389 1234 298 66 389 39 1235 300 326 281 375 1236 300 326 375 327 1237 302 22 306 331 1238 302 22 331 329 1239 302 22 329 301 1240 303 299 325 326 1241 303 299 326 375 1242 303 309 298 336 1243 303 309 336 340 1244 303 325 332 326 1245 304 244 389 281 1246 304 300 281 375 1247 304 300 375 327 1248 304 310 341 336 1249 305 245 390 284 1250 305 245 22 390 1251 305 301 328 331 1252 305 301 331 22 1253 305 331 339 306 1254 305 331 328 334 1255 305 331 334 339 1256 305 307 284 390 1257 305 307 390 308 1258 305 307 308 339 1259 305 307 339 337 1260 306 302 331 329 1261 306 302 329 330 1262 306 22 267 390 1263 306 22 390 305 1264 306 22 305 331 1265 306 308 335 339 1266 306 308 339 305 1267 306 308 305 390 1268 306 308 390 267 1269 308 338 335 339 1270 308 338 339 343 1271 310 298 309 336 1272 310 336 309 344 1273 310 336 344 341 1274 311 255 30 316 1275 311 307 337 339 1276 311 307 339 308 1277 311 307 308 390 1278 311 307 390 284 1279 311 337 342 339 1280 311 23 72 339 1281 311 23 339 342 1282 311 23 342 316 1283 311 23 316 72 1284 312 72 339 311 1285 312 72 311 390 1286 312 72 317 23 1287 312 72 23 339 1288 312 308 249 390 1289 312 308 390 311 1290 312 308 311 339 1291 312 308 339 343 1292 313 309 344 310 1293 313 285 315 40 1294 313 315 346 344 1295 313 315 344 314 1296 314 344 345 372 1297 314 344 372 315 1298 314 352 321 353 1299 314 352 353 345 1300 314 340 345 344 1301 314 340 344 309 1302 316 72 23 317 1303 316 342 347 23 1304 317 289 320 316 1305 318 314 321 372 1306 318 314 372 315 1307 319 275 320 323 1308 320 316 319 379 1309 320 316 379 317 1310 322 318 372 354 1311 322 318 321 353 1312 322 318 353 372 1313 323 319 355 379 1314 323 319 379 356 1315 323 319 356 320 1316 323 275 320 324 1317 324 320 323 356 1318 324 320 356 357 1319 326 332 303 375 1320 327 333 375 304 1321 329 331 306 335 1322 329 301 22 331 1323 329 301 331 328 1324 330 306 335 329 1325 335 331 306 339 1326 336 304 375 333 1327 336 304 333 341 1328 336 332 375 303 1329 336 332 303 340 1330 337 305 334 339 1331 339 23 312 343 1332 340 336 344 309 1333 341 313 346 344 1334 341 313 344 310 1335 344 346 372 315 1336 346 318 349 372 1337 346 318 372 315 1338 347 23 379 316 1339 347 319 316 379 1340 347 319 379 350 1341 348 320 351 379 1342 348 320 379 317 1343 353 321 314 372 1344 353 321 372 318 1345 353 345 372 314 1346 354 318 372 349 1347 354 322 353 372 1348 355 319 350 379 1349 355 323 379 356 1350 356 320 379 351 1351 356 320 351 357 1352 356 320 319 379 1353 358 26 370 383 1354 358 26 383 31 1355 358 376 7 383 1356 360 52 13 382 1357 360 52 382 75 1358 360 228 221 382 1359 360 228 382 13 1360 361 33 396 76 1361 363 31 172 393 1362 363 31 393 26 1363 364 8 398 53 1364 364 32 365 53 1365 364 32 53 398 1366 364 64 155 386 1367 364 160 386 155 1368 364 160 392 386 1369 365 85 64 386 1370 365 85 386 62 1371 366 250 377 227 1372 368 204 203 380 1373 368 204 380 249 1374 369 53 394 62 1375 371 47 398 54 1376 380 200 245 384 1377 380 200 384 201 1378 380 224 201 384 1379 381 237 242 384 1380 381 237 384 224 1381 383 7 393 122 1382 383 31 26 393 1383 384 20 395 191 1384 384 20 181 395 1385 384 200 395 181 1386 384 200 199 395 1387 392 8 394 41 1388 394 6 398 89 1389 396 4 67 399 # Generated by ./Stellar -F ../meshes/in_pyramid/house2 -rNE vmtk-1.0.1/vtkVmtk/Utilities/Stellar_1.0/house2.node0000664000175000017500000003222111757446472020630 0ustar lucaluca400 3 0 1 1 6.5 1 7.5430812757201648 1 2 4.4456243310934527 5.3728065092415962 8.3129834982130344 0 3 4.1326492294372636 8.1243529245273844 4.2828387696230079 0 4 4.75 7.7548808372563904 7.6928224992291403 0 5 4.781066056245912 6.7562132112491824 3.7375735775016352 0 6 4.4565450013305847 4.6106547206734092 10 1 7 2.000015035840534 2.500015035840534 8.5000150358405335 0 8 5.7958905446478166 5.5342496206946503 8.737548599782059 0 9 3.0268193690917435 9 6.4731806309082565 1 10 6.1309541181607372 9 7.4493139376588964 1 11 6.5 2.2757309941520467 8.4678362573099424 0 12 4.8849762291629064 4.5215261479208042 3.7865659323552263 0 13 7.3936328941576361 1.9261249538910927 4.286937523054454 0 14 3.25 2.374638452537873 4 0 15 7.6111111111111107 3.5 8.8888888888888893 0 16 6.4864979147140733 7.7318570626564522 8.8037190284682119 0 17 1.7617623604465709 1 4.2617623604465704 1 18 6.21875 6 4.1749741735537187 0 19 1.3266447368421053 4.846710526315789 3.8266447368421055 0 20 8.0657730273810824 9 5.6792236876194622 1 21 8.6999999999999993 2.5 3.7999999999999998 0 22 8.5 7.8499999999999996 1.3 0 23 8.5 3.7999999999999998 0 1 24 3.25 2.0702007225463728 6.1697523643334673 0 25 8.1230816451810934 2.3884284837323513 9.1221224677716393 0 26 2.6944444444444446 4.75 8.7777777777777786 0 27 8.2617080102256821 8.2103096666908382 8.051398343534844 0 28 1.4858583284799067 3.4717166569598135 3.766034507862551 0 29 5.9484963625725857 8.1941710019600524 5.109455742407798 0 30 8.6183030548484147 3.8549091645452442 2.1183030548484147 0 31 3.25 3.3886840203963304 8.2962086118668079 0 32 6.5637755102040813 7.0637755102040813 10 1 33 3.985948825364535 8.2515166004827964 5.7072882320102076 0 34 1.5526843913269528 5.0385618633815712 8.2650707124938325 0 35 7.6300227462210461 8.1300227462210461 10 1 36 4.75 4 8.5416666666666661 0 37 5 1 4.4583333333333339 1 38 0.5 7.583333333333333 2.416666666666667 1 39 1.3333333333333333 4.833333333333333 2.1666666666666665 0 40 1.3333333333333333 3.1666666666666665 2.1666666666666665 0 41 6.5 3.75 7.8741830065359482 0 42 3.6413195443059663 7.7220948195939414 8.4300752943295674 0 43 4 8.0412698412698411 10 1 44 3.25 8.0060677245873961 7.2462159441233238 0 45 5.5477011494252881 3.7925287356321835 3 1 46 4.9490134807639699 1 7.5501644198726714 1 47 4.2142857142857135 6.2857142857142856 10 1 48 3.3834869661416507 1.9782159586127712 8.1719375382374615 0 49 2.2387411149612291 8.2387411149612291 5 0 50 4.75 2.3363814807504903 8.3363814807504912 0 51 6.045454545454545 6.5909090909090908 3 1 52 7.410855227939444 2.2513680783066743 6 0 53 7.1167268544697482 5.1498194365907572 10 1 54 5.1846853285072818 7.2975798152864604 8.7947628489671814 0 55 2.4990103244870143 6.335217503721954 10 1 56 7.7302884615384615 9 7.2302884615384615 1 57 6.1805555555555554 2.0173611111111112 6 0 58 3.3674022849368259 5.8029812494362272 9.1387710999925105 0 59 2.4369249823071479 6.6892250530785562 8.936924982307147 0 60 2.4495071064793468 8.0504928935206532 10 1 61 4.75 3.0563251557933766 3.8468374221033117 0 62 7.6561927939578611 5.392441199570106 8.8106551974088241 0 63 6.5 7.7287604999863806 3.8643802499931903 0 64 7.7818877551020407 7.2818877551020407 8.75 0 65 9.5 3.8706896551724137 3.5258620689655173 1 66 0.5 6.1666666666666661 3 1 67 3.4715634067110677 9 7.8842340693743527 1 68 6.7100911686354427 3.8550455843177214 4 0 69 1.5 6.25 7.8415208349797902 0 70 6.5 1 4.1577380952380949 1 71 3.25 6 7.8583968340663395 0 72 8.5 4.359445731071979 1.0486651227136248 0 73 6 8.4218906934501554 10 1 74 3.5 1 4.0380288028802873 1 75 8.0504990257166646 1 7.5504990257166646 1 76 5 9 4.8091755319148941 1 77 1 9.5 10 1 78 3 9.5 10 1 79 5 9.5 10 1 80 7 9.5 10 1 81 9 9.5 10 1 82 1 8.5 10 1 83 1 7.5 10 1 84 9 7.5 10 1 85 9 6 10 1 86 1 5.5 10 1 87 9 4.5 10 1 88 1 4 10 1 89 6 3.5 10 1 90 1 2.5 10 1 91 9 2.5 10 1 92 7.25 2.25 10 1 93 1 0.5 10 1 94 3 0.5 10 1 95 5 0.5 10 1 96 7 0.5 10 1 97 9 0.5 10 1 98 0.5 10 9 1 99 1.5 10 9 1 100 2.5 10 9 1 101 4 10 9 1 102 5.5 10 9 1 103 7.5 10 9 1 104 8.5 10 9 1 105 9.5 10 9 1 106 0.5 9 9 1 107 1.5 9 9 1 108 2.5 9 9 1 109 4.5 9 9 1 110 6 9 9 1 111 7.5 9 9 1 112 8.5 9 9 1 113 9.5 9 9 1 114 9.5 8 9 1 115 0.5 7 9 1 116 9.5 7 9 1 117 9.5 6 9 1 118 0.5 5 9 1 119 9.5 5 9 1 120 0.5 4 9 1 121 9.5 4 9 1 122 0.5 3 9 1 123 9.5 3 9 1 124 0.5 2 9 1 125 0.5 1 9 1 126 1.5 1 9 1 127 2.5 1 9 1 128 4 1 9 1 129 5.5 1 9 1 130 7.5 1 9 1 131 9.5 1 9 1 132 0.5 0 9 1 133 1.5 0 9 1 134 2.5 0 9 1 135 4.5 0 9 1 136 6 0 9 1 137 7.5 0 9 1 138 9.5 0 9 1 139 9.5 9 8 1 140 1.5 8 8 0 141 9.5 8 8 1 142 9.5 6 8 1 143 0.5 4 8 1 144 9.5 4 8 1 145 0.5 2 8 1 146 8.5 2 8 0 147 0.5 1 8 1 148 0.5 9 7 1 149 9.5 9 7 1 150 0.5 7 7 1 151 2.5 7 7 1 152 4 7 7 1 153 5.5 7 7 1 154 6.5 7 7 1 155 7.5 7 7 1 156 8.5 7 7 1 157 9.5 7 7 1 158 4.75 6 7 1 159 9.5 6 7 1 160 8 5.5 7 1 161 2.25 5.25 7 1 162 0.5 5 7 1 163 4 5 7 1 164 6.5 5 7 1 165 9.5 5 7 1 166 8.25 4.25 7 1 167 0.5 4 7 1 168 4.75 4 7 1 169 9.5 4 7 1 170 0.5 3 7 1 171 1.5 3 7 1 172 2.5 3 7 1 173 4 3 7 1 174 5.5 3 7 1 175 7.5 3 7 1 176 8.5 3 7 1 177 9.5 3 7 1 178 0.5 1 7 1 179 9.5 1 7 1 180 1.5 8 6 0 181 8.5 8 6 0 182 3.25 7 6 1 183 4.75 7 6 1 184 6.5 7 6 1 185 4.75 3 6 1 186 8.5 3 6 1 187 9.5 3 6 1 188 1.5 2 6 0 189 5 1 6 1 190 9.5 1 6 1 191 6.5 9 5.9375 1 192 9.5 2 5.5 1 193 0.5 9 5 1 194 9.5 9 5 1 195 0.5 7 5 1 196 2.5 7 5 1 197 4 7 5 1 198 5.5 7 5 1 199 6.5 7 5 1 200 7.5 7 5 1 201 8.5 7 5 1 202 9.5 7 5 1 203 8.5 6 5 1 204 9.5 6 5 1 205 5.25 5.625 5 1 206 2.25 5.25 5 1 207 0.5 5 5 1 208 4 5 5 1 209 6.5 5 5 1 210 9.5 5 5 1 211 8 4.5 5 1 212 1.53125 4.03125 5 1 213 0.5 3 5 1 214 2.5 3 5 1 215 4 3 5 1 216 5.5 3 5 1 217 7.5 3 5 1 218 8.5 3 5 1 219 9.5 3 5 1 220 0.5 1 5 1 221 9.5 1 5 1 222 7.5 5.5 4.25 0 223 3.25 4 4.25 0 224 8.5 9 4 1 225 9.5 9 4 1 226 1.5 8 4 0 227 3.25 6 4 0 228 8.5 1 4 1 229 9.5 1 4 1 230 1.375 2.125 3.875 0 231 0.5 9 3 1 232 2.5 9 3 1 233 3.5 9 3 1 234 4.5 9 3 1 235 5.5 9 3 1 236 6.5 9 3 1 237 7.5 9 3 1 238 9.5 9 3 1 239 2.5 8 3 1 240 4.5 8 3 1 241 5.5 8 3 1 242 7.5 8 3 1 243 3.5 7.5 3 1 244 2.5 7 3 1 245 7.5 7 3 1 246 2.5 6 3 1 247 7.5 6 3 1 248 5 5.5 3 1 249 9.5 5.5 3 1 250 2.5 5 3 1 251 7.5 5 3 1 252 0.5 4 3 1 253 2.5 4 3 1 254 2.5 3 3 1 255 7.5 3 3 1 256 4.5 2 3 1 257 5 2 3 1 258 5.5 2 3 1 259 7.5 2 3 1 260 5.5 1.5 3 1 261 0.5 1 3 1 262 2.5 1 3 1 263 4.5 1 3 1 264 5.5 1 3 1 265 7.5 1 3 1 266 9.5 1 3 1 267 9.5 7.25 2.75 1 268 0.5 2.5 2.5 1 269 9.5 2.5 2.5 1 270 4.5 2 2.5 1 271 5 2 2.5 1 272 5.5 2 2.5 1 273 5.5 1.5 2.5 1 274 5.5 1 2.5 1 275 8.5 1 2.5 1 276 4.5 9 2 1 277 5.5 9 2 1 278 7.5 9 2 1 279 8.5 9 2 1 280 9.5 9 2 1 281 1.5 8 2 0 282 4.5 8 2 1 283 5.5 8 2 1 284 7.5 6 2 1 285 2.5 4 2 1 286 4.5 2 2 1 287 5 2 2 1 288 5.5 2 2 1 289 7.5 2 2 1 290 5.5 1.5 2 1 291 0.5 1 2 1 292 1.5 1 2 1 293 2.5 1 2 1 294 4.5 1 2 1 295 5.5 1 2 1 296 7.5 1 2 1 297 9.5 1 2 1 298 1.5 6.0625 1.4375 0 299 0.5 9 1 1 300 2.5 9 1 1 301 7.5 9 1 1 302 9.5 9 1 1 303 0.5 7 1 1 304 2.5 7 1 1 305 7.5 7 1 1 306 9.5 7 1 1 307 7.5 6 1 1 308 9.5 6 1 1 309 0.5 5 1 1 310 2.5 5 1 1 311 7.5 5 1 1 312 9.5 5 1 1 313 2.5 4 1 1 314 0.5 3 1 1 315 2.5 3 1 1 316 7.5 3 1 1 317 9.5 3 1 1 318 2.5 2 1 1 319 7.5 2 1 1 320 9.5 2 1 1 321 0.5 1 1 1 322 2.5 1 1 1 323 7.5 1 1 1 324 9.5 1 1 1 325 0 9 0 1 326 1 9 0 1 327 3 9 0 1 328 7 9 0 1 329 9 9 0 1 330 10 9 0 1 331 8.5 7.5 0 1 332 0 7 0 1 333 3 7 0 1 334 7 7 0 1 335 10 7 0 1 336 1.5 6 0 1 337 7 6 0 1 338 10 6 0 1 339 8.5 5.5 0 1 340 0 5 0 1 341 3 5 0 1 342 7 5 0 1 343 10 5 0 1 344 1.5 4 0 1 345 0 3 0 1 346 3 3 0 1 347 7 3 0 1 348 10 3 0 1 349 3 2 0 1 350 7 2 0 1 351 10 2 0 1 352 0 1 0 1 353 1 1 0 1 354 3 1 0 1 355 7 1 0 1 356 9 1 0 1 357 10 1 0 1 358 3.4500000000000002 3.25 10 1 359 1.6098371537930638 9 6 1 360 7.3611111111111107 1 6 1 361 3.1953137028334209 9 4.6710782023214072 1 362 3.9990590217310027 1 5.1437494955938083 1 363 3.7083333333333335 4 7 1 364 6.7486464480119066 6.457157721567083 8.2725041232939205 0 365 7.7054126296308771 6.3567468802220377 10 1 366 3.9000000000000004 4.5 3 1 367 4.838175675675676 2.2206081081081082 10 1 368 8.694352937484858 4.9938587999030872 3.9359646999757718 0 369 7.6780289988689265 3.7226441119908351 10 1 370 2.7682013280841611 4.7290175087581492 10 1 371 5.1783838505324864 7.2942493276038167 10 1 372 1.5227272727272727 2.4545454545454546 0 1 373 2.7954545454545454 1 5.295454545454545 1 374 3.4207368718238276 1 7.1402456239412757 1 375 1.55 7.5499999999999998 0 1 376 2.4945312499999996 1.9945312500000001 10 1 377 3.6000000000000001 6 3 1 378 1.9359315230018288 9 7.5640684769981714 1 379 8.420588235294117 2.341176470588235 0 1 380 8.6842105263157894 6.4868421052631575 3.6578947368421053 0 381 6.5465597641233177 9 4.3143873665100658 1 382 8.2933874139626358 1.7933874139626349 5.2066125860373651 0 383 2.0864026561683215 3.25 10 1 384 7.6048922587198167 8.2796992280354385 4.6642907147906936 0 385 5.737452997878127 2.0091501371597387 4.2454249314201311 0 386 8.2296400532705984 6.2797556164194344 8.0501155631488359 0 387 1.5245098039215685 6.5245098039215685 4 0 388 8.1970740878815729 3.7564309889832477 3.8834082362921714 0 389 1.4234374999999999 6.7670833333333329 2.4462500000000005 0 390 8.8148148148148149 6.2685185185185182 2.1296296296296298 0 391 5.1363636363636367 4.2897727272727275 5 1 392 7.3850381377854246 4.6484223214993241 7.8280598695240169 0 393 1.9187435523705172 3.8359351255753733 8.0015519791656615 0 394 6.5629327580641341 4.3218168377468658 9.0926413880818835 0 395 7.2949960517992904 8.1177413139584402 6.4127373657577307 0 396 4.8247907557355676 9 6.6033154059459918 1 397 6.2665289256198351 5.3326446280991728 3 1 398 5.6874103032141461 5.7737360606389281 10 1 399 4.9504051122579318 9 7.8406878279731096 1 400 1.9999999999999998 1 7.594658610427091 1 # Generated by ./Stellar -F ../meshes/in_pyramid/house2 -rNE vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/0000775000175000017500000000000011757446472016646 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterF3F3.h0000664000175000017500000000541211757446472025040 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterF3F3.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterF3F3_h #define __vtkvmtkITKImageToImageFilterF3F3_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterF3F3 : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterF3F3,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterF3F3* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; protected: //BTX // To/from ITK typedef itk::Vector InputImagePixelType; typedef itk::Vector OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterF3F3 ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline // m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); }; ~vtkvmtkITKImageToImageFilterF3F3() { }; //ETX private: vtkvmtkITKImageToImageFilterF3F3(const vtkvmtkITKImageToImageFilterF3F3&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterF3F3&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterULUL.h0000664000175000017500000000532111757446472025157 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterULUL.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterULUL_h #define __vtkvmtkITKImageToImageFilterULUL_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterULUL : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterULUL,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterULUL* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter << std::endl; }; protected: //BTX // To/from ITK typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterULUL ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->LinkITKProgressToVTKProgress ( m_Filter ); this->vtkCast->SetOutputScalarTypeToUnsignedLong(); }; ~vtkvmtkITKImageToImageFilterULUL() { }; //ETX private: vtkvmtkITKImageToImageFilterULUL(const vtkvmtkITKImageToImageFilterULUL&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterULUL&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterSS.h0000664000175000017500000000600511757446472024723 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterSS.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterSS_h #define __vtkvmtkITKImageToImageFilterSS_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterSS : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterSS,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterSS* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; // Description: // Portion of the SetReleaseDataFlag implementation can be // implemented at this level of the hierachy. virtual void SetReleaseDataFlag(int f) { Superclass::SetReleaseDataFlag(f); m_Filter->SetReleaseDataFlag(f); } protected: //BTX // To/from ITK typedef short InputImagePixelType; typedef short OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterSS ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToShort(); }; ~vtkvmtkITKImageToImageFilterSS() { }; //ETX private: vtkvmtkITKImageToImageFilterSS(const vtkvmtkITKImageToImageFilterSS&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterSS&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterUSUS.h0000664000175000017500000000546511757446472025206 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterUSUS.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterUSUS_h #define __vtkvmtkITKImageToImageFilterUSUS_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterUSUS : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterUSUS,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterUSUS* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; protected: //BTX // To/from ITK typedef unsigned short InputImagePixelType; typedef unsigned short OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterUSUS ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToUnsignedShort(); }; ~vtkvmtkITKImageToImageFilterUSUS() { }; //ETX private: vtkvmtkITKImageToImageFilterUSUS(const vtkvmtkITKImageToImageFilterUSUS&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterUSUS&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterFUL.h0000664000175000017500000000533011757446472025024 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterFUL.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterFUL_h #define __vtkvmtkITKImageToImageFilterFUL_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterFUL : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterFUL,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterFUL* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter << std::endl; }; protected: //BTX // To/from ITK typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterFUL ( GenericFilterType* filter ) : vtkvmtkITKImageToImageFilter() { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->LinkITKProgressToVTKProgress ( m_Filter ); this->vtkCast->SetOutputScalarTypeToFloat(); }; ~vtkvmtkITKImageToImageFilterFUL() { }; //ETX private: vtkvmtkITKImageToImageFilterFUL(const vtkvmtkITKImageToImageFilterFUL&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterFUL&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterUSUL.h0000664000175000017500000000526211757446472025172 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterUSUL.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterUSUL_h #define __vtkvmtkITKImageToImageFilterUSUL_h #include "vtkImageToImageFilter.h" #include "vtkvmtkITKImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterUSUL : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterUSUL,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterUSUL* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; protected: //BTX // To/from ITK typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter FilterType; FilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterUSUL ( FilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToUnsignedShort(); }; ~vtkvmtkITKImageToImageFilterUSUL() { }; //ETX private: vtkvmtkITKImageToImageFilterUSUL(const vtkvmtkITKImageToImageFilterUSUL&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterUSUL&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKConfig.cmake.in0000775000175000017500000000041411757446472023463 0ustar lucaluca# The vtkvmtkITK source and binary trees. SET(vtkvmtkITK_SOURCE_DIR "@vtkvmtkITK_SOURCE_DIR@") SET(vtkvmtkITK_BINARY_DIR "@vtkvmtkITK_BINARY_DIR@") SET(vtkvmtkITK_LIB_DIR "@CMAKE_BINARY_DIR@/bin" "@CMAKE_BINARY_DIR@") SET(ITK_DIR "@ITK_DIR@") SET(VTK_DIR "@VTK_DIR@") vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesReader.h0000664000175000017500000005276611757446472026223 0ustar lucaluca/*========================================================================= 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://svn.slicer.org/Slicer3/trunk/Libs/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesReader.h $ Date: $Date: 2010-01-22 20:45:00 +0100 (Fri, 22 Jan 2010) $ Version: $Revision: 11747 $ ==========================================================================*/ /// vtkvmtkITKArchetypeImageSeriesReader - Read a series of files /// that have a common naming convention /// /// ArchetypeImageSeriesReader creates a volume from a series of images /// stored in files. The series are represented by one filename. This /// filename, the archetype, is any one of the files in the series. // /// \note /// This work is part of the National Alliance for Medical Image Computing /// (NAMIC), funded by the National Institutes of Health through the NIH Roadmap /// for Medical Research, Grant U54 EB005149. #ifndef __vtkvmtkITKArchetypeImageSeriesReader_h #define __vtkvmtkITKArchetypeImageSeriesReader_h #include "vtkImageSource.h" #include "vtkMatrix4x4.h" #include "itkSpatialOrientation.h" #include #include #include "itkMetaDataDictionary.h" //#include "gdcmDictSet.h" /// access to dictionary #include "gdcmDict.h" /// access to dictionary #include "gdcmDictEntry.h" /// access to dictionary #include "gdcmGlobal.h" /// access to dictionary #include "vtkvmtkITK.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKArchetypeImageSeriesReader : public vtkImageSource { public: static vtkvmtkITKArchetypeImageSeriesReader *New(); vtkTypeRevisionMacro(vtkvmtkITKArchetypeImageSeriesReader,vtkImageSource); void PrintSelf(ostream& os, vtkIndent indent); //BTX typedef itk::SpatialOrientation::ValidCoordinateOrientationFlags CoordinateOrientationCode; //ETX /// /// Specify the archetype filename for the series. vtkSetStringMacro(Archetype); vtkGetStringMacro(Archetype); /// /// See how many file names were generated during ExecuteInformation unsigned int GetNumberOfFileNames() { return this->FileNames.size(); }; /// /// Specify the file names to be used when looking for extra files /// that match the archetype in defining the volume to load (e.g. /// other canidate dicom files to look in for matching tags) unsigned int AddFileName( const char* filename ); const char* GetFileName( unsigned int n ); void ResetFileNames(); /// /// Set/Get the default spacing of the data in the file. This will be /// used if the reader provided spacing is 1.0. (Default is 1.0) vtkSetVector3Macro(DefaultDataSpacing,double); vtkGetVector3Macro(DefaultDataSpacing,double); /// /// Set/Get the default origin of the data (location of first pixel /// in the file). This will be used if the reader provided origin is /// 0.0. (Default is 0.0) vtkSetVector3Macro(DefaultDataOrigin,double); vtkGetVector3Macro(DefaultDataOrigin,double); /// /// When reading files which start at an unusual index, this can be added /// to the slice number when generating the file name (default = 0) vtkSetMacro(FileNameSliceOffset,int); vtkGetMacro(FileNameSliceOffset,int); /// /// When reading files which have regular, but non contiguous slices /// (eg filename.1,filename.3,filename.5) /// a spacing can be specified to skip missing files (default = 1) vtkSetMacro(FileNameSliceSpacing,int); vtkGetMacro(FileNameSliceSpacing,int); /// /// The maximum number of files to include in the series. If this is /// zero, then all files will be included. (Default is 0) vtkSetMacro(FileNameSliceCount,int); vtkGetMacro(FileNameSliceCount,int); /// is the given file name a NRRD file? virtual int CanReadFile(const char* filename); /// /// Set the orientation of the output image void SetDesiredCoordinateOrientationToAxial () { this->DesiredCoordinateOrientation = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RAI; /// itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RPS; this->UseNativeCoordinateOrientation = 0; this->Modified(); } void SetDesiredCoordinateOrientationToCoronal () { this->DesiredCoordinateOrientation = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RSA; /// itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_RIP; this->UseNativeCoordinateOrientation = 0; this->Modified(); } void SetDesiredCoordinateOrientationToSagittal () { this->DesiredCoordinateOrientation = itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_ASL; /// itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIR; this->UseNativeCoordinateOrientation = 0; this->Modified(); } void SetDesiredCoordinateOrientationToNative () { this->UseNativeCoordinateOrientation = 1; this->Modified(); } /// /// Set the data type of pixels in the file. /// If you want the output scalar type to have a different value, set it /// after this method is called. virtual void SetOutputScalarTypeToDouble() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_DOUBLE); } virtual void SetOutputScalarTypeToFloat() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_FLOAT); } virtual void SetOutputScalarTypeToLong() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_LONG); } virtual void SetOutputScalarTypeToUnsignedLong() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_UNSIGNED_LONG); } virtual void SetOutputScalarTypeToInt() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_INT); } virtual void SetOutputScalarTypeToUnsignedInt() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_UNSIGNED_INT); } virtual void SetOutputScalarTypeToShort() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_SHORT); } virtual void SetOutputScalarTypeToUnsignedShort() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_UNSIGNED_SHORT); } virtual void SetOutputScalarTypeToChar() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_CHAR); } virtual void SetOutputScalarTypeToUnsignedChar() { UseNativeScalarType = 0; this->SetOutputScalarType(VTK_UNSIGNED_CHAR); } virtual void SetOutputScalarTypeToNative() { UseNativeScalarType = 1; this->Modified(); } /// /// Use image origin from the file void SetUseNativeOriginOn() { UseNativeOrigin = true; } /// /// Use image center as origin void SetUseNativeOriginOff() { UseNativeOrigin = false; } /// /// Get the file format. Pixels are this type in the file. vtkSetMacro(OutputScalarType, int); vtkGetMacro(OutputScalarType, int); /// /// Get number of scalars vtkSetMacro(NumberOfComponents, unsigned int); vtkGetMacro(NumberOfComponents, unsigned int); /// /// Whether load in a single file or a series vtkSetMacro(SingleFile, int); vtkGetMacro(SingleFile, int); /// /// Whether to use orientation from file vtkSetMacro(UseOrientationFromFile, int); vtkGetMacro(UseOrientationFromFile, int); /// /// Returns an IJK to RAS transformation matrix vtkMatrix4x4* GetRasToIjkMatrix(); /// /// ITK internally does not register all of the IO types that get built /// (possibly due to lingering bugs?) but many slicer users have /// GE5 (Signa - magic number: IMGF) files that they need to work /// with so we register the factory explictly here // /// In addition, ITK does register an older dicom parser that incorrectly /// report success when reading ill-formed dicom files so we turn that old /// parser off. // void RegisterExtraBuiltInFactories(); void UnRegisterDeprecatedBuiltInFactories(); //BTX /// /// Return the MetaDataDictionary from the ITK layer const itk::MetaDataDictionary &GetMetaDataDictionary() const; std::vector Tags; std::vector TagValues; void ParseDictionary(); //ETX unsigned int GetNumberOfItemsInDictionary(); bool HasKey( char* tag ); const char* GetNthKey( unsigned int n ); const char* GetNthValue( unsigned int n ); const char* GetTagValue( char* tag ); /// set/get functions for grouping by tags bool GetGroupingByTags() { return GroupingByTags; } void SetGroupingByTagsOn() { GroupingByTags = true; } void SetGroupingByTagsOff() { GroupingByTags = false; } /// ------- int GetSelectedUID() { return SelectedUID; } void SetSelectedUID( int v ) { SelectedUID = v; SetGroupingByTagsOn(); } /// ------- int GetSelectedContentTime() { return SelectedContentTime; } void SetSelectedContentTime( int v ) { SelectedContentTime = v; SetGroupingByTagsOn(); } /// ------- int GetSelectedTriggerTime() { return SelectedTriggerTime; } void SetSelectedTriggerTime( int v ) { SelectedTriggerTime = v; SetGroupingByTagsOn(); } /// ------- int GetSelectedEchoNumbers() { return SelectedEchoNumbers; } void SetSelectedEchoNumbers( int v ) { SelectedEchoNumbers = v; SetGroupingByTagsOn(); } /// ------- int GetSelectedDiffusion() { return SelectedDiffusion; } void SetSelectedDiffusion( int v ) { SelectedDiffusion = v; SetGroupingByTagsOn(); } /// ------- int GetSelectedSlice() { return SelectedSlice; } void SetSelectedSlice( int v ) { SelectedSlice = v; SetGroupingByTagsOn(); } /// ------- int GetSelectedOrientation() { return SelectedOrientation; } void SetSelectedOrientation( int v ) { SelectedOrientation = v; SetGroupingByTagsOn(); } /// get number of certain discriminators in the directory unsigned int GetNumberOfSeriesInstanceUIDs() { return this->SeriesInstanceUIDs.size(); } unsigned int GetNumberOfContentTime() { return this->ContentTime.size(); } unsigned int GetNumberOfTriggerTime() { return this->TriggerTime.size(); } unsigned int GetNumberOfEchoNumbers() { return this->EchoNumbers.size(); } unsigned int GetNumberOfSliceLocation() { return this->SliceLocation.size(); } unsigned int GetNumberOfDiffusionGradientOrientation() { return this->DiffusionGradientOrientation.size(); }; unsigned int GetNumberOfImageOrientationPatient() { return this->ImageOrientationPatient.size(); }; /// check the existance of given discriminator int ExistSeriesInstanceUID( const char* SeriesInstanceUID ) { for (unsigned int k = 0; k < GetNumberOfSeriesInstanceUIDs(); k++) { if ( this->SeriesInstanceUIDs[k].find(SeriesInstanceUID) != std::string::npos ) { return k; } } return -1; } int ExistContentTime( const char* contentTime ) { for (unsigned int k = 0; k < GetNumberOfContentTime(); k++) { if ( this->ContentTime[k].find(contentTime) != std::string::npos ) { return k; } } return -1; } int ExistTriggerTime( const char* triggerTime ) { for (unsigned int k = 0; k < GetNumberOfTriggerTime(); k++) { if ( this->TriggerTime[k].find(triggerTime) != std::string::npos ) { return k; } } return -1; } int ExistEchoNumbers( const char* echoNumbers ) { for (unsigned int k = 0; k < GetNumberOfEchoNumbers(); k++) { if ( this->EchoNumbers[k].find(echoNumbers) != std::string::npos ) { return k; } } return -1; } int ExistDiffusionGradientOrientation( float* dgo ) { float a = 0; for (int n = 0; n < 3; n++) { a += dgo[n]*dgo[n]; } for (unsigned int k = 0; k < GetNumberOfDiffusionGradientOrientation(); k++) { float b = 0; float c = 0; for (int n = 0; n < 3; n++) { b += this->DiffusionGradientOrientation[k][n] * this->DiffusionGradientOrientation[k][n]; c += this->DiffusionGradientOrientation[k][n] * dgo[n]; } c = fabs(c)/sqrt(a*b); if ( c > 0.99999 ) { return k; } } return -1; } int ExistSliceLocation( float sliceLocation ) { for (unsigned int k = 0; k < GetNumberOfSliceLocation(); k++) { if ( this->SliceLocation[k] == sliceLocation ) { return k; } } return -1; } int ExistImageOrientationPatient( float * directionCosine ) { /// input has to have six elements float a = sqrt( directionCosine[0]*directionCosine[0] + directionCosine[1]*directionCosine[1] + directionCosine[2]*directionCosine[2] ); for (int k = 0; k < 3; k++) { directionCosine[k] /= a; } a = sqrt( directionCosine[3]*directionCosine[3] + directionCosine[4]*directionCosine[4] + directionCosine[5]*directionCosine[5] ); for (int k = 3; k < 6; k++) { directionCosine[k] /= a; } for (unsigned int k = 0; k < GetNumberOfImageOrientationPatient(); k++) { std::vector aVec = ImageOrientationPatient[k]; a = sqrt( aVec[0]*aVec[0] + aVec[1]*aVec[1] + aVec[2]*aVec[2] ); float b = (directionCosine[0]*aVec[0] + directionCosine[1]*aVec[1] + directionCosine[2]*aVec[2])/a; if ( b < 0.99999 ) { continue; } a = sqrt( aVec[3]*aVec[3] + aVec[4]*aVec[4] + aVec[5]*aVec[5] ); b = (directionCosine[3]*aVec[3] + directionCosine[4]*aVec[4] + directionCosine[5]*aVec[5])/a; if ( b > 0.99999 ) { return k; } } return -1; } /// methods to get N-th discriminator const char* GetNthSeriesInstanceUID( unsigned int n ) { if ( n >= this->GetNumberOfSeriesInstanceUIDs() ) { return NULL; } return this->SeriesInstanceUIDs[n].c_str(); } const char* GetNthContentTime( unsigned int n ) { if ( n >= this->GetNumberOfContentTime() ) { return NULL; } return this->ContentTime[n].c_str(); } const char* GetNthTriggerTime( unsigned int n ) { if ( n >= this->GetNumberOfTriggerTime() ) { return NULL; } return this->TriggerTime[n].c_str(); } const char* GetNthEchoNumbers( unsigned int n ) { if ( n >= this->GetNumberOfEchoNumbers() ) { return NULL; } return this->EchoNumbers[n].c_str(); } float* GetNthDiffusionGradientOrientation( unsigned int n ) { if ( n >= this->GetNumberOfDiffusionGradientOrientation() ) { return NULL; } float *dgo = new float [3]; for (int k = 0; k <3; k++) { dgo[k] = this->DiffusionGradientOrientation[n][k]; } return dgo; } float GetNthSliceLocation( unsigned int n ) { if ( n >= this->GetNumberOfSliceLocation() ) { return this->SliceLocation[0]; } return this->SliceLocation[0]; } float* GetNthImageOrientationPatient( unsigned int n ) { if ( n >= this->GetNumberOfImageOrientationPatient() ) { return NULL; } float *dgo = new float [6]; for (int k = 0; k <3; k++) { dgo[k] = this->ImageOrientationPatient[n][k]; } return dgo; } /// insert unique item into array. Duplicate code for TCL wrapping. /// TODO: need to clean up int InsertSeriesInstanceUIDs ( const char * aUID ) { int k = ExistSeriesInstanceUID( aUID ); if ( k >= 0 ) { return k; } std::string aVector(aUID); this->SeriesInstanceUIDs.push_back( aVector ); return (this->SeriesInstanceUIDs.size()-1); } int InsertContentTime ( const char * aTime ) { int k = ExistContentTime( aTime ); if ( k >= 0 ) { return k; } std::string aVector(aTime); this->ContentTime.push_back( aVector ); return (this->ContentTime.size()-1); } int InsertTriggerTime ( const char * aTime ) { int k = ExistTriggerTime( aTime ); if ( k >= 0 ) { return k; } std::string aVector(aTime); this->TriggerTime.push_back( aVector ); return (this->TriggerTime.size()-1); } int InsertEchoNumbers ( const char * aEcho ) { int k = ExistEchoNumbers( aEcho ); if ( k >= 0 ) { return k; } std::string aVector(aEcho); this->EchoNumbers.push_back( aVector ); return (this->EchoNumbers.size()-1); } int InsertDiffusionGradientOrientation ( float *a ) { int k = ExistDiffusionGradientOrientation( a ); if ( k >= 0 ) { return k; } std::vector< float > aVector(3); float aMag = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); for (k = 0; k < 3; k++) { aVector[k] = a[k]/aMag; } this->DiffusionGradientOrientation.push_back( aVector ); return (this->DiffusionGradientOrientation.size()-1); } int InsertSliceLocation ( float a ) { int k = ExistSliceLocation( a ); if ( k >= 0 ) { return k; } this->SliceLocation.push_back( a ); return (this->SliceLocation.size()-1); } int InsertImageOrientationPatient ( float *a ) { int k = ExistImageOrientationPatient( a ); if ( k >= 0 ) { return k; } std::vector< float > aVector(6); float aMag = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); float bMag = sqrt(a[3]*a[3]+a[4]*a[4]+a[5]*a[5]); for (k = 0; k < 3; k++) { aVector[k] = a[k]/aMag; aVector[k+3] = a[k+3]/bMag; } this->ImageOrientationPatient.push_back( aVector ); return (this->ImageOrientationPatient.size()-1); } void AnalyzeDicomHeaders( ); void AssembleNthVolume( int n ); int AssembleVolumeContainingArchetype(); void GroupFiles ( int idxSeriesInstanceUID, int idxContentTime, int idxTriggerTime, int idxEchoNumbers, int idxDiffusionGradientOrientation, int idxSliceLocation, int idxImageOrientationPatient ); const char* GetNthFileName ( int idxSeriesInstanceUID, int idxContentTime, int idxTriggerTime, int idxEchoNumbers, int idxDiffusionGradientOrientation, int idxSliceLocation, int idxImageOrientationPatient, int n ); protected: vtkvmtkITKArchetypeImageSeriesReader(); ~vtkvmtkITKArchetypeImageSeriesReader(); char *Archetype; int SingleFile; int UseOrientationFromFile; int DataExtent[6]; int OutputScalarType; unsigned int NumberOfComponents; double DefaultDataSpacing[3]; double DefaultDataOrigin[3]; int FileNameSliceOffset; int FileNameSliceSpacing; int FileNameSliceCount; vtkMatrix4x4* RasToIjkMatrix; char UseNativeCoordinateOrientation; char UseNativeScalarType; bool UseNativeOrigin; bool GroupingByTags; int SelectedUID; int SelectedContentTime; int SelectedTriggerTime; int SelectedEchoNumbers; int SelectedDiffusion; int SelectedSlice; int SelectedOrientation; unsigned int IndexArchetype; //BTX std::vector FileNames; CoordinateOrientationCode DesiredCoordinateOrientation; //ETX virtual void ExecuteInformation(); /// defined in the subclasses virtual void ExecuteData(vtkDataObject *data); //BTX itk::MetaDataDictionary Dictionary; //ETX /// The following variables provide support /// for reading a directory with multiple series/groups. /// The current scheme is to check the following and see /// if multiple values exist: /// /// SeriesInstanceUID 0020,000E /// ContentTime 0008,0033 /// TriggerTime 0018,1060 /// EchoNumbers 0018,0086 /// DiffusionGradientOrientation 0018,9089 /// SliceLocation 0020,1041 /// ImageOrientationPatient 0020,0037 //BTX std::vector AllFileNames; bool AnalyzeHeader; bool IsOnlyFile; std::vector SeriesInstanceUIDs; std::vector ContentTime; std::vector TriggerTime; std::vector EchoNumbers; std::vector< std::vector > DiffusionGradientOrientation; std::vector SliceLocation; std::vector< std::vector > ImageOrientationPatient; /// index of each dicom file into the above arrays std::vector IndexSeriesInstanceUIDs; std::vector IndexContentTime; std::vector IndexTriggerTime; std::vector IndexEchoNumbers; std::vector IndexDiffusionGradientOrientation; std::vector IndexSliceLocation; std::vector IndexImageOrientationPatient; //ETX private: vtkvmtkITKArchetypeImageSeriesReader(const vtkvmtkITKArchetypeImageSeriesReader&); /// Not implemented. void operator=(const vtkvmtkITKArchetypeImageSeriesReader&); /// Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKConfigure.h.in0000775000175000017500000000071211757446472023347 0ustar lucaluca/* * Here is where system computed values get stored. * These values should only change when the target compile platform changes. */ #if defined(WIN32) && !defined(VTK_VMTK_ITK_STATIC) #pragma warning ( disable : 4275 ) #endif #cmakedefine CMAKE_WORDS_BIGENDIAN #ifdef CMAKE_WORDS_BIGENDIAN #define WORDS_BIGENDIAN #else #define WORDS_LITTLEENDIAN #endif #cmakedefine BUILD_SHARED_LIBS #ifndef BUILD_SHARED_LIBS #define VTK_VMTK_ITK_STATIC #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilter.h0000664000175000017500000001514111757446472024456 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilter.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a foo #ifndef __vtkvmtkITKImageToImageFilter_h #define __vtkvmtkITKImageToImageFilter_h #include "itkCommand.h" #include "vtkCommand.h" #include "itkProcessObject.h" #include "vtkImageImport.h" #include "vtkImageExport.h" #include "vtkImageToImageFilter.h" #include "vtkImageCast.h" #include "vtkImageData.h" #include "vtkvmtkITK.h" #undef itkExceptionMacro #define itkExceptionMacro(x) \ { \ std::ostringstream message; \ message << "itk::ERROR: " << this->GetNameOfClass() \ << "(" << this << "): "; \ std::cerr << message.str().c_str() << std::endl; \ } #undef itkGenericExceptionMacro #define itkGenericExceptionMacro(x) \ { \ std::ostringstream message; \ message << "itk::ERROR: " x; \ std::cerr << message.str() << std::endl; \ } class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilter : public vtkImageToImageFilter { public: static vtkvmtkITKImageToImageFilter *New() { return new vtkvmtkITKImageToImageFilter; }; vtkTypeMacro(vtkvmtkITKImageToImageFilter,vtkImageToImageFilter); void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); this->vtkExporter->PrintSelf ( os, indent ); this->vtkImporter->PrintSelf ( os, indent ); }; // Description: // This method considers the sub filters MTimes when computing this objects // modified time. unsigned long int GetMTime() { unsigned long int t1, t2; t1 = this->Superclass::GetMTime(); t2 = this->vtkExporter->GetMTime(); if (t2 > t1) { t1 = t2; } t2 = this->vtkImporter->GetMTime(); if (t2 > t1) { t1 = t2; } return t1; }; // Description: // Pass modified message to itk filter void Modified() { this->Superclass::Modified(); if (this->m_Process) { m_Process->Modified(); } }; // Description: // Pass DebugOn. void DebugOn() { this->m_Process->DebugOn(); }; // Description: // Pass DebugOff. void DebugOff() { this->m_Process->DebugOff(); }; // Description: // Pass SetNumberOfThreads. void SetNumberOfThreads(int val) { this->m_Process->SetNumberOfThreads(val); }; // Description: // Pass SetNumberOfThreads. int GetNumberOfThreads() { return this->m_Process->GetNumberOfThreads(); }; // Description: // This method returns the cache to make a connection // It justs feeds the request to the sub filter. void SetOutput ( vtkImageData* d ) { this->vtkImporter->SetOutput ( d ); }; virtual vtkImageData *GetOutput() { return this->vtkImporter->GetOutput(); }; virtual vtkImageData *GetOutput(int idx) { return (vtkImageData *) this->vtkImporter->GetOutput(idx); }; // Description: // Set the Input of the filter. virtual void SetInput(vtkImageData *Input) { this->vtkCast->SetInput(Input); }; // Description: Override vtkSource's Update so that we can access // this class's GetOutput(). vtkSource's GetOutput is not virtual. void Update() { if (this->GetOutput(0)) { this->GetOutput(0)->Update(); if ( this->GetOutput(0)->GetSource() ) { // this->SetErrorCode( this->GetOutput(0)->GetSource()->GetErrorCode() ); } } } //BTX void HandleProgressEvent () { if ( this->m_Process ) { this->UpdateProgress ( m_Process->GetProgress() ); } }; void HandleStartEvent () { this->InvokeEvent(vtkCommand::StartEvent,NULL); }; void HandleEndEvent () { this->InvokeEvent(vtkCommand::EndEvent,NULL); }; // ETX protected: // BTX // Dummy ExecuteData void ExecuteData (vtkDataObject *) { vtkWarningMacro(<< "This filter does not respond to Update(). Doing a GetOutput->Update() instead."); } // ETX vtkvmtkITKImageToImageFilter() { // Need an import, export, and a ITK pipeline this->vtkCast = vtkImageCast::New(); this->vtkExporter = vtkImageExport::New(); this->vtkImporter = vtkImageImport::New(); #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 2) this->vtkImporter->SetScalarArrayName("Scalars_"); #endif this->vtkExporter->SetInput ( this->vtkCast->GetOutput() ); this->m_Process = NULL; this->m_ProgressCommand = MemberCommand::New(); this->m_ProgressCommand->SetCallbackFunction ( this, &vtkvmtkITKImageToImageFilter::HandleProgressEvent ); this->m_StartEventCommand = MemberCommand::New(); this->m_StartEventCommand->SetCallbackFunction ( this, &vtkvmtkITKImageToImageFilter::HandleStartEvent ); this->m_EndEventCommand = MemberCommand::New(); this->m_EndEventCommand->SetCallbackFunction ( this, &vtkvmtkITKImageToImageFilter::HandleEndEvent ); }; ~vtkvmtkITKImageToImageFilter() { // std::cerr << "Destructing vtkvmtkITKImageToImageFilter" << std::endl; this->vtkExporter->Delete(); this->vtkImporter->Delete(); this->vtkCast->Delete(); }; // BTX void LinkITKProgressToVTKProgress ( itk::ProcessObject* process ) { if ( process ) { this->m_Process = process; this->m_Process->AddObserver ( itk::ProgressEvent(), this->m_ProgressCommand ); this->m_Process->AddObserver ( itk::StartEvent(), this->m_StartEventCommand ); this->m_Process->AddObserver ( itk::EndEvent(), this->m_EndEventCommand ); } }; typedef itk::SimpleMemberCommand MemberCommand; typedef MemberCommand::Pointer MemberCommandPointer; itk::ProcessObject::Pointer m_Process; MemberCommandPointer m_ProgressCommand; MemberCommandPointer m_StartEventCommand; MemberCommandPointer m_EndEventCommand; // ITK Progress object // To/from VTK vtkImageCast* vtkCast; vtkImageImport* vtkImporter; vtkImageExport* vtkExporter; //ETX private: vtkvmtkITKImageToImageFilter(const vtkvmtkITKImageToImageFilter&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITK.h0000775000175000017500000000141311757446472021077 0ustar lucaluca/*========================================================================= 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" vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesScalarReader.h0000775000175000017500000000256111757446472027340 0ustar lucaluca/*========================================================================= 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://svn.slicer.org/Slicer3/trunk/Libs/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesScalarReader.h $ Date: $Date: 2010-01-22 20:45:00 +0100 (Fri, 22 Jan 2010) $ Version: $Revision: 11747 $ ==========================================================================*/ #ifndef __vtkvmtkITKArchetypeImageSeriesScalarReader_h #define __vtkvmtkITKArchetypeImageSeriesScalarReader_h #include "vtkvmtkITKArchetypeImageSeriesReader.h" #include "itkImageFileReader.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKArchetypeImageSeriesScalarReader : public vtkvmtkITKArchetypeImageSeriesReader { public: static vtkvmtkITKArchetypeImageSeriesScalarReader *New(); vtkTypeRevisionMacro(vtkvmtkITKArchetypeImageSeriesScalarReader,vtkvmtkITKArchetypeImageSeriesReader); void PrintSelf(ostream& os, vtkIndent indent); protected: vtkvmtkITKArchetypeImageSeriesScalarReader(); ~vtkvmtkITKArchetypeImageSeriesScalarReader(); void ExecuteData(vtkDataObject *data); //BTX static void ReadProgressCallback(itk::ProcessObject* obj,const itk::ProgressEvent&, void* data); //ETX /// private: }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKWin32Header.h0000775000175000017500000000210411757446472023031 0ustar lucaluca/*========================================================================= 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: vtkITK Module: $HeadURL: http://www.na-mic.org/svn/Slicer3/trunk/Libs/vtkITK/vtkITKWin32Header.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKWin32Header - manage Windows system differences // .SECTION Description // The vtkITKWin32Header captures some system differences between Unix // and Windows operating systems. #ifndef __vtkvmtkITKWin32Header_h #define __vtkvmtkITKWin32Header_h #include #if defined(WIN32) && !defined(VTK_VMTK_ITK_STATIC) #if defined(vtkvmtkITK_EXPORTS) #define VTK_VMTK_ITK_EXPORT __declspec( dllexport ) #else #define VTK_VMTK_ITK_EXPORT __declspec( dllimport ) #endif #else #define VTK_VMTK_ITK_EXPORT #endif #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterSF.h0000664000175000017500000000604111757446472024706 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Language: C++ 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. =========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterSF_h #define __vtkvmtkITKImageToImageFilterSF_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterSF : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterSF,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterSF* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; // Description: // Portion of the SetReleaseDataFlag implementation can be // implemented at this level of the hierachy. virtual void SetReleaseDataFlag(int f) { Superclass::SetReleaseDataFlag(f); m_Filter->SetReleaseDataFlag(f); } protected: //BTX // To/from ITK typedef short InputImagePixelType; typedef float OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterSF ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToShort(); }; ~vtkvmtkITKImageToImageFilterSF() { }; //ETX private: vtkvmtkITKImageToImageFilterSF(const vtkvmtkITKImageToImageFilterSF&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterSF&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterFF.h0000664000175000017500000000540411757446472024673 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterFF.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterFF_h #define __vtkvmtkITKImageToImageFilterFF_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterFF : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterFF,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterFF* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; protected: //BTX // To/from ITK typedef float InputImagePixelType; typedef float OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterFF ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToFloat(); }; ~vtkvmtkITKImageToImageFilterFF() { }; //ETX private: vtkvmtkITKImageToImageFilterFF(const vtkvmtkITKImageToImageFilterFF&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterFF&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKUtility.h0000664000175000017500000001212211757446472022457 0ustar lucaluca/*========================================================================= 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 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 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 ( 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 ( 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 ( 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::Pointer progressEvent = // itk::SimpleMemberCommand::New(); // progressEvent->SetCallbackFunction(&progressDisplay, // &ProgressDisplay::Display); // denoiser->AddObserver(itk::ProgressEvent(), progressEvent); #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/CMakeLists.txt0000664000175000017500000001352311757446472021412 0ustar lucaluca# -------------------------------------------------------------------------- # Sources # include a test for endianness (used to be done by default) INCLUDE (${CMAKE_ROOT}/Modules/TestBigEndian.cmake) TEST_BIG_ENDIAN(CMAKE_WORDS_BIGENDIAN) #FIND_PACKAGE(VTK REQUIRED) #INCLUDE(${VTK_USE_FILE}) #FIND_PACKAGE(ITK REQUIRED) #INCLUDE(${ITK_USE_FILE}) SET(vtkvmtkITK_SRCS vtkvmtkITKArchetypeImageSeriesReader.cxx vtkvmtkITKArchetypeImageSeriesScalarReader.cxx vtkvmtkITKImageWriter.cxx vtkvmtkITKImageToImageFilter.h vtkvmtkITKImageToImageFilter2DFF.h vtkvmtkITKImageToImageFilterFF.h ) SET(VTK_VMTK_ITK_EXTRA_INCLUDES vtkvmtkITK.h vtkvmtkITKUtility.h ) # Abstract/pure virtual classes #SET_SOURCE_FILES_PROPERTIES ( # ABSTRACT #) # Helper classes #SET_SOURCE_FILES_PROPERTIES( # WRAP_EXCLUDE # ) # -------------------------------------------------------------------------- # Include dirs #INCLUDE_DIRECTORIES( # ${vtkvmtkITK_SOURCE_DIR} # ${vtkvmtkITK_BINARY_DIR} # ${ITK_INCLUDE_DIRS} # ${VTK_INCLUDE_DIRS} # ) # -------------------------------------------------------------------------- # Build the library ADD_LIBRARY (vtkvmtkITK ${vtkvmtkITK_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkITK PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkITK PROPERTIES LINKER_LANGUAGE CXX) IF(NOT WIN32) SET_TARGET_PROPERTIES(vtkvmtkITK PROPERTIES COMPILE_FLAGS -fPIC) ENDIF(NOT WIN32) TARGET_LINK_LIBRARIES(vtkvmtkITK vtkImaging ITKNumerics ITKBasicFilters ITKIO ITKDICOMParser) INSTALL(TARGETS vtkvmtkITK LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${vtkvmtkITK_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/Utilities/vtkvmtkITK/*.h") INSTALL(FILES ${files} ${VTK_VMTK_ITK_EXTRA_INCLUDES} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkITK) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### # -------------------------------------------------------------------------- # Wrapping #INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) #INCLUDE("${VTK_CMAKE_DIR}/vtkWrapTcl.cmake") #VTK_WRAP_TCL3(vtkvmtkITK vtkvmtkITK_TCL_SRCS "${vtkvmtkITK_SRCS}" "") IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkITKPython vtkvmtkITKPython_SRCS "${vtkvmtkITK_SRCS}") ADD_LIBRARY(vtkvmtkITKPythonD ${vtkvmtkITKPython_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkITKPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkITKPython MODULE vtkvmtkITKPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkITKPythonD vtkvmtkITK vtkCommon vtkCommonPythonD vtkFiltering vtkFilteringPythonD) TARGET_LINK_LIBRARIES (vtkvmtkITKPython vtkvmtkITKPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkITKPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkITKPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkITKPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) # INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) # INCLUDE("${VTK_CMAKE_DIR}/vtkWrapTcl.cmake") SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkITKTCL vtkvmtkITKTCL_SRCS "${vtkvmtkITK_SRCS}" "") ADD_LIBRARY(vtkvmtkITKTCL ${vtkvmtkITKTCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkITKTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkITKTCL vtkvmtkITK vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkImaging vtkImagingTCL) INSTALL(TARGETS vtkvmtkITKTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Develpment RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkITKTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) # -------------------------------------------------------------------------- # Build the library #ADD_LIBRARY(vtkvmtkITK # ${vtkvmtkITK_SRCS} # ) # #IF(Slicer3_SOURCE_DIR) # IF(BUILD_SHARED_LIBS) # INSTALL_TARGETS(${SLICER3_LIB_INSTALL_DIR} vtkvmtkITK) # ENDIF(BUILD_SHARED_LIBS) #ENDIF(Slicer3_SOURCE_DIR) # #TARGET_LINK_LIBRARIES(vtkvmtkITK # vtkCommonTCL # vtkFilteringTCL # vtkImagingTCL # ITKAlgorithms # ITKNumerics # ITKCommon # ITKBasicFilters # ITKNumerics # ITKStatistics # ITKBasicFilters # ITKIO # ITKDICOMParser # ) # # ## -------------------------------------------------------------------------- ## Testing (requires some of the examples) # #IF(BUILD_TESTING) # SUBDIRS(Testing) #ENDIF(BUILD_TESTING) # #CONFIGURE_FILE( # ${vtkvmtkITK_SOURCE_DIR}/vtkvmtkITKConfigure.h.in # ${vtkvmtkITK_BINARY_DIR}/vtkvmtkITKConfigure.h #) #CONFIGURE_FILE( # ${vtkvmtkITK_SOURCE_DIR}/vtkvmtkITKConfig.cmake.in # ${vtkvmtkITK_BINARY_DIR}/vtkvmtkITKConfig.cmake #) vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesScalarReader.cxx0000775000175000017500000002044711757446472027716 0ustar lucaluca/*========================================================================= 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://svn.slicer.org/Slicer3/trunk/Libs/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesScalarReader.cxx $ Date: $Date: 2007-01-19 19:21:56 +0100 (Fri, 19 Jan 2007) $ Version: $Revision: 2267 $ ==========================================================================*/ #include "vtkvmtkITKArchetypeImageSeriesScalarReader.h" #include "vtkImageData.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkDataArray.h" #include #include "itkArchetypeSeriesFileNames.h" #include "itkImage.h" #include "itkVector.h" #include "itkOrientImageFilter.h" #include "itkImageSeriesReader.h" #include "itkImageFileReader.h" #include "itkImportImageContainer.h" #include "itkImageRegion.h" #include "itkGDCMSeriesFileNames.h" #include "itkGDCMImageIO.h" #include vtkCxxRevisionMacro(vtkvmtkITKArchetypeImageSeriesScalarReader, "$Revision: 2267 $"); vtkStandardNewMacro(vtkvmtkITKArchetypeImageSeriesScalarReader); //---------------------------------------------------------------------------- vtkvmtkITKArchetypeImageSeriesScalarReader::vtkvmtkITKArchetypeImageSeriesScalarReader() { } //---------------------------------------------------------------------------- vtkvmtkITKArchetypeImageSeriesScalarReader::~vtkvmtkITKArchetypeImageSeriesScalarReader() { } //---------------------------------------------------------------------------- void vtkvmtkITKArchetypeImageSeriesScalarReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "vtk ITK Archetype Image Series Scalar Reader\n"; } //---------------------------------------------------------------------------- // This function reads a data from a file. The datas extent/axes // are assumed to be the same as the file extent/order. void vtkvmtkITKArchetypeImageSeriesScalarReader::ExecuteData(vtkDataObject *output) { if (!this->Superclass::Archetype) { vtkErrorMacro("An Archetype must be specified."); return; } vtkImageData *data = vtkImageData::SafeDownCast(output); // removed UpdateInformation: generates an error message // from VTK and doesn't appear to be needed... //data->UpdateInformation(); data->SetExtent(0,0,0,0,0,0); data->AllocateScalars(); data->SetExtent(data->GetWholeExtent()); /// SCALAR MACRO #define vtkvmtkITKExecuteDataFromSeries(typeN, type) \ case typeN: \ {\ typedef itk::Image image##typeN;\ typedef itk::ImageSource FilterType; \ FilterType::Pointer filter; \ itk::ImageSeriesReader::Pointer reader##typeN = \ itk::ImageSeriesReader::New(); \ itk::CStyleCommand::Pointer pcl=itk::CStyleCommand::New(); \ pcl->SetCallback((itk::CStyleCommand::FunctionPointer)&ReadProgressCallback); \ pcl->SetClientData(this); \ reader##typeN->AddObserver(itk::ProgressEvent(),pcl); \ reader##typeN->SetFileNames(this->FileNames); \ reader##typeN->ReleaseDataFlagOn(); \ if (this->UseNativeCoordinateOrientation) \ { \ filter = reader##typeN; \ } \ else \ { \ itk::OrientImageFilter::Pointer orient##typeN = \ itk::OrientImageFilter::New(); \ if (this->Debug) {orient##typeN->DebugOn();} \ orient##typeN->SetInput(reader##typeN->GetOutput()); \ orient##typeN->UseImageDirectionOn(); \ orient##typeN->SetDesiredCoordinateOrientation(this->DesiredCoordinateOrientation); \ filter = orient##typeN; \ }\ filter->UpdateLargestPossibleRegion(); \ itk::ImportImageContainer::Pointer PixelContainer##typeN;\ PixelContainer##typeN = filter->GetOutput()->GetPixelContainer();\ void *ptr = static_cast (PixelContainer##typeN->GetBufferPointer());\ (dynamic_cast( output))->GetPointData()->GetScalars()->SetVoidArray(ptr, PixelContainer##typeN->Size(), 0);\ PixelContainer##typeN->ContainerManageMemoryOff();\ }\ break #define vtkvmtkITKExecuteDataFromFile(typeN, type) \ case typeN: \ {\ typedef itk::Image image2##typeN;\ typedef itk::ImageSource FilterType; \ FilterType::Pointer filter; \ itk::ImageFileReader::Pointer reader2##typeN = \ itk::ImageFileReader::New(); \ reader2##typeN->SetFileName(this->FileNames[0].c_str()); \ if (this->UseNativeCoordinateOrientation) \ { \ filter = reader2##typeN; \ } \ else \ { \ itk::OrientImageFilter::Pointer orient2##typeN = \ itk::OrientImageFilter::New(); \ if (this->Debug) {orient2##typeN->DebugOn();} \ orient2##typeN->SetInput(reader2##typeN->GetOutput()); \ orient2##typeN->UseImageDirectionOn(); \ orient2##typeN->SetDesiredCoordinateOrientation(this->DesiredCoordinateOrientation); \ filter = orient2##typeN; \ } \ filter->UpdateLargestPossibleRegion();\ itk::ImportImageContainer::Pointer PixelContainer2##typeN;\ PixelContainer2##typeN = filter->GetOutput()->GetPixelContainer();\ void *ptr = static_cast (PixelContainer2##typeN->GetBufferPointer());\ (dynamic_cast( output))->GetPointData()->GetScalars()->SetVoidArray(ptr, PixelContainer2##typeN->Size(), 0);\ PixelContainer2##typeN->ContainerManageMemoryOff();\ }\ break /// END SCALAR MACRO // If there is only one file in the series, just use an image file reader if (this->FileNames.size() == 1) { if (this->GetNumberOfComponents() == 1) { switch (this->OutputScalarType) { vtkvmtkITKExecuteDataFromFile(VTK_DOUBLE, double); vtkvmtkITKExecuteDataFromFile(VTK_FLOAT, float); vtkvmtkITKExecuteDataFromFile(VTK_LONG, long); vtkvmtkITKExecuteDataFromFile(VTK_UNSIGNED_LONG, unsigned long); vtkvmtkITKExecuteDataFromFile(VTK_INT, int); vtkvmtkITKExecuteDataFromFile(VTK_UNSIGNED_INT, unsigned int); vtkvmtkITKExecuteDataFromFile(VTK_SHORT, short); vtkvmtkITKExecuteDataFromFile(VTK_UNSIGNED_SHORT, unsigned short); vtkvmtkITKExecuteDataFromFile(VTK_CHAR, char); vtkvmtkITKExecuteDataFromFile(VTK_UNSIGNED_CHAR, unsigned char); default: vtkErrorMacro(<< "UpdateFromFile: Unknown data type"); } } else { vtkErrorMacro(<< "UpdateFromFile: Unsupported number of components (only 1 allowed): " << this->GetNumberOfComponents()); } } else { if (this->GetNumberOfComponents() == 1) { switch (this->OutputScalarType) { vtkvmtkITKExecuteDataFromSeries(VTK_DOUBLE, double); vtkvmtkITKExecuteDataFromSeries(VTK_FLOAT, float); vtkvmtkITKExecuteDataFromSeries(VTK_LONG, long); vtkvmtkITKExecuteDataFromSeries(VTK_UNSIGNED_LONG, unsigned long); vtkvmtkITKExecuteDataFromSeries(VTK_INT, int); vtkvmtkITKExecuteDataFromSeries(VTK_UNSIGNED_INT, unsigned int); vtkvmtkITKExecuteDataFromSeries(VTK_SHORT, short); vtkvmtkITKExecuteDataFromSeries(VTK_UNSIGNED_SHORT, unsigned short); vtkvmtkITKExecuteDataFromSeries(VTK_CHAR, char); vtkvmtkITKExecuteDataFromSeries(VTK_UNSIGNED_CHAR, unsigned char); default: vtkErrorMacro(<< "UpdateFromFile: Unknown data type"); } } else { vtkErrorMacro(<<"UpdateFromSeries: Unsupported number of components: 1 != " << this->GetNumberOfComponents()); } } } void vtkvmtkITKArchetypeImageSeriesScalarReader::ReadProgressCallback(itk::ProcessObject* obj,const itk::ProgressEvent&,void* data) { vtkvmtkITKArchetypeImageSeriesScalarReader* me=reinterpret_cast(data); me->Progress=obj->GetProgress(); me->InvokeEvent(vtkCommand::ProgressEvent,&me->Progress); } vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterF2F.h0000664000175000017500000000543611757446472024762 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilterF2F.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterF2F_h #define __vtkvmtkITKImageToImageFilterF2F_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterF2F : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterF2F,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterF2F* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; protected: //BTX // To/from ITK typedef itk::Vector InputImagePixelType; typedef float OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterF2F ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToFloat(); }; ~vtkvmtkITKImageToImageFilterF2F() { }; //ETX private: vtkvmtkITKImageToImageFilterF2F(const vtkvmtkITKImageToImageFilterF2F&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterF2F&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesReader.cxx0000664000175000017500000011072211757446472026561 0ustar lucaluca/*========================================================================= 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://svn.slicer.org/Slicer3/trunk/Libs/vtkvmtkITK/vtkvmtkITKArchetypeImageSeriesReader.cxx $ Date: $Date: 2010-01-29 16:40:56 +0100 (Fri, 29 Jan 2010) $ Version: $Revision: 11861 $ ==========================================================================*/ #include "vtkvmtkITKArchetypeImageSeriesReader.h" #include "vtkImageData.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkDataArray.h" #include "itkExceptionObject.h" #include "itkTimeProbe.h" // Commented out redefinition of ExceptionMacro #ifdef REDEFINE_EXCEPTION_MACROS // turn itk exceptions into vtk errors #undef itkExceptionMacro #define itkExceptionMacro(x) \ { \ std::ostringstream message; \ message << "itk::ERROR: " << this->GetNameOfClass() \ << "(" << this << "): " x; \ std::cout << message.str().c_str() << std::endl; \ } #undef itkGenericExceptionMacro #define itkGenericExceptionMacro(x) \ { \ std::ostringstream message; \ message << "itk::ERROR: " x; \ std::cout << message.str().c_str() << std::endl; \ } #endif // // uncomment the define below to enable use of the GE5 (Signa) reader // this is not on by default because the reader does not support // reading directions from the file. // The GE5 reader was fixed just after the itk 3.2 release // //#if (ITK_VERSION_MAJOR > 3) || \ //((ITK_VERSION_MAJOR == 3 && ITK_VERSION_MINOR >= 2)) //#define USE_ITKGE5READER //#endif #ifdef USE_ITKGE5READER #include "itkImageIOFactory.h" #include "itkMutexLock.h" #include "itkMutexLockHolder.h" #include "itkGE5ImageIOFactory.h" #endif #include "itkArchetypeSeriesFileNames.h" #include "itkImage.h" #include "itkVector.h" #include "itkOrientImageFilter.h" #include "itkImageSeriesReader.h" #include "itkImageFileReader.h" #include "itkImportImageContainer.h" #include "itkImageRegion.h" #include "itkGDCMSeriesFileNames.h" #include "itkGDCMImageIO.h" #include "itkMetaImageIO.h" #include "itkNrrdImageIO.h" #include "itkGE5ImageIO.h" //#include "itkBrains2MaskImageIOFactory.h" //#include "itkBrains2MaskImageIO.h" #include "itkNiftiImageIO.h" #include "itkVTKImageIO.h" #include "itkTIFFImageIO.h" #include "itkAnalyzeImageIO.h" #include "itkDICOMImageIO2Factory.h" #include vtkCxxRevisionMacro(vtkvmtkITKArchetypeImageSeriesReader, "$Revision: 11861 $"); vtkStandardNewMacro(vtkvmtkITKArchetypeImageSeriesReader); //---------------------------------------------------------------------------- vtkvmtkITKArchetypeImageSeriesReader::vtkvmtkITKArchetypeImageSeriesReader() { this->Archetype = NULL; this->IndexArchetype = 0; this->SingleFile = 1; this->UseOrientationFromFile = 1; this->RasToIjkMatrix = NULL; this->SetDesiredCoordinateOrientationToAxial(); this->UseNativeCoordinateOrientation = 0; this->FileNameSliceOffset = 0; this->FileNameSliceSpacing = 1; this->FileNameSliceCount = 0; this->UseNativeOrigin = true; this->OutputScalarType = VTK_FLOAT; this->NumberOfComponents = 0; this->UseNativeScalarType = 0; for (int i = 0; i < 3; i++) { this->DefaultDataSpacing[i] = 1.0; this->DefaultDataOrigin[i] = 0.0; } this->SeriesInstanceUIDs.resize( 0 ); this->ContentTime.resize( 0 ); this->TriggerTime.resize( 0 ); this->EchoNumbers.resize( 0 ); this->DiffusionGradientOrientation.resize( 0 ); this->SliceLocation.resize( 0 ); this->ImageOrientationPatient.resize( 0 ); this->AnalyzeHeader = true; this->GroupingByTags = false; this->IsOnlyFile = false; this->SelectedUID = -1; this->SelectedContentTime = -1; this->SelectedTriggerTime = -1; this->SelectedEchoNumbers = -1; this->SelectedDiffusion = -1; this->SelectedSlice = -1; this->SelectedOrientation = -1; // make sure ITK built-in factories are registered, // then register the extra ones and unregister the // ones we don't want itk::ImageIOFactory::RegisterBuiltInFactories(); this->RegisterExtraBuiltInFactories(); this->UnRegisterDeprecatedBuiltInFactories(); } // // ITK internally does not register all of the IO types that get built // (possibly due to lingering bugs?) but many slicer users have // GE5 (Signa - magic number: IMGF) files that they need to work // with so we register the factory explictly here // void vtkvmtkITKArchetypeImageSeriesReader::RegisterExtraBuiltInFactories() { #ifdef USE_ITKGE5READER static bool firstTime = true; static itk::SimpleMutexLock mutex; { // This helper class makes sure the Mutex is unlocked // in the event an exception is thrown. itk::MutexLockHolder mutexHolder( mutex ); if( firstTime ) { itk::ObjectFactoryBase::RegisterFactory( itk::Brains2MaskImageIOFactory::New() ); itk::ObjectFactoryBase::RegisterFactory( itk::GE5ImageIOFactory::New() ); firstTime = false; } } #endif } // // ITK includes some old/unwanted IO Factories that cause // incorrect parsing of dicom files in some circumstances // void vtkvmtkITKArchetypeImageSeriesReader::UnRegisterDeprecatedBuiltInFactories() { static bool firstTime = true; if (!firstTime) { return; } firstTime = false; std::list registeredFactories = itk::ObjectFactoryBase::GetRegisteredFactories(); itk::DICOMImageIO2Factory *dicomIO = NULL; for ( std::list::iterator i = registeredFactories.begin(); i != registeredFactories.end(); ++i ) { dicomIO = dynamic_cast(*i); if ( dicomIO ) { break; } } if ( dicomIO ) { itk::ObjectFactoryBase::UnRegisterFactory( dicomIO ); } else { vtkErrorMacro("Could not find dicomIO factory to unregister"); } } //---------------------------------------------------------------------------- vtkvmtkITKArchetypeImageSeriesReader::~vtkvmtkITKArchetypeImageSeriesReader() { if (this->Archetype) { delete [] this->Archetype; this->Archetype = NULL; } if (RasToIjkMatrix) { RasToIjkMatrix->Delete(); RasToIjkMatrix = NULL; } } vtkMatrix4x4* vtkvmtkITKArchetypeImageSeriesReader::GetRasToIjkMatrix() { this->UpdateInformation(); return RasToIjkMatrix; } //---------------------------------------------------------------------------- void vtkvmtkITKArchetypeImageSeriesReader::PrintSelf(ostream& os, vtkIndent indent) { int idx; this->Superclass::PrintSelf(os,indent); os << indent << "Archetype: " << (this->Archetype ? this->Archetype : "(none)") << "\n"; os << indent << "FileNameSliceOffset: " << this->FileNameSliceOffset << "\n"; os << indent << "FileNameSliceSpacing: " << this->FileNameSliceSpacing << "\n"; os << indent << "FileNameSliceCount: " << this->FileNameSliceCount << "\n"; os << indent << "OutputScalarType: " << vtkImageScalarTypeNameMacro(this->OutputScalarType) << std::endl; os << indent << "DefaultDataSpacing: (" << this->DefaultDataSpacing[0]; for (idx = 1; idx < 3; ++idx) { os << ", " << this->DefaultDataSpacing[idx]; } os << ")\n"; os << indent << "DefaultDataOrigin: (" << this->DefaultDataOrigin[0]; for (idx = 1; idx < 3; ++idx) { os << ", " << this->DefaultDataOrigin[idx]; } os << ")\n"; } int vtkvmtkITKArchetypeImageSeriesReader::CanReadFile(const char* vtkNotUsed(filename)) { std::string fileNameCollapsed = itksys::SystemTools::CollapseFullPath( this->Archetype); // First see if the archetype exists if (!itksys::SystemTools::FileExists (fileNameCollapsed.c_str())) { vtkDebugMacro(<<"The filename does not exist."); return false; } return true; } //---------------------------------------------------------------------------- // This method returns the largest data that can be generated. void vtkvmtkITKArchetypeImageSeriesReader::ExecuteInformation() { vtkImageData *output = this->GetOutput(); std::vector candidateFiles; std::vector candidateSeries; int extent[6]; std::string fileNameCollapsed = itksys::SystemTools::CollapseFullPath( this->Archetype); if ( this->SingleFile ) { this->AnalyzeHeader = false; } // Since we only need origin, spacing and extents, we can use one // image type. typedef itk::Image ImageType; itk::ImageRegion<3> region; typedef itk::ImageSource FilterType; FilterType::Pointer filter; // First see if the archetype exists, if it's not a pointer into memory if (fileNameCollapsed.find("slicer:0x") != std::string::npos && fileNameCollapsed.find("#") != std::string::npos) { vtkDebugMacro("File " << fileNameCollapsed.c_str() << " is a pointer to the mrml scene in memory, not checking for it on disk"); } else { if (!itksys::SystemTools::FileExists (fileNameCollapsed.c_str())) { itkGenericExceptionMacro ( "vtkvmtkITKArchetypeImageSeriesReader::ExecuteInformation: Archetype file " << fileNameCollapsed.c_str() << " does not exist."); return; } } this->AllFileNames.resize( 0 ); // Some file types require special processing itk::GDCMImageIO::Pointer dicomIO = itk::GDCMImageIO::New(); // Test whether the input file is a DICOM file bool isDicomFile = dicomIO->CanReadFile(this->Archetype); // if user already set up FileNames, we do not try to find candidate files if ( this->GetNumberOfFileNames() > 0 ) { unsigned int nFiles = this->GetNumberOfFileNames(); this->AllFileNames.resize( 0 ); for (unsigned int k = 0; k < nFiles; k++) { this->AllFileNames.push_back( this->FileNames[k] ); } this->FileNames.resize( 0 ); // if this is the only file set by user if (nFiles == 1) { this->IsOnlyFile = true; } // if we need to analyze the header if ( AnalyzeHeader ) { this->AnalyzeDicomHeaders(); } } else { if ( isDicomFile && !this->GetSingleFile() ) { typedef itk::GDCMSeriesFileNames DICOMNameGeneratorType; DICOMNameGeneratorType::Pointer inputImageFileGenerator = DICOMNameGeneratorType::New(); std::string fileNameName = itksys::SystemTools::GetFilenameName( this->Archetype ); std::string fileNamePath = itksys::SystemTools::GetFilenamePath( this->Archetype ); if (fileNamePath == "") { fileNamePath = "."; } inputImageFileGenerator->SetDirectory( fileNamePath ); // determine if the file is diffusion weighted MR file // Find the series that contains the archetype candidateSeries = inputImageFileGenerator->GetSeriesUIDs(); // Find all dicom files in the directory for (unsigned int s = 0; s < candidateSeries.size(); s++) { std::vector seriesFileNames; seriesFileNames = inputImageFileGenerator->GetFileNames( candidateSeries[s] ); for (unsigned int f = 0; f < seriesFileNames.size(); f++) { this->AllFileNames.push_back( seriesFileNames[f] ); } } //int nFiles = this->AllFileNames.size(); UNUSED // analysis dicom files and fill the Dicom Tag arrays if ( AnalyzeHeader ) { this->AnalyzeDicomHeaders(); } // the following for loop set up candidate files with same series number // that include the given Archetype; int found = 0; for (unsigned int s = 0; s < candidateSeries.size() && found == 0; s++) { candidateFiles = inputImageFileGenerator->GetFileNames(candidateSeries[s]); for (unsigned int f = 0; f < candidateFiles.size(); f++) { if (itksys::SystemTools::CollapseFullPath(candidateFiles[f].c_str()) == fileNameCollapsed) { found = 1; break; } } } // do we have just one candidate file if ( candidateFiles.size() == 1 ) { this->IsOnlyFile = true; } } else if( !this->GetSingleFile() ) { // not dicom // check the dimensions of the archetype - if there // is more then one slice, use only the archetype // but if it is a single slice, try to generate a // series of filenames itk::ImageFileReader::Pointer imageReader = itk::ImageFileReader::New(); imageReader->SetFileName(this->Archetype); imageReader->UpdateOutputInformation(); region = imageReader->GetOutput()->GetLargestPossibleRegion(); if ( region.GetSize()[2] > 1 ) { candidateFiles.push_back( this->Archetype ); this->AllFileNames.push_back( this->Archetype ); this->IsOnlyFile = true; } else { // Generate filenames from the Archetype itk::ArchetypeSeriesFileNames::Pointer fit = itk::ArchetypeSeriesFileNames::New(); fit->SetArchetype (this->Archetype); candidateFiles = fit->GetFileNames(); this->AllFileNames.resize( candidateFiles.size() ); for (int f = 0; f < (int)(candidateFiles.size()); f ++) { this->AllFileNames[f] = candidateFiles[f]; } if ( candidateFiles.size() == 1 ) { this->IsOnlyFile = true; } else if ( AnalyzeHeader ) { this->AnalyzeDicomHeaders(); } } } else { this->AllFileNames.push_back( this->Archetype ); this->IsOnlyFile = true; } } // figure out the index of Archetype in AllFileNames for (unsigned int k = 0; k < this->AllFileNames.size(); k++) { if (this->AllFileNames[k] == this->Archetype) { this->IndexArchetype = k; break; } } // Reduce the selection of filenames if ( this->IsOnlyFile || this->SingleFile ) { this->FileNames.resize( 0 ); this->FileNames.push_back( this->Archetype ); } else { if ( !GroupingByTags ) { AssembleVolumeContainingArchetype(); } else { GroupFiles( SelectedUID, SelectedContentTime, SelectedTriggerTime, SelectedEchoNumbers, SelectedDiffusion, SelectedSlice, SelectedOrientation ); } } if (RasToIjkMatrix) { RasToIjkMatrix->Delete(); } RasToIjkMatrix = vtkMatrix4x4::New(); vtkMatrix4x4* IjkToLpsMatrix = vtkMatrix4x4::New(); RasToIjkMatrix->Identity(); IjkToLpsMatrix->Identity(); double spacing[3]; double origin[3]; itk::ImageIOBase::Pointer imageIO = NULL; try { // If there is only one file in the series, just use an image file reader if (this->FileNames.size() == 1) { itk::OrientImageFilter::Pointer orient = itk::OrientImageFilter::New(); itk::ImageFileReader::Pointer imageReader = itk::ImageFileReader::New(); imageReader->SetFileName(this->FileNames[0].c_str()); if (isDicomFile) { imageReader->SetImageIO(dicomIO); } if (this->UseNativeCoordinateOrientation) { imageReader->UpdateOutputInformation(); filter = imageReader; } else { orient->SetInput(imageReader->GetOutput()); orient->UseImageDirectionOn(); orient->SetDesiredCoordinateOrientation(this->DesiredCoordinateOrientation); orient->UpdateOutputInformation(); filter = orient; } for (int i = 0; i < 3; i++) { spacing[i] = filter->GetOutput()->GetSpacing()[i]; origin[i] = filter->GetOutput()->GetOrigin()[i]; // Get IJK to RAS direction vector for ( unsigned int j=0; j < filter->GetOutput()->GetImageDimension (); j++ ) { IjkToLpsMatrix->SetElement(j, i, spacing[i]*filter->GetOutput()->GetDirection()[j][i]); } } region = filter->GetOutput()->GetLargestPossibleRegion(); extent[0] = region.GetIndex()[0]; extent[1] = region.GetIndex()[0] + region.GetSize()[0] - 1; extent[2] = region.GetIndex()[1]; extent[3] = region.GetIndex()[1] + region.GetSize()[1] - 1; extent[4] = region.GetIndex()[2]; extent[5] = region.GetIndex()[2] + region.GetSize()[2] - 1; imageIO = imageReader->GetImageIO(); if (imageIO.GetPointer() == NULL) { itkGenericExceptionMacro ( "vtkvmtkITKArchetypeImageSeriesReader::ExecuteInformation: ImageIO for file " << fileNameCollapsed.c_str() << " does not exist."); return; } } else { itk::OrientImageFilter::Pointer orient = itk::OrientImageFilter::New(); itk::ImageSeriesReader::Pointer seriesReader = itk::ImageSeriesReader::New(); seriesReader->SetFileNames(this->FileNames); if (isDicomFile) { seriesReader->SetImageIO(dicomIO); } else { itk::ImageFileReader::Pointer imageReader = itk::ImageFileReader::New(); imageReader->SetFileName(this->FileNames[0].c_str()); imageReader->UpdateOutputInformation(); imageIO = imageReader->GetImageIO(); seriesReader->SetImageIO(imageIO); } if (this->UseNativeCoordinateOrientation) { seriesReader->UpdateOutputInformation(); filter = seriesReader; } else { orient->SetInput(seriesReader->GetOutput()); orient->UseImageDirectionOn(); orient->SetDesiredCoordinateOrientation(this->DesiredCoordinateOrientation); orient->UpdateOutputInformation(); filter = orient; } for (int i = 0; i < 3; i++) { spacing[i] = filter->GetOutput()->GetSpacing()[i]; origin[i] = filter->GetOutput()->GetOrigin()[i]; // Get IJK to RAS direction vector for ( unsigned int j=0; j < filter->GetOutput()->GetImageDimension (); j++ ) { IjkToLpsMatrix->SetElement(j, i, spacing[i]*filter->GetOutput()->GetDirection()[j][i]); } } region = filter->GetOutput()->GetLargestPossibleRegion(); extent[0] = region.GetIndex()[0]; extent[1] = region.GetIndex()[0] + region.GetSize()[0] - 1; extent[2] = region.GetIndex()[1]; extent[3] = region.GetIndex()[1] + region.GetSize()[1] - 1; extent[4] = region.GetIndex()[2]; extent[5] = region.GetIndex()[2] + region.GetSize()[2] - 1; imageIO = seriesReader->GetImageIO(); } } catch (...) { IjkToLpsMatrix->Delete(); itkGenericExceptionMacro ( "vtkvmtkITKArchetypeImageSeriesReader::ExecuteInformation: Cannot open " << fileNameCollapsed.c_str() << "."); return; } // Transform from LPS to RAS vtkMatrix4x4* LpsToRasMatrix = vtkMatrix4x4::New(); LpsToRasMatrix->Identity(); LpsToRasMatrix->SetElement(0,0,-1); LpsToRasMatrix->SetElement(1,1,-1); vtkMatrix4x4::Multiply4x4(LpsToRasMatrix,IjkToLpsMatrix, RasToIjkMatrix); LpsToRasMatrix->Delete(); // If it looks like the pipeline did not provide the spacing and // origin, modify the spacing and origin with the defaults for (int j = 0; j < 3; j++) { if (spacing[j] == 1.0) { spacing[j] = this->DefaultDataSpacing[j]; } if (origin[j] == 0.0) { origin[j] = this->DefaultDataOrigin[j]; } } origin[0] *= -1; // L -> R origin[1] *= -1; // P -> A if (this->UseNativeOrigin) { for (int j = 0; j < 3; j++) { RasToIjkMatrix->SetElement(j, 3, origin[j]); } RasToIjkMatrix->Invert(); } else { RasToIjkMatrix->Invert(); for (int j = 0; j < 3; j++) { RasToIjkMatrix->SetElement(j, 3, (extent[2*j+1] - extent[2*j])/2.0); } } output->SetSpacing(spacing); output->SetOrigin(origin); RasToIjkMatrix->SetElement(3,3,1.0); IjkToLpsMatrix->Delete(); if ( !this->GetUseOrientationFromFile() ) { RasToIjkMatrix->Identity(); for ( unsigned int j=0; j < 3; j++ ) { RasToIjkMatrix->SetElement(j, j, 1.0/spacing[j]); } } output->SetWholeExtent(extent); if (this->UseNativeScalarType) { if (imageIO.GetPointer() == NULL) { this->SetOutputScalarType(VTK_SHORT); // TODO - figure out why multi-file series doen't have an imageIO } else if (imageIO->GetComponentType() == itk::ImageIOBase::UCHAR) { this->SetOutputScalarType(VTK_UNSIGNED_CHAR); } else if (imageIO->GetComponentType() == itk::ImageIOBase::CHAR) { this->SetOutputScalarType(VTK_CHAR); } else if (imageIO->GetComponentType() == itk::ImageIOBase::USHORT) { this->SetOutputScalarType(VTK_UNSIGNED_SHORT); } else if (imageIO->GetComponentType() == itk::ImageIOBase::SHORT) { this->SetOutputScalarType(VTK_SHORT); } else if (imageIO->GetComponentType() == itk::ImageIOBase::UINT) { this->SetOutputScalarType(VTK_UNSIGNED_INT); } else if (imageIO->GetComponentType() == itk::ImageIOBase::INT) { this->SetOutputScalarType(VTK_INT); } else if (imageIO->GetComponentType() == itk::ImageIOBase::ULONG) { this->SetOutputScalarType(VTK_UNSIGNED_LONG); } else if (imageIO->GetComponentType() == itk::ImageIOBase::LONG) { this->SetOutputScalarType(VTK_LONG); } else if (imageIO->GetComponentType() == itk::ImageIOBase::FLOAT) { this->SetOutputScalarType(VTK_FLOAT); } else if (imageIO->GetComponentType() == itk::ImageIOBase::DOUBLE) { this->SetOutputScalarType(VTK_DOUBLE); } } if (imageIO.GetPointer() == NULL) { this->SetNumberOfComponents(1); } else { this->SetNumberOfComponents(imageIO->GetNumberOfComponents()); } output->SetScalarType(this->OutputScalarType); output->SetNumberOfScalarComponents(this->GetNumberOfComponents()); // Copy the MetaDataDictionary from the ITK layer to the VTK layer if (imageIO.GetPointer() != NULL) { this->Dictionary = imageIO->GetMetaDataDictionary(); } else { this->Dictionary = itk::MetaDataDictionary(); } ParseDictionary(); } //---------------------------------------------------------------------------- void vtkvmtkITKArchetypeImageSeriesReader::AssembleNthVolume ( int n ) { this->FileNames.resize( 0 ); // int nFiles = this->AllFileNames.size(); UNUSED unsigned int nSlices = this->GetNumberOfSliceLocation(); for (unsigned int k = 0; k < nSlices; k++) { const char* name = GetNthFileName( 0, -1, -1, -1, 0, k, 0, n ); if (name == NULL) { continue; } std::string nameInString (name); this->FileNames.push_back(nameInString); } } //---------------------------------------------------------------------------- const char* vtkvmtkITKArchetypeImageSeriesReader::GetNthFileName ( int idxSeriesInstanceUID, int idxContentTime, int idxTriggerTime, int idxEchoNumbers, int idxDiffusionGradientOrientation, int idxSliceLocation, int idxImageOrientationPatient, int n ) { int nFiles = this->AllFileNames.size(); int count = 0; std::string FirstName; for (int k = 0; k < nFiles; k++) { if ( (this->IndexSeriesInstanceUIDs[k] != idxSeriesInstanceUID && this->IndexSeriesInstanceUIDs[k] >= 0 && idxSeriesInstanceUID >= 0) || (this->IndexContentTime[k] != idxContentTime && this->IndexContentTime[k] >= 0 && idxContentTime >= 0) || (this->IndexTriggerTime[k] != idxTriggerTime && this->IndexTriggerTime[k] >= 0 && idxTriggerTime >= 0) || (this->IndexEchoNumbers[k] != idxEchoNumbers && this->IndexEchoNumbers[k] >= 0 && idxEchoNumbers >= 0) || (this->IndexDiffusionGradientOrientation[k] != idxDiffusionGradientOrientation && this->IndexDiffusionGradientOrientation[k] >= 0 && idxDiffusionGradientOrientation >= 0) || (this->IndexSliceLocation[k] != idxSliceLocation && this->IndexSliceLocation[k] >= 0 && idxSliceLocation >= 0) || (this->IndexImageOrientationPatient[k] != idxImageOrientationPatient && this->IndexImageOrientationPatient[k] >= 0 && idxImageOrientationPatient >= 0) ) { continue; } else { if (count == n) { return this->AllFileNames[k].c_str(); } else if( count == 0 ) { FirstName = this->AllFileNames[k]; count ++; } else { count ++; } } } return NULL; } //---------------------------------------------------------------------------- void vtkvmtkITKArchetypeImageSeriesReader::GroupFiles ( int idxSeriesInstanceUID, int idxContentTime, int idxTriggerTime, int idxEchoNumbers, int idxDiffusionGradientOrientation, int idxSliceLocation, int idxImageOrientationPatient ) { this->FileNames.resize( 0 ); int nFiles = this->AllFileNames.size(); for (int k = 0; k < nFiles; k++) { if ( (this->IndexSeriesInstanceUIDs[k] != idxSeriesInstanceUID && this->IndexSeriesInstanceUIDs[k] >= 0 && idxSeriesInstanceUID >= 0) || (this->IndexContentTime[k] != idxContentTime && this->IndexContentTime[k] >= 0 && idxContentTime >= 0) || (this->IndexTriggerTime[k] != idxTriggerTime && this->IndexTriggerTime[k] >= 0 && idxTriggerTime >= 0) || (this->IndexEchoNumbers[k] != idxEchoNumbers && this->IndexEchoNumbers[k] >= 0 && idxEchoNumbers >= 0) || (this->IndexDiffusionGradientOrientation[k] != idxDiffusionGradientOrientation && this->IndexDiffusionGradientOrientation[k] >= 0 && idxDiffusionGradientOrientation >= 0) || (this->IndexSliceLocation[k] != idxSliceLocation && this->IndexSliceLocation[k] >= 0 && idxSliceLocation >= 0) || (this->IndexImageOrientationPatient[k] != idxImageOrientationPatient && this->IndexImageOrientationPatient[k] >= 0 && idxImageOrientationPatient >= 0) ) { continue; } else { this->FileNames.push_back( this->AllFileNames[k] ); } } return; } void vtkvmtkITKArchetypeImageSeriesReader::AnalyzeDicomHeaders() { itk::TimeProbe AnalyzeTime; AnalyzeTime.Start(); int nFiles = this->AllFileNames.size(); typedef itk::Image ImageType; this->IndexSeriesInstanceUIDs.resize( nFiles ); this->IndexContentTime.resize( nFiles ); this->IndexTriggerTime.resize( nFiles ); this->IndexEchoNumbers.resize( nFiles ); this->IndexDiffusionGradientOrientation.resize( nFiles ); this->IndexSliceLocation.resize( nFiles ); this->IndexImageOrientationPatient.resize( nFiles ); this->SeriesInstanceUIDs.resize( 0 ); this->ContentTime.resize( 0 ); this->TriggerTime.resize( 0 ); this->EchoNumbers.resize( 0 ); this->DiffusionGradientOrientation.resize( 0 ); this->SliceLocation.resize( 0 ); this->ImageOrientationPatient.resize( 0 ); itk::GDCMImageIO::Pointer gdcmIO = itk::GDCMImageIO::New(); if ( !gdcmIO->CanReadFile(this->Archetype) ) { for (int f = 0; f < nFiles; f++) { itk::ImageFileReader::Pointer imageReader = itk::ImageFileReader::New(); imageReader->SetFileName( this->AllFileNames[f] ); imageReader->UpdateOutputInformation(); // insert series int idx = InsertSeriesInstanceUIDs( "Non-Dicom Series" ); this->IndexSeriesInstanceUIDs[f] = idx; // for now, assume ContentTime, TriggerTime, and DiffusionGradientOrientation do not exist this->IndexContentTime[f] = -1; this->IndexTriggerTime[f] = -1; this->IndexEchoNumbers[f] = -1; this->IndexDiffusionGradientOrientation[f] = -1; // Slice Location ImageType::PointType origin = imageReader->GetOutput()->GetOrigin(); std::string IOType = imageReader->GetImageIO()->GetNameOfClass(); if( IOType.find("BPMImageIO") == std::string::npos || IOType.find("JPEGImageIO") == std::string::npos || IOType.find("PNGImageIO") == std::string::npos || IOType.find("TIFFImageIO") == std::string::npos || IOType.find("RawImageIO") == std::string::npos ) { idx = InsertSliceLocation( static_cast(f) ); this->IndexSliceLocation[f] = idx; } else { idx = InsertSliceLocation( origin[2] ); this->IndexSliceLocation[f] = idx; } // Orientation ImageType::DirectionType orientation = imageReader->GetOutput()->GetDirection(); float a[6]; for (int k = 0; k < 3; k++) { a[k] = orientation[0][k]; a[k+3] = orientation[1][k]; } idx = InsertImageOrientationPatient( a ); this->IndexImageOrientationPatient[f] = idx; } return; } // if Archetype is a Dicom File gdcmIO->SetFileName( this->Archetype ); for (int f = 0; f < nFiles; f++) { gdcmIO->SetFileName( this->AllFileNames[f] ); gdcmIO->ReadImageInformation(); itk::MetaDataDictionary &dict = gdcmIO->GetMetaDataDictionary(); std::string tagValue; // series instance UID tagValue.clear(); itk::ExposeMetaData( dict, "0020|000e", tagValue ); if ( tagValue.length() > 0 ) { int idx = InsertSeriesInstanceUIDs( tagValue.c_str() ); this->IndexSeriesInstanceUIDs[f] = idx; } else { this->IndexSeriesInstanceUIDs[f] = -1; } // content time tagValue.clear(); itk::ExposeMetaData( dict, "0008|0033", tagValue ); if ( tagValue.length() > 0 ) { int idx = InsertContentTime( tagValue.c_str() ); this->IndexContentTime[f] = idx; } else { this->IndexContentTime[f] = -1; } // trigger time tagValue.clear(); itk::ExposeMetaData( dict, "0018|1060", tagValue ); if ( tagValue.length() > 0 ) { int idx = InsertTriggerTime( tagValue.c_str() ); this->IndexTriggerTime[f] = idx; } else { this->IndexTriggerTime[f] = -1; } // echo numbers tagValue.clear(); itk::ExposeMetaData( dict, "0018|0086", tagValue ); if ( tagValue.length() > 0 ) { int idx = InsertEchoNumbers( tagValue.c_str() ); this->IndexEchoNumbers[f] = idx; } else { this->IndexEchoNumbers[f] = -1; } // diffision gradient orientation tagValue.clear(); itk::ExposeMetaData( dict, "0010|9089", tagValue ); if ( tagValue.length() > 0 ) { float a[3]; sscanf( tagValue.c_str(), "%f\\%f\\%f", a, a+1, a+2 ); int idx = InsertDiffusionGradientOrientation( a ); this->IndexDiffusionGradientOrientation[f] = idx; } else { this->IndexDiffusionGradientOrientation[f] = -1; } // slice location tagValue.clear(); itk::ExposeMetaData( dict, "0020|1041", tagValue ); if ( tagValue.length() > 0 ) { float a; sscanf( tagValue.c_str(), "%f", &a ); int idx = InsertSliceLocation( a ); this->IndexSliceLocation[f] = idx; } else { this->IndexSliceLocation[f] = -1; } // image orientation patient tagValue.clear(); itk::ExposeMetaData( dict, "0020|0037", tagValue ); if ( tagValue.length() > 0 ) { float a[6]; sscanf( tagValue.c_str(), "%f\\%f\\%f\\%f\\%f\\%f", a, a+1, a+2, a+3, a+4, a+5 ); int idx = InsertImageOrientationPatient( a ); this->IndexImageOrientationPatient[f] = idx; } else { this->IndexImageOrientationPatient[f] = -1; } } AnalyzeTime.Stop(); // double timeelapsed = AnalyzeTime.GetMeanTime(); UNUSED AnalyzeHeader = false; return; } //---------------------------------------------------------------------------- // This function reads a data from a file. The datas extent/axes // are assumed to be the same as the file extent/order. // implemented in the Scalar and Vector subclasses void vtkvmtkITKArchetypeImageSeriesReader::ExecuteData(vtkDataObject *vtkNotUsed(output)) { vtkWarningMacro(<<"The subclass has not defined anything for ExecuteData!\n"); } const itk::MetaDataDictionary& vtkvmtkITKArchetypeImageSeriesReader ::GetMetaDataDictionary() const { return this->Dictionary; } void vtkvmtkITKArchetypeImageSeriesReader::ParseDictionary() { int nItems = this->Dictionary.GetKeys().size(); this->Tags.resize(0); this->TagValues.resize(0); if (nItems == 0) { return; } std::vector keys = this->Dictionary.GetKeys(); for (int k = 0; k < nItems; k++) { this->Tags.push_back( keys[k] ); std::string tagvalue; itk::ExposeMetaData(this->Dictionary, keys[k], tagvalue); this->TagValues.push_back( tagvalue ); } } unsigned int vtkvmtkITKArchetypeImageSeriesReader::GetNumberOfItemsInDictionary() { return this->Tags.size(); } bool vtkvmtkITKArchetypeImageSeriesReader::HasKey( char* tag ) { return this->Dictionary.HasKey( tag ); } const char* vtkvmtkITKArchetypeImageSeriesReader::GetNthKey( unsigned int n ) { if (n >= this->Tags.size()) { return NULL; } return this->Tags[n].c_str(); } const char* vtkvmtkITKArchetypeImageSeriesReader::GetNthValue( unsigned int n ) { if (n >= this->TagValues.size()) { return NULL; } return this->TagValues[n].c_str(); } const char* vtkvmtkITKArchetypeImageSeriesReader::GetTagValue( char* tag ) { std::string tagstr (tag); for (unsigned int k = 0; k < this->Tags.size(); k++) { if (this->Tags[k] == tagstr) { return this->TagValues[k].c_str(); } } return NULL; } const char* vtkvmtkITKArchetypeImageSeriesReader::GetFileName( unsigned int n ) { if ( n >= this->GetNumberOfFileNames() ) { return NULL; } return this->FileNames[n].c_str(); } unsigned int vtkvmtkITKArchetypeImageSeriesReader::AddFileName( const char* filename ) { std::string filenamestr (filename); this->FileNames.push_back( filenamestr ); return this->FileNames.size(); } void vtkvmtkITKArchetypeImageSeriesReader::ResetFileNames( ) { this->FileNames.resize( 0 ); } int vtkvmtkITKArchetypeImageSeriesReader::AssembleVolumeContainingArchetype( ) { this->FileNames.resize(0); // Note: Since IndexArchetype is unsigned int, it's always postive if (this->IndexArchetype > this->IndexSeriesInstanceUIDs.size() || this->IndexArchetype > this->IndexTriggerTime.size() || this->IndexArchetype > this->IndexDiffusionGradientOrientation.size() || this->IndexArchetype > this->IndexImageOrientationPatient.size()) { vtkErrorMacro("AssembleVolumeContainingArchetype: index archetype " << this->IndexArchetype << " is out of bounds 0-" << this->IndexSeriesInstanceUIDs.size()); return 0; } long int iArchetypeSeriesUID = this->IndexSeriesInstanceUIDs[this->IndexArchetype]; //long int iArchetypeContentTime = //this->IndexContentTime[this->IndexArchetype]; long int iArchetypeEchoNumbers = this->IndexEchoNumbers[this->IndexArchetype]; long int iArchetypeDiffusion = this->IndexDiffusionGradientOrientation[this->IndexArchetype]; long int iArchetypeOrientation = this->IndexImageOrientationPatient[this->IndexArchetype]; for (unsigned int k = 0; k < this->AllFileNames.size(); k++) { if ( (this->IndexSeriesInstanceUIDs[k] != iArchetypeSeriesUID && this->IndexSeriesInstanceUIDs[k] >= 0 && iArchetypeSeriesUID >= 0) || //(this->IndexContentTime[k] != iArchetypeContentTime && this->IndexContentTime[k] >= 0 && iArchetypeContentTime >= 0) || //(this->IndexTriggerTime[k] != iArchetypeTriggerTime && this->IndexTriggerTime[k] >= 0 && iArchetypeTriggerTime >= 0) || (this->IndexEchoNumbers[k] != iArchetypeEchoNumbers && this->IndexEchoNumbers[k] >= 0 && iArchetypeEchoNumbers >= 0) || (this->IndexDiffusionGradientOrientation[k] != iArchetypeDiffusion && this->IndexDiffusionGradientOrientation[k] >= 0 && iArchetypeDiffusion >= 0) || (this->IndexImageOrientationPatient[k] != iArchetypeOrientation && this->IndexImageOrientationPatient[k] >= 0 && iArchetypeOrientation >= 0) ) { continue; } else { this->FileNames.push_back( this->AllFileNames[k] ); } } return this->FileNames.size(); } vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilterSUL.h0000664000175000017500000000546311757446472025050 0ustar lucaluca/*========================================================================= Program: Insight Segmentation & Registration Toolkit Language: C++ 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. =========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterSUL_h #define __vtkvmtkITKImageToImageFilterSUL_h #include "vtkImageToImageFilter.h" #include "vtkvmtkITKImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilterSUL : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilterSUL,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilterSUL* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; virtual void SetReleaseDataFlag(int f) { Superclass::SetReleaseDataFlag(f); m_Filter->SetReleaseDataFlag(f); } protected: //BTX // To/from ITK typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter FilterType; FilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilterSUL ( FilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToShort(); }; ~vtkvmtkITKImageToImageFilterSUL() { }; //ETX private: vtkvmtkITKImageToImageFilterSUL(const vtkvmtkITKImageToImageFilterSUL&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilterSUL&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageWriter.h0000775000175000017500000000430411757446472023241 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageWriter.h $ Date: $Date: 2006-12-21 07:21:52 -0500 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageWriter_h #define __vtkvmtkITKImageWriter_h #include "vtkProcessObject.h" #include "vtkImageData.h" #include "vtkObjectFactory.h" #include "vtkMatrix4x4.h" #include "vtkvmtkITK.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageWriter : public vtkProcessObject { public: static vtkvmtkITKImageWriter *New(); vtkTypeRevisionMacro(vtkvmtkITKImageWriter,vtkProcessObject); void PrintSelf(ostream& os, vtkIndent indent); // Description: // Specify file name for the image file. You should specify either // a FileName or a FilePrefix. Use FilePrefix if the data is stored // in multiple files. void SetFileName(const char *); char *GetFileName() { return FileName; } // Description: // use compression if possible vtkGetMacro (UseCompression, int); vtkSetMacro (UseCompression, int); // Description: // Set/Get the input object from the image pipeline. void SetInput(vtkImageData *input); vtkImageData *GetInput(); // Description: // The main interface which triggers the writer to start. void Write(); // Set orienation matrix void SetRasToIJKMatrix( vtkMatrix4x4* mat) { RasToIJKMatrix = mat; } protected: vtkvmtkITKImageWriter(); ~vtkvmtkITKImageWriter(); char *FileName; vtkMatrix4x4* RasToIJKMatrix; int UseCompression; private: vtkvmtkITKImageWriter(const vtkvmtkITKImageWriter&); // Not implemented. void operator=(const vtkvmtkITKImageWriter&); // Not implemented. }; //vtkStandardNewMacro(vtkvmtkITKImageWriter) #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageToImageFilter2DFF.h0000664000175000017500000000542711757446472025066 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageToImageFilter2DFF.h $ Date: $Date: 2006-12-21 13:21:52 +0100 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ // .NAME vtkvmtkITKImageToImageFilter - Abstract base class for connecting ITK and VTK // .SECTION Description // vtkvmtkITKImageToImageFilter provides a #ifndef __vtkvmtkITKImageToImageFilterFF_h #define __vtkvmtkITKImageToImageFilterFF_h #include "vtkvmtkITKImageToImageFilter.h" #include "vtkImageToImageFilter.h" #include "itkImageToImageFilter.h" #include "itkVTKImageExport.h" #include "itkVTKImageImport.h" #include "vtkvmtkITKUtility.h" class VTK_VMTK_ITK_EXPORT vtkvmtkITKImageToImageFilter2DFF : public vtkvmtkITKImageToImageFilter { public: vtkTypeMacro(vtkvmtkITKImageToImageFilter2DFF,vtkvmtkITKImageToImageFilter); static vtkvmtkITKImageToImageFilter2DFF* New() { return 0; }; void PrintSelf(ostream& os, vtkIndent indent) { Superclass::PrintSelf ( os, indent ); os << m_Filter; }; protected: //BTX // To/from ITK typedef float InputImagePixelType; typedef float OutputImagePixelType; typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::VTKImageImport ImageImportType; typedef itk::VTKImageExport ImageExportType; ImageImportType::Pointer itkImporter; ImageExportType::Pointer itkExporter; typedef itk::ImageToImageFilter GenericFilterType; GenericFilterType::Pointer m_Filter; vtkvmtkITKImageToImageFilter2DFF ( GenericFilterType* filter ) { // Need an import, export, and a ITK pipeline m_Filter = filter; this->itkImporter = ImageImportType::New(); this->itkExporter = ImageExportType::New(); ConnectPipelines(this->vtkExporter, this->itkImporter); ConnectPipelines(this->itkExporter, this->vtkImporter); this->LinkITKProgressToVTKProgress ( m_Filter ); // Set up the filter pipeline m_Filter->SetInput ( this->itkImporter->GetOutput() ); this->itkExporter->SetInput ( m_Filter->GetOutput() ); this->vtkCast->SetOutputScalarTypeToFloat (); }; ~vtkvmtkITKImageToImageFilter2DFF() { }; //ETX private: vtkvmtkITKImageToImageFilter2DFF(const vtkvmtkITKImageToImageFilter2DFF&); // Not implemented. void operator=(const vtkvmtkITKImageToImageFilter2DFF&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/Utilities/vtkvmtkITK/vtkvmtkITKImageWriter.cxx0000775000175000017500000003245311757446472023622 0ustar lucaluca/*========================================================================= 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/vtkvmtkITKImageWriter.cxx $ Date: $Date: 2006-12-21 07:21:52 -0500 (Thu, 21 Dec 2006) $ Version: $Revision: 1900 $ ==========================================================================*/ #include "vtkvmtkITKImageWriter.h" #include #include "vtkImageExport.h" #include "vtkImageFlip.h" #include "itkVTKImageImport.h" #include "itkImageFileWriter.h" #include "vtkvmtkITKUtility.h" vtkStandardNewMacro(vtkvmtkITKImageWriter); vtkCxxRevisionMacro(vtkvmtkITKImageWriter, "$Revision: 1900 $") #if 0 // helper function template void ITKWriteVTKImage(vtkvmtkITKImageWriter *self, vtkImageData *inputImage, char *fileName, vtkMatrix4x4* rasToIjkMatrix, TPixelType dummy) { typedef itk::Image ImageType; vtkMatrix4x4 *ijkToRasMatrix = vtkMatrix4x4::New(); vtkMatrix4x4::Invert(rasToIjkMatrix, ijkToRasMatrix); ijkToRasMatrix->Transpose(); typename ImageType::DirectionType direction; typename ImageType::PointType origin; direction.SetIdentity(); double mag[3]; int i; for (i=0; i<3; i++) { // normalize vectors mag[i] = 0; for (int j=0; j<3; j++) { mag[i] += ijkToRasMatrix->GetElement(i,j)* ijkToRasMatrix->GetElement(i,j); } if (mag[i] == 0.0) { mag[i] = 1; } mag[i] = sqrt(mag[i]); //if (i == 1) { // Y flip //mag[i] = -mag[i]; //} } for ( i=0; i<3; i++) { int j; for (j=0; j<3; j++) { ijkToRasMatrix->SetElement(i, j, ijkToRasMatrix->GetElement(i,j)/mag[i]); } } // ITK image direction are in LPS space // convert from ijkToRas to ijkToLps vtkMatrix4x4* rasToLpsMatrix = vtkMatrix4x4::New(); rasToLpsMatrix->Identity(); rasToLpsMatrix->SetElement(0,0,-1); rasToLpsMatrix->SetElement(1,1,-1); vtkMatrix4x4* ijkToLpsMatrix = vtkMatrix4x4::New(); vtkMatrix4x4::Multiply4x4(ijkToRasMatrix, rasToLpsMatrix, ijkToLpsMatrix); for ( i=0; i<3; i++) { origin[i] = ijkToRasMatrix->GetElement(3,i); int j; for (j=0; j<3; j++) { direction[j][i] = ijkToLpsMatrix->GetElement(i,j); } } rasToLpsMatrix->Delete(); ijkToRasMatrix->Delete(); ijkToLpsMatrix->Delete(); origin[0] *= -1; origin[1] *= -1; // itk import for input itk images typedef typename itk::VTKImageImport ImageImportType; typename ImageImportType::Pointer itkImporter = ImageImportType::New(); // vtk export for vtk image vtkImageExport* vtkExporter = vtkImageExport::New(); vtkImageFlip* vtkFlip = vtkImageFlip::New(); // writer typedef typename itk::ImageFileWriter ImageWriterType; typename ImageWriterType::Pointer itkImageWriter = ImageWriterType::New(); if ( self->GetUseCompression() ) { itkImageWriter->UseCompressionOn(); } else { itkImageWriter->UseCompressionOff(); } // set pipeline for the image vtkFlip->SetInput( inputImage ); vtkFlip->SetFilteredAxis(1); vtkFlip->FlipAboutOriginOn(); vtkExporter->SetInput ( inputImage ); itkImporter = ImageImportType::New(); ConnectPipelines(vtkExporter, itkImporter); // write image itkImageWriter->SetInput(itkImporter->GetOutput()); itkImporter->GetOutput()->SetDirection(direction); itkImporter->GetOutput()->Update(); itkImporter->GetOutput()->SetOrigin(origin); itkImporter->GetOutput()->SetSpacing(mag); itkImageWriter->SetFileName( fileName ); itkImageWriter->Update(); // clean up vtkExporter->Delete(); vtkFlip->Delete(); } #endif template void ITKWriteVTKImage(vtkvmtkITKImageWriter *self, vtkImageData *inputImage, char *fileName, vtkMatrix4x4* rasToIjkMatrix, TPixelType dummy) { typedef itk::Image ImageType; double mag[3]; typename ImageType::DirectionType direction; typename ImageType::PointType origin; direction.SetIdentity(); if (rasToIjkMatrix) { vtkMatrix4x4 *ijkToRasMatrix = vtkMatrix4x4::New(); vtkMatrix4x4::Invert(rasToIjkMatrix, ijkToRasMatrix); ijkToRasMatrix->Transpose(); int i; for (i=0; i<3; i++) { // normalize vectors mag[i] = 0; for (int j=0; j<3; j++) { mag[i] += ijkToRasMatrix->GetElement(i,j)* ijkToRasMatrix->GetElement(i,j); } if (mag[i] == 0.0) { mag[i] = 1; } mag[i] = sqrt(mag[i]); //if (i == 1) { // Y flip //mag[i] = -mag[i]; //} } for ( i=0; i<3; i++) { int j; for (j=0; j<3; j++) { ijkToRasMatrix->SetElement(i, j, ijkToRasMatrix->GetElement(i,j)/mag[i]); } } // ITK image direction are in LPS space // convert from ijkToRas to ijkToLps vtkMatrix4x4* rasToLpsMatrix = vtkMatrix4x4::New(); rasToLpsMatrix->Identity(); rasToLpsMatrix->SetElement(0,0,-1); rasToLpsMatrix->SetElement(1,1,-1); vtkMatrix4x4* ijkToLpsMatrix = vtkMatrix4x4::New(); vtkMatrix4x4::Multiply4x4(ijkToRasMatrix, rasToLpsMatrix, ijkToLpsMatrix); for ( i=0; i<3; i++) { origin[i] = ijkToRasMatrix->GetElement(3,i); int j; for (j=0; j<3; j++) { direction[j][i] = ijkToLpsMatrix->GetElement(i,j); } } rasToLpsMatrix->Delete(); ijkToRasMatrix->Delete(); ijkToLpsMatrix->Delete(); origin[0] *= -1; origin[1] *= -1; } else { // ITK image direction are in LPS space vtkMatrix4x4* rasToLpsMatrix = vtkMatrix4x4::New(); rasToLpsMatrix->Identity(); rasToLpsMatrix->SetElement(0,0,-1); rasToLpsMatrix->SetElement(1,1,-1); int i; for ( i=0; i<3; i++) { int j; for (j=0; j<3; j++) { direction[j][i] = rasToLpsMatrix->GetElement(i,j); } } rasToLpsMatrix->Delete(); double inputOrigin[3]; inputImage->GetOrigin(inputOrigin); origin[0] = -1.0 * inputOrigin[0]; origin[1] = -1.0 * inputOrigin[1]; origin[2] = inputOrigin[2]; } // itk import for input itk images typedef typename itk::VTKImageImport ImageImportType; typename ImageImportType::Pointer itkImporter = ImageImportType::New(); // vtk export for vtk image vtkImageExport* vtkExporter = vtkImageExport::New(); // writer typedef typename itk::ImageFileWriter ImageWriterType; typename ImageWriterType::Pointer itkImageWriter = ImageWriterType::New(); if ( self->GetUseCompression() ) { itkImageWriter->UseCompressionOn(); } else { itkImageWriter->UseCompressionOff(); } // set pipeline for the image vtkExporter->SetInput ( inputImage ); itkImporter = ImageImportType::New(); ConnectPipelines(vtkExporter, itkImporter); // write image itkImageWriter->SetInput(itkImporter->GetOutput()); if (rasToIjkMatrix) { itkImporter->GetOutput()->SetDirection(direction); itkImporter->GetOutput()->Update(); itkImporter->GetOutput()->SetOrigin(origin); itkImporter->GetOutput()->SetSpacing(mag); } else { itkImporter->GetOutput()->SetDirection(direction); itkImporter->GetOutput()->Update(); itkImporter->GetOutput()->SetOrigin(origin); } itkImporter->Update(); itkImageWriter->SetFileName( fileName ); itkImageWriter->Update(); // clean up vtkExporter->Delete(); } //---------------------------------------------------------------------------- vtkvmtkITKImageWriter::vtkvmtkITKImageWriter() { this->FileName = NULL; this->RasToIJKMatrix = NULL; this->UseCompression = 0; } //---------------------------------------------------------------------------- vtkvmtkITKImageWriter::~vtkvmtkITKImageWriter() { // get rid of memory allocated for file names if (this->FileName) { delete [] this->FileName; this->FileName = NULL; } } //---------------------------------------------------------------------------- void vtkvmtkITKImageWriter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << "\n"; } //---------------------------------------------------------------------------- void vtkvmtkITKImageWriter::SetInput(vtkImageData *input) { this->vtkProcessObject::SetNthInput(0, input); } //---------------------------------------------------------------------------- vtkImageData *vtkvmtkITKImageWriter::GetInput() { if (this->NumberOfInputs < 1) { return NULL; } return (vtkImageData *)(this->Inputs[0]); } //---------------------------------------------------------------------------- // This function sets the name of the file. void vtkvmtkITKImageWriter::SetFileName(const char *name) { if ( this->FileName && name && (!strcmp(this->FileName,name))) { return; } if (!name && !this->FileName) { return; } if (this->FileName) { delete [] this->FileName; } this->FileName = new char[strlen(name) + 1]; strcpy(this->FileName, name); this->Modified(); } //---------------------------------------------------------------------------- // Writes all the data from the input. void vtkvmtkITKImageWriter::Write() { if ( this->GetInput() == NULL ) { return; } if ( ! this->FileName ) { vtkErrorMacro(<<"vtkvmtkITKImageWriter: Please specify a FileName"); return; } this->GetInput()->UpdateInformation(); this->GetInput()->SetUpdateExtent(this->GetInput()->GetWholeExtent()); if (this->GetInput()->GetNumberOfScalarComponents() == 1) { // take into consideration the scalar type switch (this->GetInput()->GetScalarType()) { case VTK_DOUBLE: { double pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_FLOAT: { float pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_LONG: { long pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_UNSIGNED_LONG: { unsigned long pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_INT: { int pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_UNSIGNED_INT: { unsigned int pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_SHORT: { short pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_UNSIGNED_SHORT: { unsigned short pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_CHAR: { char pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_UNSIGNED_CHAR: { unsigned char pixelType=0; ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; default: vtkErrorMacro(<< "Execute: Unknown output ScalarType"); return; } } // scalar else if (this->GetInput()->GetNumberOfScalarComponents() == 3) { // take into consideration the scalar type switch (this->GetInput()->GetScalarType()) { case VTK_DOUBLE: { typedef itk::Vector VectorPixelType; VectorPixelType pixelType; pixelType.Fill(0.0); ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_FLOAT: { typedef itk::Vector VectorPixelType; VectorPixelType pixelType; pixelType.Fill(0.0); ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_UNSIGNED_SHORT: { typedef itk::Vector VectorPixelType; VectorPixelType pixelType; pixelType.Fill(0); ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; case VTK_UNSIGNED_CHAR: { typedef itk::Vector VectorPixelType; VectorPixelType pixelType; pixelType.Fill(0); ITKWriteVTKImage(this, this->GetInput(), this->GetFileName(), this->RasToIJKMatrix, pixelType); } break; default: vtkErrorMacro(<< "Execute: Unknown output ScalarType"); return; } } // vector else { vtkErrorMacro(<< "Can only export 1 or 3 component images"); return; } } vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/0000775000175000017500000000000011757446472016205 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doxygen.css0000664000175000017500000003711311757446472020401 0ustar lucaluca/* The standard CSS for doxygen */ body, table, div, p, dl { font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; font-size: 13px; line-height: 1.3; } /* @group Heading Levels */ h1 { font-size: 150%; } .title { font-size: 150%; font-weight: bold; margin: 10px 2px; } h2 { font-size: 120%; } h3 { font-size: 100%; } dt { font-weight: bold; } div.multicol { -moz-column-gap: 1em; -webkit-column-gap: 1em; -moz-column-count: 3; -webkit-column-count: 3; } p.startli, p.startdd, p.starttd { margin-top: 2px; } p.endli { margin-bottom: 0px; } p.enddd { margin-bottom: 4px; } p.endtd { margin-bottom: 2px; } /* @end */ caption { font-weight: bold; } span.legend { font-size: 70%; text-align: center; } h3.version { font-size: 90%; text-align: center; } div.qindex, div.navtab{ background-color: ##ee; border: 1px solid ##b0; text-align: center; } div.qindex, div.navpath { width: 100%; line-height: 140%; } div.navtab { margin-right: 15px; } /* @group Link Styling */ a { color: ##50; font-weight: normal; text-decoration: none; } .contents a:visited { color: ##60; } a:hover { text-decoration: underline; } a.qindex { font-weight: bold; } a.qindexHL { font-weight: bold; background-color: ##AA; color: #ffffff; border: 1px double ##98; } .contents a.qindexHL:visited { color: #ffffff; } a.el { font-weight: bold; } a.elRef { } a.code, a.code:visited { color: #4665A2; } a.codeRef, a.codeRef:visited { color: #4665A2; } /* @end */ dl.el { margin-left: -1cm; } .fragment { font-family: monospace, fixed; font-size: 105%; } pre.fragment { border: 1px solid ##CC; background-color: ##FC; padding: 4px 6px; margin: 4px 8px 4px 2px; overflow: auto; word-wrap: break-word; font-size: 9pt; line-height: 125%; } div.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px; padding: 0.2em; border: solid thin #333; border-radius: 0.5em; -webkit-border-radius: .5em; -moz-border-radius: .5em; box-shadow: 2px 2px 3px #999; -webkit-box-shadow: 2px 2px 3px #999; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); } div.groupHeader { margin-left: 16px; margin-top: 12px; font-weight: bold; } div.groupText { margin-left: 16px; font-style: italic; } body { background-color: white; color: black; margin: 0; } div.contents { margin-top: 10px; margin-left: 8px; margin-right: 8px; } td.indexkey { background-color: ##ee; font-weight: bold; border: 1px solid ##cc; margin: 2px 0px 2px 0; padding: 2px 10px; white-space: nowrap; vertical-align: top; } td.indexvalue { background-color: ##ee; border: 1px solid ##cc; padding: 2px 10px; margin: 2px 0px; } tr.memlist { background-color: ##f0; } p.formulaDsp { text-align: center; } img.formulaDsp { } img.formulaInl { vertical-align: middle; } div.center { text-align: center; margin-top: 0px; margin-bottom: 0px; padding: 0px; } div.center img { border: 0px; } address.footer { text-align: right; padding-right: 12px; } img.footer { border: 0px; vertical-align: middle; } /* @group Code Colorization */ span.keyword { color: #008000 } span.keywordtype { color: #604020 } span.keywordflow { color: #e08000 } span.comment { color: #800000 } span.preprocessor { color: #806020 } span.stringliteral { color: #002080 } span.charliteral { color: #008080 } span.vhdldigit { color: #ff00ff } span.vhdlchar { color: #000000 } span.vhdlkeyword { color: #700070 } span.vhdllogic { color: #ff0000 } blockquote { background-color: ##F8; border-left: 2px solid ##AA; margin: 0 24px 0 4px; padding: 0 12px 0 16px; } /* @end */ /* .search { color: #003399; font-weight: bold; } form.search { margin-bottom: 0px; margin-top: 0px; } input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } */ td.tiny { font-size: 75%; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid ##b0; } th.dirtab { background: ##ee; font-weight: bold; } hr { height: 0px; border: none; border-top: 1px solid ##66; } hr.footer { height: 1px; } /* @group Member Descriptions */ table.memberdecls { border-spacing: 0px; padding: 0px; } .mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { background-color: ##FA; border: none; margin: 4px; padding: 1px 0 0 8px; } .mdescLeft, .mdescRight { padding: 0px 8px 4px 8px; color: #555; } .memItemLeft, .memItemRight, .memTemplParams { border-top: 1px solid ##cc; } .memItemLeft, .memTemplItemLeft { white-space: nowrap; } .memItemRight { width: 100%; } .memTemplParams { color: ##60; white-space: nowrap; } /* @end */ /* @group Member Details */ /* Styles for detailed member documentation */ .memtemplate { font-size: 80%; color: ##60; font-weight: normal; margin-left: 9px; } .memnav { background-color: ##ee; border: 1px solid ##b0; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } .mempage { width: 100%; } .memitem { padding: 0; margin-bottom: 10px; margin-right: 5px; } .memname { white-space: nowrap; font-weight: bold; margin-left: 6px; } .memproto, dl.reflist dt { border-top: 1px solid ##B4; border-left: 1px solid ##B4; border-right: 1px solid ##B4; padding: 6px 0px 6px 0px; color: ##2b; font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); /* opera specific markup */ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); border-top-right-radius: 8px; border-top-left-radius: 8px; /* firefox specific markup */ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; -moz-border-radius-topright: 8px; -moz-border-radius-topleft: 8px; /* webkit specific markup */ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); -webkit-border-top-right-radius: 8px; -webkit-border-top-left-radius: 8px; background-image:url('nav_f.png'); background-repeat:repeat-x; background-color: ##E6; } .memdoc, dl.reflist dd { border-bottom: 1px solid ##B4; border-left: 1px solid ##B4; border-right: 1px solid ##B4; padding: 2px 5px; background-color: ##FC; border-top-width: 0; /* opera specific markup */ border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); /* firefox specific markup */ -moz-border-radius-bottomleft: 8px; -moz-border-radius-bottomright: 8px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; background-image: -moz-linear-gradient(center top, ##FF 0%, ##FF 60%, ##F8 95%, ##F0); /* webkit specific markup */ -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px; -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); background-image: -webkit-gradient(linear,center top,center bottom,from(##FF), color-stop(0.6,##FF), color-stop(0.60,##FF), color-stop(0.95,##F8), to(##F0)); } dl.reflist dt { padding: 5px; } dl.reflist dd { margin: 0px 0px 10px 0px; padding: 5px; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; } .paramname { color: #602020; white-space: nowrap; } .paramname em { font-style: normal; } .params, .retval, .exception, .tparams { border-spacing: 6px 2px; } .params .paramname, .retval .paramname { font-weight: bold; vertical-align: top; } .params .paramtype { font-style: italic; vertical-align: top; } .params .paramdir { font-family: "courier new",courier,monospace; vertical-align: top; } /* @end */ /* @group Directory (tree) */ /* for the tree view */ .ftvtree { font-family: sans-serif; margin: 0px; } /* these are for tree view when used as main index */ .directory { font-size: 9pt; font-weight: bold; margin: 5px; } .directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } /* The following two styles can be used to replace the root node title with an image of your choice. Simply uncomment the next two styles, specify the name of your image and be sure to set 'height' to the proper pixel height of your image. */ /* .directory h3.swap { height: 61px; background-repeat: no-repeat; background-image: url("yourimage.gif"); } .directory h3.swap span { display: none; } */ .directory > h3 { margin-top: 0; } .directory p { margin: 0px; white-space: nowrap; } .directory div { display: none; margin: 0px; } .directory img { vertical-align: -30%; } /* these are for tree view when not used as main index */ .directory-alt { font-size: 100%; font-weight: bold; } .directory-alt h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } .directory-alt > h3 { margin-top: 0; } .directory-alt p { margin: 0px; white-space: nowrap; } .directory-alt div { display: none; margin: 0px; } .directory-alt img { vertical-align: -30%; } /* @end */ div.dynheader { margin-top: 8px; } address { font-style: normal; color: ##33; } table.doxtable { border-collapse:collapse; margin-top: 4px; margin-bottom: 4px; } table.doxtable td, table.doxtable th { border: 1px solid ##37; padding: 3px 7px 2px; } table.doxtable th { background-color: ##47; color: #FFFFFF; font-size: 110%; padding-bottom: 4px; padding-top: 5px; } table.fieldtable { width: 100%; margin-bottom: 10px; border: 1px solid ##B4; border-spacing: 0px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } .fieldtable td, .fieldtable th { padding: 3px 7px 2px; } .fieldtable td.fieldtype, .fieldtable td.fieldname { white-space: nowrap; border-right: 1px solid ##B4; border-bottom: 1px solid ##B4; vertical-align: top; } .fieldtable td.fielddoc { border-bottom: 1px solid ##B4; width: 100%; } .fieldtable tr:last-child td { border-bottom: none; } .fieldtable th { background-image:url('nav_f.png'); background-repeat:repeat-x; background-color: ##E6; font-size: 90%; color: ##2B; padding-bottom: 4px; padding-top: 5px; text-align:left; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom: 1px solid ##B4; } .tabsearch { top: 0px; left: 10px; height: 36px; background-image: url('tab_b.png'); z-index: 101; overflow: hidden; font-size: 13px; } .navpath ul { font-size: 11px; background-image:url('tab_b.png'); background-repeat:repeat-x; height:30px; line-height:30px; color:##9b; border:solid 1px ##ca; overflow:hidden; margin:0px; padding:0px; } .navpath li { list-style-type:none; float:left; padding-left:10px; padding-right:15px; background-image:url('bc_s.png'); background-repeat:no-repeat; background-position:right; color:##45; } .navpath li.navelem a { height:32px; display:block; text-decoration: none; outline: none; } .navpath li.navelem a:hover { color:##80; } .navpath li.footer { list-style-type:none; float:right; padding-left:10px; padding-right:15px; background-image:none; background-repeat:no-repeat; background-position:right; color:##45; font-size: 8pt; } div.summary { float: right; font-size: 8pt; padding-right: 5px; width: 50%; text-align: right; } div.summary a { white-space: nowrap; } div.ingroups { margin-left: 5px; font-size: 8pt; padding-left: 5px; width: 50%; text-align: left; } div.ingroups a { white-space: nowrap; } div.header { background-image:url('nav_h.png'); background-repeat:repeat-x; background-color: ##FA; margin: 0px; border-bottom: 1px solid ##CC; } div.headertitle { padding: 5px 5px 5px 7px; } dl { padding: 0 0 0 10px; } /* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ dl.section { border-left:4px solid; padding: 0 0 0 6px; } dl.note { border-color: #D0C000; } dl.warning, dl.attention { border-color: #FF0000; } dl.pre, dl.post, dl.invariant { border-color: #00D000; } dl.deprecated { border-color: #505050; } dl.todo { border-color: #00C0E0; } dl.test { border-color: #3030E0; } dl.bug { border-color: #C08050; } dl.section dd { margin-bottom: 6px; } #projectlogo { text-align: center; vertical-align: bottom; border-collapse: separate; } #projectlogo img { border: 0px none; } #projectname { font: 300% Tahoma, Arial,sans-serif; margin: 0px; padding: 2px 0px; } #projectbrief { font: 120% Tahoma, Arial,sans-serif; margin: 0px; padding: 0px; } #projectnumber { font: 50% Tahoma, Arial,sans-serif; margin: 0px; padding: 0px; } #titlearea { padding: 0px; margin: 0px; width: 100%; border-bottom: 1px solid ##70; } .image { text-align: center; } .dotgraph { text-align: center; } .mscgraph { text-align: center; } .caption { font-weight: bold; } div.zoom { border: 1px solid ##A0; } dl.citelist { margin-bottom:50px; } dl.citelist dt { color:##40; float:left; font-weight:bold; margin-right:10px; padding:5px; } dl.citelist dd { margin:2px 0; padding:5px 0; } div.toc { padding: 14px 25px; background-color: ##F6; border: 1px solid ##DD; border-radius: 7px 7px 7px 7px; float: right; height: auto; margin: 0 20px 10px 10px; width: 200px; } div.toc li { background: url("bdwn.png") no-repeat scroll 0 5px transparent; font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; margin-top: 5px; padding-left: 10px; padding-top: 2px; } div.toc h3 { font: bold 12px/1.2 Arial,FreeSans,sans-serif; color: ##60; border-bottom: 0 none; margin: 0; } div.toc ul { list-style: none outside none; border: medium none; padding: 0px; } div.toc li.level1 { margin-left: 0px; } div.toc li.level2 { margin-left: 15px; } div.toc li.level3 { margin-left: 30px; } div.toc li.level4 { margin-left: 45px; } @media print { #top { display: none; } #side-nav { display: none; } #nav-path { display: none; } body { overflow:visible; } h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } .summary { display: none; } .memitem { page-break-inside: avoid; } #doc-content { margin-left:0 !important; height:auto !important; width:auto !important; overflow:inherit; display:inline; } pre.fragment { overflow: visible; text-wrap: unrestricted; white-space: -moz-pre-wrap; /* Moz */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ white-space: pre-wrap; /* CSS3 */ word-wrap: break-word; /* IE 5.5+ */ } } vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doc_header2doxygen.pl0000664000175000017500000004433311757446472022306 0ustar lucaluca#!/usr/bin/env perl # Time-stamp: <2002-01-28 11:56:19 barre> # # Convert VTK headers to doxygen format # # roeim : Vetle Roeim # barre : Sebastien Barre # # 0.83 (barre) : # - add --stdout : print converted file to standard output # # 0.82 (barre) : # - add --relativeto path : each file/directory to document is considered # relative to 'path', where --to and --relativeto should be absolute # # 0.81 (barre) : # - fix pb if both --to and path to the file to document were absolute # - remove warning when date or revision not found # # 0.8 (barre) : # - update to match the new VTK 4.0 tree # - change default --dirs so that it can be launched from Utilities/Doxygen # - change default --to so that it can be launched from Utilities/Doxygen # - handle more .SECTION syntax # - add group support (at last) # # 0.76 (barre) : # - add 'parallel' to the default set of directories # # 0.75 (barre) : # - change default --to to '../vtk-doxygen' to comply with Kitware's doxyfile # # 0.74 (barre) : # - as doxygen now handles RCS/CVS tags of the form $word:text$, use them # # 0.73 (barre) : # - change doxygen command style from \ to @ to match javadoc, autodoc, etc. # # 0.72 (barre) : # - change default --to to '../vtk-dox' # # 0.71 (barre) : # - fix O_TEXT flag problem # - switch to Unix CR/LF format # # 0.7 (barre) : # - change name # - remove -c option # # 0.6 (barre) : # - change (warning) default --to to '../vtk2' because I ruined my own # VTK distrib too many times :( # - add automatic creation of missing directory trees # - add check for current OS (if Windows, do not perform tests based # on stat()/idev/ino features) # # 0.5 (barre) : # - better .SECTION handling # - add support for empty lines in documentation block # - fix problem with headers not corresponding to classes # - change name to doc_header2doxygen (removed vtk_) # - change '-s' (silent) to '-v' (verbose) # - add function description reformatting # # 0.4 (barre) : # - change /*! ... */ position upon request # - add 'Date:' support as @date # - add 'Version:' support as @version # - add 'Thanks:' support as @par Thanks # # 0.3 (barre) : # - fix various " // Description" spelling problems :) # # 0.2 (barre) : # - fix problem with classes with no brief documentation # # 0.1 (barre) : # - add Perl syntactic sugar, options... # - add standard output (filter) mode (-c) # - add silent mode (-s) # - add update mode, convert only if newer (-u) # - add conversion to another directory (--to) # - add '.SECTION Caveats' support as @warning # - add/fix '.SECTION whatever' support as @par # - add default directories to process # # 0.0 (roeim) # - first release (thanks to V. Roeim !) use Carp; use Cwd 'abs_path'; use Getopt::Long; use Fcntl; use File::Basename; use File::Find; use File::Path; use Text::Wrap; use strict; my ($VERSION, $PROGNAME, $AUTHOR) = (0.83, $0, "Sebastien Barre et al."); $PROGNAME =~ s/^.*[\\\/]//; # ------------------------------------------------------------------------- # Defaults (add options as you want: "verbose" => 1 for default verbose mode) my %default = ( dirs => ["../../Common", "../../Filtering", "../../Graphics", "../../Hybrid", "../../Imaging", "../../IO", "../../Parallel", "../../Patented", "../../Rendering"], relativeto => "", temp => "doc_header2doxygen.tmp", to => "../../../VTK-doxygen" ); # ------------------------------------------------------------------------- # Parse options my %args; Getopt::Long::Configure("bundling"); GetOptions (\%args, "help", "verbose|v", "update|u", "force|f", "temp=s", "to=s", "stdout", "relativeto=s"); print "$PROGNAME $VERSION, by $AUTHOR\n" if ! exists $args{"stdout"}; if (exists $args{"help"}) { print <<"EOT"; Usage : $PROGNAME [--help] [--verbose|-v] [--update|-u] [--force|-f] [--temp file] [--to path] [--relativeto path] [files|directories...] --help : this message --verbose|-v : verbose (display filenames while processing) --update|-u : update (convert only if newer, requires --to) --force|-f : force conversion for all files (overrides --update) --stdout : print converted file to standard output --temp file : use 'file' as temporary file (default: $default{temp}) --to path : use 'path' as destination directory (default: $default{to}) --relativeto path : each file/directory to document is considered relative to 'path', where --to and --relativeto should be absolute (default: $default{relativeto}) Example: $PROGNAME --to ../vtk-doxygen $PROGNAME contrib EOT exit; } $args{"verbose"} = 1 if exists $default{"verbose"}; $args{"update"} = 1 if exists $default{"update"}; $args{"force"} = 1 if exists $default{"force"}; $args{"temp"} = $default{temp} if ! exists $args{"temp"}; $args{"to"} = $default{"to"} if ! exists $args{"to"}; $args{"to"} =~ s/[\\\/]*$// if exists $args{"to"}; $args{"relativeto"} = $default{"relativeto"} if ! exists $args{"relativeto"}; $args{"relativeto"} =~ s/[\\\/]*$// if exists $args{"relativeto"}; croak "$PROGNAME: --update requires --to\n" if exists $args{"update"} && ! exists $args{"to"}; my $os_is_win = ($^O =~ m/(MSWin32|Cygwin)/i); my $open_file_as_text = $os_is_win ? O_TEXT : 0; my $start_time = time(); # ------------------------------------------------------------------------- # Collect all files and directories push @ARGV, @{$default{dirs}} if !@ARGV; print "Collecting...\n" if ! exists $args{"stdout"}; my @files; foreach my $file (@ARGV) { if (-f $file) { push @files, $file; } elsif (-d $file) { find sub { push @files, $File::Find::name; }, $file; } } # ------------------------------------------------------------------------- # Process files corresponding to headers print "Converting...\n" if ! exists $args{"stdout"}; my $intermediate_time = time(); my $nb_file = 0; foreach my $source (@files) { next if $source !~ /vtk[^\\\/]*\.h\Z/; # Figure out destination file now my $dest; if (! exists $args{"to"}) { $dest = $args{"temp"}; } else { # if source has absolute path, just use the basename, unless a # relativeto path has been set if ($source =~ m/^(\/|[a-zA-W]\:[\/\\])/) { if ($args{"relativeto"}) { my ($dir, $absrel) = (abs_path(dirname($source)), abs_path($args{"relativeto"})); $dir =~ s/$absrel//; $dest = $args{"to"} . $dir . '/' . basename($source); } else { $dest = $args{"to"} . '/' . basename($source); } } else { my $source2 = $source; # let's remove the ../ component before the source filename, so # that it might be appended to the "to" directory $source2 =~ s/^(\.\.[\/\\])*//; $dest = $args{"to"} . '/' . $source2; } # Ensure both source and target are different if (!$os_is_win) { my ($i_dev, $i_ino) = stat $source; my ($o_dev, $o_ino) = stat $dest; croak "$PROGNAME: sorry, $source and $dest are the same file\n" if ($i_dev == $o_dev && $i_ino == $o_ino); } } # Update mode : skip the file if it is not newer than the # previously converted target if (exists $args{"update"} && ! exists $args{"force"}) { next if -e $dest && (stat $source)[9] < (stat $dest)[9]; } ++$nb_file; print " $source\n" if exists $args{"verbose"}; # Open file, feed it entirely to an array sysopen(HEADERFILE, $source, O_RDONLY|$open_file_as_text) or croak "$PROGNAME: unable to open $source\n"; my @headerfile = ; close(HEADERFILE); my ($date, $revision) = ("", ""); my @converted = (); my @thanks = (); # Parse the file until the beginning of the documentation block # is found. The copyright and disclaimer sections are parsed to # extract the 'Date', 'Version' and 'Thanks' values. my $line; while ($line = shift @headerfile) { # Quit if the beginning of the documentation block has been reached. # It is supposed to start with: # // .NAME vtkFooBar - foo bar class last if $line =~ /\/\/ \.NAME/; # Date. Example: # Date: $Date: 2004/05/19 10:03:55 $ if ($line =~ /^\s*Date:\s*(.*)$/) { $date = $1; # Version. Example: # Version: $Revision: 1.1.1.1 $ } elsif ($line =~ /^\s*Version:\s*(.*)$/) { $revision = $1; # Thanks (maybe multi-lines). Example: # Thanks: Thanks to Sebastien Barre who developed this class. } elsif ($line =~ /^\s*Thanks:\s*(.*)$/) { push @thanks, " ", $1, "\n"; # Handle multi-line thanks while ($line = shift @headerfile) { last if $line =~ /^\s*$/; $line =~ s/^(\s*)//; push @thanks, " ", $line; } push @converted, $line; # Everything else goes to the converted file } else { push @converted, $line; } } # Process the documentation block # Extract the name of the class and its short description # // .NAME vtkFooBar - foo bar class if (defined($line) && $line =~ /\/\/ \.NAME (\w*)( \- (.*))?/) { my ($class_name, $class_short_description) = ($1, $3); $class_name =~ s/\.h//; # Insert class description, date, revision, thanks push @converted, "/*! \@class $class_name\n"; push @converted, " \@brief $class_short_description\n" if $class_short_description; if ($date) { push @converted, "\n $date\n"; } # WARNING : need a blank line between RCS tags and previous dox tag if ($revision) { push @converted, "\n" if (!$date); push @converted, " $revision\n"; } # Do not add thanks anymore. Will be done externally. # push @converted, " \@par Thanks:\n", @thanks if @thanks; # Read until the end of the documentation block is reached # Translate 'See Also', 'Caveats' and whatever .SECTION # As of 24 sep 2001, there are: # 137 // .SECTION Caveats # 1 // .SECTION Credits # 702 // .SECTION Description # 3 // .SECTION Note # 1 // .SECTION note # 329 // .SECTION See Also # 4 // .SECTION See also # 70 // .SECTION see also # 1 // .SECTION Warning # find . -name vtk\*.h -exec grep "\.SECTION" {} \; | sort | uniq -c # Let's provide support for bugs too: # // .SECTION Bug # // .SECTION Bugs # // .SECTION Todo my ($tag, $inblock) = ("", 0); while ($line = shift @headerfile) { # Quit if the end of the documentation block has been reached. # Let'say that it is supposed to end as soon as the usual # inclusion directives are found, for example: # #ifndef __vtkAbstractTransform_h # #define __vtkAbstractTransform_h last if $line =~ /^\#/; # Process and recognize a .SECTION command and convert it to # the corresponding doxygen tag ($tag) if ($line =~ /^\/\/\s+\.SECTION\s+(.+)\s*$/i) { my $type = $1; # Bugs (@bugs). Starts with: # // .SECTION Bug # // .SECTION Bugs if ($type =~ /Bugs?/i) { $tag = "\@bug"; } # Caveats or Warnings (@warning). Starts with: # // .SECTION Caveats # // .SECTION Warning # // .SECTION Warnings elsif ($type =~ /(Caveats|Warnings?)/i) { $tag = "\@warning"; } # Description. Starts with: # // .SECTION Description elsif ($type =~ /Description/i) { $tag = ""; push @converted, "\n"; } # Note (@attention). Starts with: # // .SECTION Note elsif ($type =~ /Note/i) { $tag = "\@attention"; } # See also (@sa). Starts with: # // .SECTION See Also elsif ($type =~ /See Also/i) { $tag = "\@sa"; } # Todo (@todo). Starts with: # // .SECTION Todo elsif ($type =~ /Todo/i) { $tag = "\@todo"; } # Any other .SECTION (@par). Starts with: # // .SECTION whatever else { $tag = "\@par " . $type . ":"; } $inblock = 0; } # If the line starts with '//', we are still within the tag block. # Remove '//' for non empty lines, eventually put or duplicate # the tag name if an empty comment is found (meaning that a new # 'paragraph' is requested but with the same tag type) # Example: # // .SECTION Caveats # // blabla1q # // blabla1b # // # // blabla2 # Gets translated into: # @warning # blabla1q # blabla1b # # @warning # blabla2 elsif ($line =~ /^\/\/(.*)/) { my $remaining = $1; if ($remaining =~ /\S/) { push @converted, " $tag\n" if $tag ne "" && ! $inblock; push @converted, $remaining, "\n"; $inblock = 1; } else { push @converted, "\n"; $inblock = 0; } } else { # Does not starts with // but still within block or just # before the end (#). Probably an empty line. # Hack : let's have a look at the next line... if it begins # with // then the current line is included (was a space). if (my $next_line = shift @headerfile) { push @converted, $line if $next_line =~ /^\/\//; unshift @headerfile, $next_line; } } } # Close the doxygen documentation block describing the class push @converted, "*/\n\n", $line; } # Read until the end of the header and translate the description of # each function provided that it is located in a C++ comment # containing the 'Description:' keyword. # Example: # // Description: # // Construct with automatic computation of divisions, averaging # // 25 points per bucket. # static vtkPointLocator2D *New(); while ($line = shift @headerfile) { if ($line =~ /^(\s*)\/\/\s*De(s|c)(s|c)?ription/) { my $indent = $1; $Text::Wrap::columns = 76; # While there are still lines beginning with '//' append them to # the function's description and trim spaces. my @description = (); while ($line = shift @headerfile) { last if $line !~ /^\s*\/\//; chop $line; $line =~ s/^\s*\/\/\s*//; $line =~ s/\s*$//; push @description, $line; } # While there are non-empty lines add these lines to the # list of declarations (and/or inline definitions) # pertaining to the same description. my @declarations = (); while ($line && $line =~ /\s+\S/) { push @declarations, $line; $line = shift @headerfile } # If there is more than one declaration or at least a macro, # enclose in a group (actually a single multiline declaration will # be enclosed too, but who cares :)... my $enclose = (scalar @declarations > 1 || $declarations[0] =~ /vtk.+Macro/); push @converted, "$indent//@\{\n" if $enclose; push @converted, wrap("$indent/*! ", "$indent ", @description), " */\n" if @description; push @converted, @declarations; push @converted, "$indent//@\}\n" if $enclose; } push @converted, $line; } # Write the converted header to its destination # or to standard output. if (exists $args{"stdout"}) { print @converted; } else { # Open the target and create the missing directory if any if (!sysopen(DEST_FILE, $dest, O_WRONLY|O_TRUNC|O_CREAT|$open_file_as_text)) { my $dir = dirname($dest); mkpath($dir); sysopen(DEST_FILE, $dest, O_WRONLY|O_TRUNC|O_CREAT|$open_file_as_text) or croak "$PROGNAME: unable to open destination file $dest\n"; } print DEST_FILE @converted; close(DEST_FILE); # If in-place conversion was requested, remove source and rename target # (or temp file) to source if (! exists $args{"to"}) { unlink($source) or carp "$PROGNAME: unable to delete original file $source\n"; rename($args{"temp"}, $source) or carp "$PROGNAME: unable to rename ", $args{"temp"}, " to $source\n"; } } } if (! exists $args{"stdout"}) { print " => $nb_file files converted in ", time() - $intermediate_time, " s. \n"; print "Finished in ", time() - $start_time, " s.\n"; } vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/CMakeLists.txt0000664000175000017500000000333411757446472020750 0ustar lucaluca# # Build the documentation # INCLUDE (${CMAKE_ROOT}/Modules/Documentation.cmake OPTIONAL) IF (BUILD_DOCUMENTATION) # # Configure the script and the doxyfile, then add target # CONFIGURE_FILE( ${VTK_VMTK_SOURCE_DIR}/Utilities/Doxygen/doxyfile.in ${VTK_VMTK_BINARY_DIR}/Utilities/Doxygen/doxyfile) CONFIGURE_FILE( ${VTK_VMTK_SOURCE_DIR}/Utilities/Doxygen/doc_makeall.sh.in ${VTK_VMTK_BINARY_DIR}/Utilities/Doxygen/doc_makeall.sh) ADD_CUSTOM_TARGET(DoxygenDoc ${BASH} ${VTK_VMTK_BINARY_DIR}/Utilities/Doxygen/doc_makeall.sh) INCLUDE (${VTK_VMTK_SOURCE_DIR}/Utilities/Doxygen/LocalUserOptions.cmake OPTIONAL) INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen "\\.css$") INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen "\\.gif$") INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen "\\.html$") INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen "\\.png$") #INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen "\\.pl$") #INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen "\\.stop$") #INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen .txt ) #INSTALL_FILES(${VTK_VMTK_INSTALL_LIB_DIR}/doxygen .txt authors doc_readme) ENDIF (BUILD_DOCUMENTATION) vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doc_makeall.sh.in0000664000175000017500000000254011757446472021402 0ustar lucalucaexport DOXYGEN_PROG="@DOXYGEN@" export PERL_PROG="@PERL@" export RM_PROG="@RM@" export SOURCE_DIR="@VTK_VMTK_SOURCE_DIR@" export PATH_TO_VTK_VMTK_DOX_SCRIPTS="@VTK_VMTK_SOURCE_DIR@/Utilities/Doxygen" export REL_PATH_TO_TOP=. export DOXTEMP="@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen" export INTERMEDIATE_DOX_DIR="$DOXTEMP/dox" export DOXYFILE="$DOXTEMP/doxyfile" export OUTPUT_DIRECTORY="$DOXTEMP/doc" $PERL_PROG $PATH_TO_VTK_VMTK_DOX_SCRIPTS/doc_header2doxygen.pl \ --to "$INTERMEDIATE_DOX_DIR" \ --relativeto "$SOURCE_DIR/$REL_PATH_TO_TOP" \ "$SOURCE_DIR/$REL_PATH_TO_TOP/Common" \ "$SOURCE_DIR/$REL_PATH_TO_TOP/ComputationalGeometry" \ "$SOURCE_DIR/$REL_PATH_TO_TOP/DifferentialGeometry" \ "$SOURCE_DIR/$REL_PATH_TO_TOP/Misc" \ "$SOURCE_DIR/$REL_PATH_TO_TOP/IO" \ "$SOURCE_DIR/$REL_PATH_TO_TOP/Segmentation" $RM_PROG -fr $OUTPUT_DIRECTORY $DOXYGEN_PROG $DOXYFILE $PERL_PROG $PATH_TO_VTK_VMTK_DOX_SCRIPTS/doc_rmpath.pl \ --to "$INTERMEDIATE_DOX_DIR" \ --html "$OUTPUT_DIRECTORY/html" $PERL_PROG $PATH_TO_VTK_VMTK_DOX_SCRIPTS/doc_cleanhtml.pl \ --html "$OUTPUT_DIRECTORY/html" $RM_PROG -fr $INTERMEDIATE_DOX_DIR vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doc_rmpath.pl0000664000175000017500000000576311757446472020675 0ustar lucaluca#!/usr/bin/env perl # Time-stamp: <2001-10-05 11:49:40 barre> # # Remove path to intermediate Doxygen dir from html doc # # barre : Sebastien Barre # # 0.1 (barre) # - first release use Carp; use Cwd 'abs_path'; use Getopt::Long; use Fcntl; use File::Find; use strict; my ($VERSION, $PROGNAME, $AUTHOR) = (0.1, $0, "Sebastien Barre"); $PROGNAME =~ s/^.*[\\\/]//; print "$PROGNAME $VERSION, by $AUTHOR\n"; # ------------------------------------------------------------------------- # Defaults (add options as you want : "verbose" => 1 for default verbose mode) my %default = ( html => "../../../doc/html", to => "../../../VTK-doxygen" ); # ------------------------------------------------------------------------- # Parse options my %args; Getopt::Long::Configure("bundling"); GetOptions (\%args, "help", "verbose|v", "html=s", "to=s"); if (exists $args{"help"}) { print <<"EOT"; Usage : $PROGNAME [--help] [--verbose|-v] [--html path] [--to path] --help : this message --verbose|-v : verbose (display filenames while processing) --html path : 'path' the Doxygen generated HTML doc (default : $default{html}) --to path : 'path' to intermediate Doxygen dir (default : $default{to}) Example: $PROGNAME EOT exit; } $args{"to"} = $default{"to"} if ! exists $args{"to"}; $args{"to"} =~ s/[\\\/]*$// if exists $args{"to"}; $args{"html"} = $default{"html"} if ! exists $args{"html"}; $args{"html"} =~ s/[\\\/]*$// if exists $args{"html"}; my $os_is_win = ($^O =~ m/(MSWin32|Cygwin)/i); my $open_file_as_text = $os_is_win ? O_TEXT : 0; my $start_time = time(); # ------------------------------------------------------------------------- # Collect all HTML files print "Collecting HTML files in ", $args{"html"}, "\n"; my @files; find sub { push @files, $File::Find::name if -f $_ && $_ =~ /\.html$/; }, $args{"html"}; print " => ", scalar @files, " file(s) collected in ", time() - $start_time, " s.\n"; # ------------------------------------------------------------------------- # Remove path my ($nb_files, $htmlpath) = (0, abs_path($args{"to"}) . '/'); undef $/; # slurp mode print "Removing $htmlpath and writing...\n"; my $intermediate_time = time(); foreach my $filename (@files) { print " $filename\n" if exists $args{"verbose"}; # Open the file, read it entirely sysopen(HTMLFILE, $filename, O_RDONLY|$open_file_as_text) or croak "$PROGNAME: unable to open $filename\n"; my $html = ; close(HTMLFILE); # Remove all paths if ($html =~ s/$htmlpath//gms) { ++$nb_files; sysopen(HTMLFILE, $filename, O_WRONLY|O_TRUNC|O_CREAT|$open_file_as_text) or croak "$PROGNAME: unable to open destination file $filename\n"; print HTMLFILE $html; close(HTMLFILE); } } print " => $nb_files file(s) processed and written in ", time() - $intermediate_time, " s.\n"; print "Finished in ", time() - $start_time, " s.\n"; vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doc_cleanhtml.pl0000664000175000017500000000565511757446472021351 0ustar lucaluca#!/usr/bin/env perl # Time-stamp: <2002-10-25 20:17:59 barre> # # Clean the HTML generated by Doxygen to remove some layout quicks # # barre : Sebastien Barre # # 0.1 (barre) # - first release use Carp; use Getopt::Long; use Fcntl; use File::Find; use strict; my ($VERSION, $PROGNAME, $AUTHOR) = (0.1, $0, "Sebastien Barre"); $PROGNAME =~ s/^.*[\\\/]//; print "$PROGNAME $VERSION, by $AUTHOR\n"; # ------------------------------------------------------------------------- # Defaults (add options as you want : "verbose" => 1 for default verbose mode) my %default = ( html => "../../../doc/html", ); # ------------------------------------------------------------------------- # Parse options my %args; Getopt::Long::Configure("bundling"); GetOptions (\%args, "help", "verbose|v", "html=s"); if (exists $args{"help"}) { print <<"EOT"; Usage : $PROGNAME [--help] [--verbose|-v] [--html path] --help : this message --verbose|-v : verbose (display filenames while processing) --html path : 'path' the Doxygen generated HTML doc (default : $default{html}) Example: $PROGNAME EOT exit; } $args{"html"} = $default{"html"} if ! exists $args{"html"}; $args{"html"} =~ s/[\\\/]*$// if exists $args{"html"}; my $os_is_win = ($^O =~ m/(MSWin32|Cygwin)/i); my $open_file_as_text = $os_is_win ? O_TEXT : 0; my $start_time = time(); # ------------------------------------------------------------------------- # Collect all HTML files print "Collecting HTML files in ", $args{"html"}, "\n"; my @files; find sub { push @files, $File::Find::name if -f $_ && $_ =~ /\.html$/; }, $args{"html"}; print " => ", scalar @files, " file(s) collected in ", time() - $start_time, " s.\n"; # ------------------------------------------------------------------------- # Remove path my $nb_files = 0; undef $/; # slurp mode print "Cleaning and writing...\n"; my $intermediate_time = time(); foreach my $filename (@files) { print " $filename\n" if exists $args{"verbose"}; # Open the file, read it entirely sysopen(HTMLFILE, $filename, O_RDONLY|$open_file_as_text) or croak "$PROGNAME: unable to open $filename\n"; my $html = ; close(HTMLFILE); # Clean my $has_been_cleaned = 0; if ($html =~ s//
/gms) { $has_been_cleaned = 1; } # Write if ($has_been_cleaned) { ++$nb_files; sysopen(HTMLFILE, $filename, O_WRONLY|O_TRUNC|O_CREAT|$open_file_as_text) or croak "$PROGNAME: unable to open destination file $filename\n"; print HTMLFILE $html; close(HTMLFILE); } } print " => $nb_files file(s) processed and written in ", time() - $intermediate_time, " s.\n"; print "Finished in ", time() - $start_time, " s.\n"; vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doxyfile.in0000664000175000017500000001453411757446472020367 0ustar lucaluca# PROJECT_NAME = "VMTK" FULL_PATH_NAMES = NO WARN_IF_UNDOCUMENTED = NO GENERATE_TREEVIEW = NO GENERATE_TODOLIST = YES GENERATE_BUGLIST = YES GENERATE_HTML = YES GENERATE_HTMLHELP = NO HTML_OUTPUT = html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = "@VTK_VMTK_SOURCE_DIR@/Utilities/Doxygen/doxygen.css" GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO #GENERATE_TAGFILE = "./VTK.tag" HAVE_DOT = YES DOT_PATH = "@DOT_PATH@" CLASS_GRAPH = YES COLLABORATION_GRAPH = YES TEMPLATE_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CLASS_DIAGRAMS = YES GENERATE_LEGEND = YES GRAPHICAL_HIERARCHY = YES ALLEXTERNALS = NO IMAGE_PATH = "@VTK_VMTK_SOURCE_DIR@/Utilities/Doxygen" "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/contrib" OUTPUT_DIRECTORY = "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/doc" INPUT = "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/dox/Common" \ "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/dox/ComputationalGeometry" \ "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/dox/DifferentialGeometry" \ "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/dox/Misc" \ "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/dox/IO" \ "@VTK_VMTK_BINARY_DIR@/Utilities/Doxygen/dox/Segmentation" \ "@VTK_VMTK_SOURCE_DIR@/Utilities/Doxygen/doc_mainpage.dox" #TAGFILES = "/usr/local/src/CVS/BuildTrees/VTK/Utilities/Doxygen/vtk4.tag"=http://public.kitware.com/VTK/doc/nightly/html EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = YES ALWAYS_DETAILED_SEC = NO SOURCE_BROWSER = NO INLINE_SOURCES = NO CASE_SENSE_NAMES = YES VERBATIM_HEADERS = NO SHOW_INCLUDE_FILES = YES JAVADOC_AUTOBRIEF = YES SORT_MEMBER_DOCS = NO DISTRIBUTE_GROUP_DOC = YES TAB_SIZE = 3 FILE_PATTERNS = *.h RECURSIVE = YES EXCLUDE = EXCLUDE_PATTERNS = *Win32Header* vtkvmtkT* HTML_ALIGN_MEMBERS = YES ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 3 IGNORE_PREFIX = vtkvmtk ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES SEARCH_INCLUDES = YES INCLUDE_PATH = EXPAND_ONLY_PREDEF = YES PREDEFINED = "vtkSetMacro(name,type)= \ virtual void Set##name (type);" \ "vtkGetMacro(name,type)= \ virtual type Get##name ();" \ "vtkSetStringMacro(name)= \ virtual void Set##name (const char*);" \ "vtkGetStringMacro(name)= \ virtual char* Get##name ();" \ "vtkSetClampMacro(name,type,min,max)= \ virtual void Set##name (type);" \ "vtkSetObjectMacro(name,type)= \ virtual void Set##name (type*);" \ "vtkGetObjectMacro(name,type)= \ virtual type *Get##name ();" \ "vtkBooleanMacro(name,type)= \ virtual void name##On (); \ virtual void name##Off ();" \ "vtkSetVector2Macro(name,type)= \ virtual void Set##name (type, type); \ void Set##name (type [2]);" \ "vtkGetVector2Macro(name,type)= \ virtual type *Get##name (); \ virtual void Get##name (type &, type &); \ virtual void Get##name (type [2]);" \ "vtkSetVector3Macro(name,type)= \ virtual void Set##name (type, type, type); \ virtual void Set##name (type [3]);" \ "vtkGetVector3Macro(name,type)= \ virtual type *Get##name (); \ virtual void Get##name (type &, type &, type &); \ virtual void Get##name (type [3]);" \ "vtkSetVector4Macro(name,type)= \ virtual void Set##name (type, type, type, type); \ virtual void Set##name (type [4]);" \ "vtkGetVector4Macro(name,type)= \ virtual type *Get##name (); \ virtual void Get##name (type &, type &, type &, type &); \ virtual void Get##name (type [4]);" \ "vtkSetVector6Macro(name,type)= \ virtual void Set##name (type, type, type, type, \ type, type); \ virtual void Set##name (type [6]);" \ "vtkGetVector6Macro(name,type)= \ virtual type *Get##name (); \ virtual void Get##name (type &, type &, type &, \ type &, type &, type &); \ virtual void Get##name (type [6]);" \ "vtkSetVectorMacro(name,type,count)= \ virtual void Set##name(type data[]);" \ "vtkGetVectorMacro(name,type,count)= \ virtual type *Get##name (); \ virtual void Get##name(type data[##count]);" \ "vtkWorldCoordinateMacro(name)= \ virtual vtkCoordinate *Get##name##Coordinate (); \ virtual void Set##name(float x[3]); \ virtual void Set##name(float x, float y, float z); \ virtual float *Get##name();" \ "vtkViewportCoordinateMacro(name)= \ virtual vtkCoordinate *Get##name##Coordinate (); \ virtual void Set##name(float x[2]); \ virtual void Set##name(float x, float y); \ virtual float *Get##name();" \ "vtkTypeMacro(thisClass,superclass)= \ typedef superclass Superclass; \ virtual const char *GetClassName(); \ static int IsTypeOf(const char *type); \ virtual int IsA(const char *type); \ static thisClass* SafeDownCast(vtkObject *o);" "vtkTypeRevisionMacro(thisClass,superclass)= \ typedef superclass Superclass; \ virtual const char *GetClassName(); \ static int IsTypeOf(const char *type); \ virtual int IsA(const char *type); \ static thisClass* SafeDownCast(vtkObject *o);" vmtk-1.0.1/vtkVmtk/Utilities/Doxygen/doc_mainpage.dox0000664000175000017500000000036111757446472021327 0ustar lucaluca/*! \mainpage VMTK Documentation \section intro Introduction These pages contain the Doxygen documentation of the C++ classes contained in the Vascular Modeling Toolkit. See http://www.vmtk.org for more information on the project. */ vmtk-1.0.1/vtkVmtk/Utilities/CMakeLists.txt0000664000175000017500000000021611757446472017327 0ustar lucalucaSUBDIRS( Doxygen OpenNL #Stellar_1.0 vtkvmtkITK ) IF (VTK_VMTK_BUILD_TETGEN) SUBDIRS(tetgen1.4.3) ENDIF (VTK_VMTK_BUILD_TETGEN) vmtk-1.0.1/vtkVmtk/Utilities/OpenNL/0000775000175000017500000000000011757446472015723 5ustar lucalucavmtk-1.0.1/vtkVmtk/Utilities/OpenNL/nl.h0000664000175000017500000002046511757446472016514 0ustar lucaluca/* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * 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, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * 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 vmtk-1.0.1/vtkVmtk/Utilities/OpenNL/CMakeLists.txt0000664000175000017500000000033211757446472020461 0ustar lucalucaSET (OPENNL_SRCS nl_single_file.c ) INCLUDE_DIRECTORIES(${OPENNL_SOURCE_DIR}) ADD_LIBRARY (nl STATIC ${OPENNL_SRCS}) IF(NOT WIN32) SET_TARGET_PROPERTIES(nl PROPERTIES COMPILE_FLAGS -fPIC) ENDIF(NOT WIN32) vmtk-1.0.1/vtkVmtk/Utilities/OpenNL/nl_single_file.c0000664000175000017500000037400711757446472021053 0ustar lucaluca#include "nl.h" /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_PRIVATE__ #define __NL_PRIVATE__ #include #include #include #include /******************************************************************************/ /*** Assertion checks ***/ /******************************************************************************/ void nl_assertion_failed(const char* cond, const char* file, int line) ; void nl_range_assertion_failed( double x, double min_val, double max_val, const char* file, int line ) ; void nl_should_not_have_reached(const char* file, int line) ; #define nl_assert(x) { \ if(!(x)) { \ nl_assertion_failed(#x,__FILE__, __LINE__) ; \ } \ } #define nl_range_assert(x,min_val,max_val) { \ if(((x) < (min_val)) || ((x) > (max_val))) { \ nl_range_assertion_failed(x, min_val, max_val, \ __FILE__, __LINE__ \ ) ; \ } \ } #define nl_assert_not_reached { \ nl_should_not_have_reached(__FILE__, __LINE__) ; \ } #ifdef NL_DEBUG #define nl_debug_assert(x) nl_assert(x) #define nl_debug_range_assert(x,min_val,max_val) \ nl_range_assert(x,min_val,max_val) #else #define nl_debug_assert(x) #define nl_debug_range_assert(x,min_val,max_val) #endif #ifdef NL_PARANOID #define nl_parano_assert(x) nl_assert(x) #define nl_parano_range_assert(x,min_val,max_val) \ nl_range_assert(x,min_val,max_val) #else #define nl_parano_assert(x) #define nl_parano_range_assert(x,min_val,max_val) #endif /******************************************************************************/ /*** Error reporting ***/ /******************************************************************************/ void nlError(const char* function, const char* message) ; void nlWarning(const char* function, const char* message) ; /******************************************************************************/ /*** OS ***/ /******************************************************************************/ NLdouble nlCurrentTime() ; /******************************************************************************/ /* classic macros */ #ifndef MIN #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #endif #ifndef MAX #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif /******************************************************************************/ /* Memory management */ /******************************************************************************/ #define NL_NEW(T) (T*)(calloc(1, sizeof(T))) #define NL_NEW_ARRAY(T,NB) (T*)(calloc((NB),sizeof(T))) #define NL_RENEW_ARRAY(T,x,NB) (T*)(realloc(x,(NB)*sizeof(T))) #define NL_DELETE(x) free(x); x = NULL #define NL_DELETE_ARRAY(x) free(x); x = NULL #define NL_CLEAR(T, x) memset(x, 0, sizeof(T)) #define NL_CLEAR_ARRAY(T,x,NB) memset(x, 0, (NB)*sizeof(T)) #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_MATRIX__ #define __NL_MATRIX__ #ifdef __cplusplus extern "C" { #endif /************************************************************************************/ /* Dynamic arrays for sparse row/columns */ typedef struct { NLuint index ; NLdouble value ; } NLCoeff ; typedef struct { NLuint size ; NLuint capacity ; NLCoeff* coeff ; } NLRowColumn ; void nlRowColumnConstruct(NLRowColumn* c) ; void nlRowColumnDestroy(NLRowColumn* c) ; void nlRowColumnGrow(NLRowColumn* c) ; void nlRowColumnAdd(NLRowColumn* c, NLint index, NLdouble value) ; void nlRowColumnAppend(NLRowColumn* c, NLint index, NLdouble value) ; void nlRowColumnZero(NLRowColumn* c) ; void nlRowColumnClear(NLRowColumn* c) ; void nlRowColumnSort(NLRowColumn* c) ; /************************************************************************************/ /* SparseMatrix data structure */ #define NL_MATRIX_STORE_ROWS 1 #define NL_MATRIX_STORE_COLUMNS 2 #define NL_MATRIX_STORE_SYMMETRIC 4 typedef struct { NLuint m ; NLuint n ; NLuint diag_size ; NLenum storage ; NLRowColumn* row ; NLRowColumn* column ; NLdouble* diag ; } NLSparseMatrix ; void nlSparseMatrixConstruct( NLSparseMatrix* M, NLuint m, NLuint n, NLenum storage ) ; void nlSparseMatrixDestroy(NLSparseMatrix* M) ; void nlSparseMatrixAdd( NLSparseMatrix* M, NLuint i, NLuint j, NLdouble value ) ; void nlSparseMatrixZero( NLSparseMatrix* M) ; void nlSparseMatrixClear( NLSparseMatrix* M) ; NLuint nlSparseMatrixNNZ( NLSparseMatrix* M) ; void nlSparseMatrixSort( NLSparseMatrix* M) ; /************************************************************************************/ /* SparseMatrix x Vector routine */ void nlSparseMatrixMult(NLSparseMatrix* A, NLdouble* x, NLdouble* y) ; #ifdef __cplusplus } #endif #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_CONTEXT__ #define __NL_CONTEXT__ /******************************************************************************/ /* NLContext data structure */ typedef void(*NLMatrixFunc)(double* x, double* y) ; typedef NLboolean(*NLSolverFunc)() ; typedef struct { NLdouble value ; NLboolean locked ; NLuint index ; } NLVariable ; #define NL_STATE_INITIAL 0 #define NL_STATE_SYSTEM 1 #define NL_STATE_MATRIX 2 #define NL_STATE_ROW 3 #define NL_STATE_MATRIX_CONSTRUCTED 4 #define NL_STATE_SYSTEM_CONSTRUCTED 5 #define NL_STATE_SOLVED 6 typedef struct { NLenum state ; NLVariable* variable ; NLuint n ; NLSparseMatrix M ; NLRowColumn af ; NLRowColumn al ; NLRowColumn xl ; NLdouble* x ; NLdouble* b ; NLdouble right_hand_side ; NLdouble row_scaling ; NLenum solver ; NLenum preconditioner ; NLuint nb_variables ; NLuint current_row ; NLboolean least_squares ; NLboolean symmetric ; NLuint max_iterations ; NLuint inner_iterations ; NLdouble threshold ; NLdouble omega ; NLboolean normalize_rows ; NLboolean alloc_M ; NLboolean alloc_af ; NLboolean alloc_al ; NLboolean alloc_xl ; NLboolean alloc_variable ; NLboolean alloc_x ; NLboolean alloc_b ; NLuint used_iterations ; NLdouble error ; NLdouble elapsed_time ; NLMatrixFunc matrix_vector_prod ; NLMatrixFunc precond_vector_prod ; NLSolverFunc solver_func ; } NLContextStruct ; extern NLContextStruct* nlCurrentContext ; void nlCheckState(NLenum state) ; void nlTransition(NLenum from_state, NLenum to_state) ; void nlMatrixVectorProd_default(NLdouble* x, NLdouble* y) ; NLboolean nlDefaultSolver() ; #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_BLAS__ #define __NL_BLAS__ #ifndef NL_FORTRAN_WRAP #define NL_FORTRAN_WRAP(x) x##_ #endif /***********************************************************************************/ /* C wrappers for BLAS routines */ /* x <- a*x */ void dscal( int n, double alpha, double *x, int incx ) ; /* y <- x */ void dcopy( int n, double *x, int incx, double *y, int incy ) ; /* y <- a*x+y */ void daxpy( int n, double alpha, double *x, int incx, double *y, int incy ) ; /* returns x^T*y */ double ddot( int n, double *x, int incx, double *y, int incy ) ; /** returns |x|_2 */ double dnrm2( int n, double *x, int incx ) ; typedef enum { NoTranspose=0, Transpose=1, ConjugateTranspose=2 } MatrixTranspose ; typedef enum { UpperTriangle=0, LowerTriangle=1 } MatrixTriangle ; typedef enum { UnitTriangular=0, NotUnitTriangular=1 } MatrixUnitTriangular ; /** x <- A^{-1}*x, x <- A^{-T}*x */ void dtpsv( MatrixTriangle uplo, MatrixTranspose trans, MatrixUnitTriangular diag, int n, double *AP, double *x, int incx ) ; /** y <- alpha*A*x + beta*y, y <- alpha*A^T*x + beta*y, A-(m,n) */ void dgemv( MatrixTranspose trans, int m, int n, double alpha, double *A, int ldA, double *x, int incx, double beta, double *y, int incy ) ; #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * * The implementation of the solvers is inspired by * the lsolver library, by Christian Badura, available from: * http://www.mathematik.uni-freiburg.de * /IAM/Research/projectskr/lin_solver/ * */ #ifndef __NL_ITERATIVE_SOLVERS__ #define __NL_ITERATIVE_SOLVERS__ NLuint nlSolve_CG() ; NLuint nlSolve_CG_precond() ; NLuint nlSolve_BICGSTAB() ; NLuint nlSolve_BICGSTAB_precond() ; NLuint nlSolve_GMRES() ; #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_PRECONDITIONERS__ #define __NL_PRECONDITIONERS__ /******************************************************************************/ /* preconditioners */ void nlPreconditioner_Jacobi(NLdouble* x, NLdouble* y) ; void nlPreconditioner_SSOR(NLdouble* x, NLdouble* y) ; /* Utilities for preconditioners */ /* (use the matrix in the current context) */ void nlMultDiagonal(NLdouble* xy, NLdouble omega) ; void nlMultDiagonalInverse(NLdouble* xy, NLdouble omega) ; void nlMultLowerInverse(NLdouble* x, NLdouble* y, double omega) ; void nlMultUpperInverse(NLdouble* x, NLdouble* y, NLdouble omega) ; #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_SUPERLU__ #define __NL_SUPERLU__ NLboolean nlSolve_SUPERLU() ; #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifndef __NL_CNC_GPU_CUDA__ #define __NL_CNC_GPU_CUDA__ #ifdef __cplusplus extern "C" { #endif NLboolean nlSolverIsCNC(NLint solver) ; NLuint nlSolve_CNC() ; #ifdef __cplusplus } #endif #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifdef WIN32 #include #else #include #include #endif /******************************************************************************/ /* Assertions */ void nl_assertion_failed(const char* cond, const char* file, int line) { fprintf( stderr, "OpenNL assertion failed: %s, file:%s, line:%d\n", cond,file,line ) ; abort() ; } void nl_range_assertion_failed( double x, double min_val, double max_val, const char* file, int line ) { fprintf( stderr, "OpenNL range assertion failed: %f in [ %f ... %f ], file:%s, line:%d\n", x, min_val, max_val, file,line ) ; abort() ; } void nl_should_not_have_reached(const char* file, int line) { fprintf( stderr, "OpenNL should not have reached this point: file:%s, line:%d\n", file,line ) ; abort() ; } /************************************************************************************/ /* Timing */ #ifdef WIN32 NLdouble nlCurrentTime() { return (NLdouble)GetTickCount() / 1000.0 ; } #else double nlCurrentTime() { clock_t user_clock ; struct tms user_tms ; user_clock = times(&user_tms) ; return (NLdouble)user_clock / 100.0 ; } #endif /************************************************************************************/ /* Error-reporting functions */ void nlError(const char* function, const char* message) { fprintf(stderr, "OpenNL error in %s(): %s\n", function, message) ; } void nlWarning(const char* function, const char* message) { fprintf(stderr, "OpenNL warning in %s(): %s\n", function, message) ; } /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ void nlRowColumnConstruct(NLRowColumn* c) { c->size = 0 ; c->capacity = 0 ; c->coeff = NULL ; } void nlRowColumnDestroy(NLRowColumn* c) { NL_DELETE_ARRAY(c->coeff) ; #ifdef NL_PARANOID NL_CLEAR(NLRowColumn, c) ; #endif } void nlRowColumnGrow(NLRowColumn* c) { if(c->capacity != 0) { c->capacity = 2 * c->capacity ; c->coeff = NL_RENEW_ARRAY(NLCoeff, c->coeff, c->capacity) ; } else { c->capacity = 4 ; c->coeff = NL_NEW_ARRAY(NLCoeff, c->capacity) ; } } void nlRowColumnAdd(NLRowColumn* c, NLint index, NLdouble value) { NLuint i ; for(i=0; isize; i++) { if(c->coeff[i].index == index) { c->coeff[i].value += value ; return ; } } if(c->size == c->capacity) { nlRowColumnGrow(c) ; } c->coeff[c->size].index = index ; c->coeff[c->size].value = value ; c->size++ ; } /* Does not check whether the index already exists */ void nlRowColumnAppend(NLRowColumn* c, NLint index, NLdouble value) { if(c->size == c->capacity) { nlRowColumnGrow(c) ; } c->coeff[c->size].index = index ; c->coeff[c->size].value = value ; c->size++ ; } void nlRowColumnZero(NLRowColumn* c) { c->size = 0 ; } void nlRowColumnClear(NLRowColumn* c) { c->size = 0 ; c->capacity = 0 ; NL_DELETE_ARRAY(c->coeff) ; } static int nlCoeffCompare(const void* p1, const void* p2) { return (((NLCoeff*)(p2))->index > ((NLCoeff*)(p1))->index) ; } void nlRowColumnSort(NLRowColumn* c) { qsort(c->coeff, c->size, sizeof(NLCoeff), nlCoeffCompare) ; } /******************************************************************************/ /* SparseMatrix data structure */ void nlSparseMatrixConstruct( NLSparseMatrix* M, NLuint m, NLuint n, NLenum storage ) { NLuint i ; M->m = m ; M->n = n ; M->storage = storage ; if(storage & NL_MATRIX_STORE_ROWS) { M->row = NL_NEW_ARRAY(NLRowColumn, m) ; for(i=0; irow[i])) ; } } else { M->row = NULL ; } if(storage & NL_MATRIX_STORE_COLUMNS) { M->column = NL_NEW_ARRAY(NLRowColumn, n) ; for(i=0; icolumn[i])) ; } } else { M->column = NULL ; } M->diag_size = MIN(m,n) ; M->diag = NL_NEW_ARRAY(NLdouble, M->diag_size) ; } void nlSparseMatrixDestroy(NLSparseMatrix* M) { NLuint i ; NL_DELETE_ARRAY(M->diag) ; if(M->storage & NL_MATRIX_STORE_ROWS) { for(i=0; im; i++) { nlRowColumnDestroy(&(M->row[i])) ; } NL_DELETE_ARRAY(M->row) ; } if(M->storage & NL_MATRIX_STORE_COLUMNS) { for(i=0; in; i++) { nlRowColumnDestroy(&(M->column[i])) ; } NL_DELETE_ARRAY(M->column) ; } #ifdef NL_PARANOID NL_CLEAR(NLSparseMatrix,M) ; #endif } void nlSparseMatrixAdd(NLSparseMatrix* M, NLuint i, NLuint j, NLdouble value) { nl_parano_range_assert(i, 0, M->m - 1) ; nl_parano_range_assert(j, 0, M->n - 1) ; if((M->storage & NL_MATRIX_STORE_SYMMETRIC) && (j > i)) { return ; } if(i == j) { M->diag[i] += value ; } if(M->storage & NL_MATRIX_STORE_ROWS) { nlRowColumnAdd(&(M->row[i]), j, value) ; } if(M->storage & NL_MATRIX_STORE_COLUMNS) { nlRowColumnAdd(&(M->column[j]), i, value) ; } } void nlSparseMatrixZero( NLSparseMatrix* M) { NLuint i ; if(M->storage & NL_MATRIX_STORE_ROWS) { for(i=0; im; i++) { nlRowColumnZero(&(M->row[i])) ; } } if(M->storage & NL_MATRIX_STORE_COLUMNS) { for(i=0; in; i++) { nlRowColumnZero(&(M->column[i])) ; } } NL_CLEAR_ARRAY(NLdouble, M->diag, M->diag_size) ; } void nlSparseMatrixClear( NLSparseMatrix* M) { NLuint i ; if(M->storage & NL_MATRIX_STORE_ROWS) { for(i=0; im; i++) { nlRowColumnClear(&(M->row[i])) ; } } if(M->storage & NL_MATRIX_STORE_COLUMNS) { for(i=0; in; i++) { nlRowColumnClear(&(M->column[i])) ; } } NL_CLEAR_ARRAY(NLdouble, M->diag, M->diag_size) ; } /* Returns the number of non-zero coefficients */ NLuint nlSparseMatrixNNZ( NLSparseMatrix* M) { NLuint nnz = 0 ; NLuint i ; if(M->storage & NL_MATRIX_STORE_ROWS) { for(i = 0; im; i++) { nnz += M->row[i].size ; } } else if (M->storage & NL_MATRIX_STORE_COLUMNS) { for(i = 0; in; i++) { nnz += M->column[i].size ; } } else { nl_assert_not_reached ; } return nnz ; } void nlSparseMatrixSort( NLSparseMatrix* M) { NLuint i ; if(M->storage & NL_MATRIX_STORE_ROWS) { for(i = 0; im; i++) { nlRowColumnSort(&(M->row[i])) ; } } if (M->storage & NL_MATRIX_STORE_COLUMNS) { for(i = 0; in; i++) { nlRowColumnSort(&(M->row[i])) ; } } } /************************************************************************************/ /* SparseMatrix x Vector routines, internal helper routines */ static void nlSparseMatrix_mult_rows_symmetric( NLSparseMatrix* A, NLdouble* x, NLdouble* y) { NLuint m = A->m ; NLuint i,ij ; NLRowColumn* Ri = NULL ; NLCoeff* c = NULL ; for(i=0; irow[i]) ; for(ij=0; ijsize; ij++) { c = &(Ri->coeff[ij]) ; y[i] += c->value * x[c->index] ; if(i != c->index) { y[c->index] += c->value * x[i] ; } } } } static void nlSparseMatrix_mult_rows( NLSparseMatrix* A, NLdouble* x, NLdouble* y) { NLuint m = A->m ; NLuint i,ij ; NLRowColumn* Ri = NULL ; NLCoeff* c = NULL ; for(i=0; irow[i]) ; for(ij=0; ijsize; ij++) { c = &(Ri->coeff[ij]) ; y[i] += c->value * x[c->index] ; } } } static void nlSparseMatrix_mult_cols_symmetric( NLSparseMatrix* A, NLdouble* x, NLdouble* y) { NLuint n = A->n ; NLuint j,ii ; NLRowColumn* Cj = NULL ; NLCoeff* c = NULL ; for(j=0; jcolumn[j]) ; for(ii=0; iisize; ii++) { c = &(Cj->coeff[ii]) ; y[c->index] += c->value * x[j] ; if(j != c->index) { y[j] += c->value * x[c->index] ; } } } } static void nlSparseMatrix_mult_cols( NLSparseMatrix* A, NLdouble* x, NLdouble* y) { NLuint n = A->n ; NLuint j,ii ; NLRowColumn* Cj = NULL ; NLCoeff* c = NULL ; NL_CLEAR_ARRAY(NLdouble, y, A->m) ; for(j=0; jcolumn[j]) ; for(ii=0; iisize; ii++) { c = &(Cj->coeff[ii]) ; y[c->index] += c->value * x[j] ; } } } /************************************************************************************/ /* SparseMatrix x Vector routines, main driver routine */ void nlSparseMatrixMult(NLSparseMatrix* A, NLdouble* x, NLdouble* y) { if(A->storage & NL_MATRIX_STORE_ROWS) { if(A->storage & NL_MATRIX_STORE_SYMMETRIC) { nlSparseMatrix_mult_rows_symmetric(A, x, y) ; } else { nlSparseMatrix_mult_rows(A, x, y) ; } } else { if(A->storage & NL_MATRIX_STORE_SYMMETRIC) { nlSparseMatrix_mult_cols_symmetric(A, x, y) ; } else { nlSparseMatrix_mult_cols(A, x, y) ; } } } /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ NLContextStruct* nlCurrentContext = NULL ; void nlMatrixVectorProd_default(NLdouble* x, NLdouble* y) { nlSparseMatrixMult(&(nlCurrentContext->M), x, y) ; } NLContext nlNewContext() { NLContextStruct* result = NL_NEW(NLContextStruct) ; result->state = NL_STATE_INITIAL ; result->solver = NL_BICGSTAB ; result->max_iterations = 100 ; result->threshold = 1e-6 ; result->omega = 1.5 ; result->row_scaling = 1.0 ; result->right_hand_side = 0.0 ; result->inner_iterations = 5 ; result->matrix_vector_prod = nlMatrixVectorProd_default ; result->solver_func = nlDefaultSolver ; nlMakeCurrent(result) ; return result ; } void nlDeleteContext(NLContext context_in) { NLContextStruct* context = (NLContextStruct*)(context_in) ; if(nlCurrentContext == context) { nlCurrentContext = NULL ; } if(context->alloc_M) { nlSparseMatrixDestroy(&context->M) ; } if(context->alloc_af) { nlRowColumnDestroy(&context->af) ; } if(context->alloc_al) { nlRowColumnDestroy(&context->al) ; } if(context->alloc_xl) { nlRowColumnDestroy(&context->xl) ; } if(context->alloc_variable) { NL_DELETE_ARRAY(context->variable) ; } if(context->alloc_x) { NL_DELETE_ARRAY(context->x) ; } if(context->alloc_b) { NL_DELETE_ARRAY(context->b) ; } #ifdef NL_PARANOID NL_CLEAR(NLContextStruct, context) ; #endif NL_DELETE(context) ; } void nlMakeCurrent(NLContext context) { nlCurrentContext = (NLContextStruct*)(context) ; } NLContext nlGetCurrent() { return nlCurrentContext ; } /************************************************************************/ /* Finite state automaton */ void nlCheckState(NLenum state) { nl_assert(nlCurrentContext->state == state) ; } void nlTransition(NLenum from_state, NLenum to_state) { nlCheckState(from_state) ; nlCurrentContext->state = to_state ; } /************************************************************************/ /* Default solver */ static void nlSetupPreconditioner() { switch(nlCurrentContext->preconditioner) { case NL_PRECOND_NONE: nlCurrentContext->precond_vector_prod = NULL ; break ; case NL_PRECOND_JACOBI: nlCurrentContext->precond_vector_prod = nlPreconditioner_Jacobi ; break ; case NL_PRECOND_SSOR: nlCurrentContext->precond_vector_prod = nlPreconditioner_SSOR ; break ; default: nl_assert_not_reached ; break ; } /* Check compatibility between solver and preconditioner */ if( nlCurrentContext->solver == NL_BICGSTAB && nlCurrentContext->preconditioner == NL_PRECOND_SSOR ) { nlWarning( "nlSolve", "cannot use SSOR preconditioner with non-symmetric matrix, switching to Jacobi" ) ; nlCurrentContext->preconditioner = NL_PRECOND_JACOBI ; nlCurrentContext->precond_vector_prod = nlPreconditioner_Jacobi ; } if( nlCurrentContext->solver == NL_GMRES && nlCurrentContext->preconditioner != NL_PRECOND_NONE ) { nlWarning("nlSolve", "Preconditioner not implemented yet for GMRES") ; nlCurrentContext->preconditioner = NL_PRECOND_NONE ; nlCurrentContext->precond_vector_prod = NULL ; } if( nlCurrentContext->solver == NL_SUPERLU_EXT && nlCurrentContext->preconditioner != NL_PRECOND_NONE ) { nlWarning("nlSolve", "Preconditioner not implemented yet for SUPERLU") ; nlCurrentContext->preconditioner = NL_PRECOND_NONE ; nlCurrentContext->precond_vector_prod = NULL ; } if( nlCurrentContext->solver == NL_PERM_SUPERLU_EXT && nlCurrentContext->preconditioner != NL_PRECOND_NONE ) { nlWarning("nlSolve", "Preconditioner not implemented yet for PERMSUPERLU") ; nlCurrentContext->preconditioner = NL_PRECOND_NONE ; nlCurrentContext->precond_vector_prod = NULL ; } if( nlCurrentContext->solver == NL_SYMMETRIC_SUPERLU_EXT && nlCurrentContext->preconditioner != NL_PRECOND_NONE ) { nlWarning("nlSolve", "Preconditioner not implemented yet for PERMSUPERLU") ; nlCurrentContext->preconditioner = NL_PRECOND_NONE ; nlCurrentContext->precond_vector_prod = NULL ; } } NLboolean nlDefaultSolver() { NLboolean result = NL_TRUE ; nlSetupPreconditioner() ; switch(nlCurrentContext->solver) { case NL_CG: { if(nlCurrentContext->preconditioner == NL_PRECOND_NONE) { nlCurrentContext->used_iterations = nlSolve_CG() ; } else { nlCurrentContext->used_iterations = nlSolve_CG_precond() ; } } break ; case NL_BICGSTAB: { if(nlCurrentContext->preconditioner == NL_PRECOND_NONE) { nlCurrentContext->used_iterations = nlSolve_BICGSTAB() ; } else { nlCurrentContext->used_iterations = nlSolve_BICGSTAB_precond() ; } } break ; case NL_GMRES: { nlCurrentContext->used_iterations = nlSolve_GMRES() ; } break ; case NL_CNC_FLOAT_CRS: case NL_CNC_DOUBLE_CRS: case NL_CNC_FLOAT_BCRS2: case NL_CNC_DOUBLE_BCRS2: case NL_CNC_FLOAT_ELL: case NL_CNC_DOUBLE_ELL: case NL_CNC_FLOAT_HYB: case NL_CNC_DOUBLE_HYB: { nlCurrentContext->used_iterations = nlSolve_CNC() ; } break ; case NL_SUPERLU_EXT: case NL_PERM_SUPERLU_EXT: case NL_SYMMETRIC_SUPERLU_EXT: { result = nlSolve_SUPERLU() ; } break ; default: nl_assert_not_reached ; } return result ; } /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ #ifdef NL_USE_ATLAS int NL_FORTRAN_WRAP(xerbla)(char *srname, int *info) { printf("** On entry to %6s, parameter number %2d had an illegal value\n", srname, *info ); return 0; } #ifndef NL_USE_BLAS #define NL_USE_BLAS #endif #endif #ifdef NL_USE_SUPERLU #ifndef NL_USE_BLAS #define NL_USE_BLAS /* * The BLAS included in SuperLU does not have DTPSV, * we use the DTPSV embedded in OpenNL. */ #define NEEDS_DTPSV #endif #endif #ifndef NL_USE_BLAS #define NEEDS_DTPSV #endif /************************************************************************/ /* BLAS routines */ /* copy-pasted from CBLAS (i.e. generated from f2c) */ /* * lsame * xerbla * daxpy * ddot * dscal * dnrm2 * dcopy * dgemv * dtpsv */ typedef NLint integer ; typedef NLdouble doublereal ; typedef NLboolean logical ; typedef NLint ftnlen ; #ifndef max #define max(x,y) ((x) > (y) ? (x) : (y)) #endif #ifndef NL_USE_BLAS int NL_FORTRAN_WRAP(lsame)(char *ca, char *cb) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= LSAME returns .TRUE. if CA is the same letter as CB regardless of case. Arguments ========= CA (input) CHARACTER*1 CB (input) CHARACTER*1 CA and CB specify the single characters to be compared. ===================================================================== */ /* System generated locals */ int ret_val; /* Local variables */ int inta, intb, zcode; ret_val = *(unsigned char *)ca == *(unsigned char *)cb; if (ret_val) { return ret_val; } /* Now test for equivalence if both characters are alphabetic. */ zcode = 'Z'; /* Use 'Z' rather than 'A' so that ASCII can be detected on Prime machines, on which ICHAR returns a value with bit 8 set. ICHAR('A') on Prime machines returns 193 which is the same as ICHAR('A') on an EBCDIC machine. */ inta = *(unsigned char *)ca; intb = *(unsigned char *)cb; if (zcode == 90 || zcode == 122) { /* ASCII is assumed - ZCODE is the ASCII code of either lower or upper case 'Z'. */ if (inta >= 97 && inta <= 122) inta += -32; if (intb >= 97 && intb <= 122) intb += -32; } else if (zcode == 233 || zcode == 169) { /* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or upper case 'Z'. */ if ((inta >= 129 && inta <= 137) || (inta >= 145 && inta <= 153) || (inta >= 162 && inta <= 169) ) inta += 64; if ( (intb >= 129 && intb <= 137) || (intb >= 145 && intb <= 153) || (intb >= 162 && intb <= 169) ) intb += 64; } else if (zcode == 218 || zcode == 250) { /* ASCII is assumed, on Prime machines - ZCODE is the ASCII code plus 128 of either lower or upper case 'Z'. */ if (inta >= 225 && inta <= 250) inta += -32; if (intb >= 225 && intb <= 250) intb += -32; } ret_val = inta == intb; return ret_val; } /* lsame_ */ /* Subroutine */ int NL_FORTRAN_WRAP(xerbla)(char *srname, int *info) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= XERBLA is an error handler for the LAPACK routines. It is called by an LAPACK routine if an input parameter has an invalid value. A message is printed and execution stops. Installers may consider modifying the STOP statement in order to call system-specific exception-handling facilities. Arguments ========= SRNAME (input) CHARACTER*6 The name of the routine which called XERBLA. INFO (input) INT The position of the invalid parameter in the parameter list of the calling routine. ===================================================================== */ printf("** On entry to %6s, parameter number %2d had an illegal value\n", srname, *info); /* End of XERBLA */ return 0; } /* xerbla_ */ /* Subroutine */ int NL_FORTRAN_WRAP(daxpy)(integer *n, doublereal *da, doublereal *dx, integer *incx, doublereal *dy, integer *incy) { /* System generated locals */ integer i__1; /* Local variables */ static integer i, m, ix, iy, mp1; /* constant times a vector plus a vector. uses unrolled loops for increments equal to one. jack dongarra, linpack, 3/11/78. modified 12/3/93, array(1) declarations changed to array(*) Parameter adjustments Function Body */ #define DY(I) dy[(I)-1] #define DX(I) dx[(I)-1] if (*n <= 0) { return 0; } if (*da == 0.) { return 0; } if (*incx == 1 && *incy == 1) { goto L20; } /* code for unequal increments or equal increments not equal to 1 */ ix = 1; iy = 1; if (*incx < 0) { ix = (-(*n) + 1) * *incx + 1; } if (*incy < 0) { iy = (-(*n) + 1) * *incy + 1; } i__1 = *n; for (i = 1; i <= *n; ++i) { DY(iy) += *da * DX(ix); ix += *incx; iy += *incy; /* L10: */ } return 0; /* code for both increments equal to 1 clean-up loop */ L20: m = *n % 4; if (m == 0) { goto L40; } i__1 = m; for (i = 1; i <= m; ++i) { DY(i) += *da * DX(i); /* L30: */ } if (*n < 4) { return 0; } L40: mp1 = m + 1; i__1 = *n; for (i = mp1; i <= *n; i += 4) { DY(i) += *da * DX(i); DY(i + 1) += *da * DX(i + 1); DY(i + 2) += *da * DX(i + 2); DY(i + 3) += *da * DX(i + 3); /* L50: */ } return 0; } /* daxpy_ */ #undef DY #undef DX doublereal NL_FORTRAN_WRAP(ddot)(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy) { /* System generated locals */ integer i__1; doublereal ret_val; /* Local variables */ static integer i, m; static doublereal dtemp; static integer ix, iy, mp1; /* forms the dot product of two vectors. uses unrolled loops for increments equal to one. jack dongarra, linpack, 3/11/78. modified 12/3/93, array(1) declarations changed to array(*) Parameter adjustments Function Body */ #define DY(I) dy[(I)-1] #define DX(I) dx[(I)-1] ret_val = 0.; dtemp = 0.; if (*n <= 0) { return ret_val; } if (*incx == 1 && *incy == 1) { goto L20; } /* code for unequal increments or equal increments not equal to 1 */ ix = 1; iy = 1; if (*incx < 0) { ix = (-(*n) + 1) * *incx + 1; } if (*incy < 0) { iy = (-(*n) + 1) * *incy + 1; } i__1 = *n; for (i = 1; i <= *n; ++i) { dtemp += DX(ix) * DY(iy); ix += *incx; iy += *incy; /* L10: */ } ret_val = dtemp; return ret_val; /* code for both increments equal to 1 clean-up loop */ L20: m = *n % 5; if (m == 0) { goto L40; } i__1 = m; for (i = 1; i <= m; ++i) { dtemp += DX(i) * DY(i); /* L30: */ } if (*n < 5) { goto L60; } L40: mp1 = m + 1; i__1 = *n; for (i = mp1; i <= *n; i += 5) { dtemp = dtemp + DX(i) * DY(i) + DX(i + 1) * DY(i + 1) + DX(i + 2) * DY(i + 2) + DX(i + 3) * DY(i + 3) + DX(i + 4) * DY(i + 4); /* L50: */ } L60: ret_val = dtemp; return ret_val; } /* ddot_ */ #undef DY #undef DX /* Subroutine */ int NL_FORTRAN_WRAP(dscal)(integer *n, doublereal *da, doublereal *dx, integer *incx) { /* System generated locals */ integer i__1, i__2; /* Local variables */ static integer i, m, nincx, mp1; /* scales a vector by a constant. uses unrolled loops for increment equal to one. jack dongarra, linpack, 3/11/78. modified 3/93 to return if incx .le. 0. modified 12/3/93, array(1) declarations changed to array(*) Parameter adjustments Function Body */ #ifdef DX #undef DX #endif #define DX(I) dx[(I)-1] if (*n <= 0 || *incx <= 0) { return 0; } if (*incx == 1) { goto L20; } /* code for increment not equal to 1 */ nincx = *n * *incx; i__1 = nincx; i__2 = *incx; for (i = 1; *incx < 0 ? i >= nincx : i <= nincx; i += *incx) { DX(i) = *da * DX(i); /* L10: */ } return 0; /* code for increment equal to 1 clean-up loop */ L20: m = *n % 5; if (m == 0) { goto L40; } i__2 = m; for (i = 1; i <= m; ++i) { DX(i) = *da * DX(i); /* L30: */ } if (*n < 5) { return 0; } L40: mp1 = m + 1; i__2 = *n; for (i = mp1; i <= *n; i += 5) { DX(i) = *da * DX(i); DX(i + 1) = *da * DX(i + 1); DX(i + 2) = *da * DX(i + 2); DX(i + 3) = *da * DX(i + 3); DX(i + 4) = *da * DX(i + 4); /* L50: */ } return 0; } /* dscal_ */ #undef DX doublereal NL_FORTRAN_WRAP(dnrm2)(integer *n, doublereal *x, integer *incx) { /* System generated locals */ integer i__1, i__2; doublereal ret_val, d__1; /* Builtin functions */ double sqrt(doublereal); /* Local variables */ static doublereal norm, scale, absxi; static integer ix; static doublereal ssq; /* DNRM2 returns the euclidean norm of a vector via the function name, so that DNRM2 := sqrt( x'*x ) -- This version written on 25-October-1982. Modified on 14-October-1993 to inline the call to DLASSQ. Sven Hammarling, Nag Ltd. Parameter adjustments Function Body */ #ifdef X #undef X #endif #define X(I) x[(I)-1] if (*n < 1 || *incx < 1) { norm = 0.; } else if (*n == 1) { norm = fabs(X(1)); } else { scale = 0.; ssq = 1.; /* The following loop is equivalent to this call to the LAPACK auxiliary routine: CALL DLASSQ( N, X, INCX, SCALE, SSQ ) */ i__1 = (*n - 1) * *incx + 1; i__2 = *incx; for (ix = 1; *incx < 0 ? ix >= (*n-1)**incx+1 : ix <= (*n-1)**incx+1; ix += *incx) { if (X(ix) != 0.) { absxi = (d__1 = X(ix), fabs(d__1)); if (scale < absxi) { /* Computing 2nd power */ d__1 = scale / absxi; ssq = ssq * (d__1 * d__1) + 1.; scale = absxi; } else { /* Computing 2nd power */ d__1 = absxi / scale; ssq += d__1 * d__1; } } /* L10: */ } norm = scale * sqrt(ssq); } ret_val = norm; return ret_val; /* End of DNRM2. */ } /* dnrm2_ */ #undef X /* Subroutine */ int NL_FORTRAN_WRAP(dcopy)(integer *n, doublereal *dx, integer *incx, doublereal *dy, integer *incy) { /* System generated locals */ integer i__1; /* Local variables */ static integer i, m, ix, iy, mp1; /* copies a vector, x, to a vector, y. uses unrolled loops for increments equal to one. jack dongarra, linpack, 3/11/78. modified 12/3/93, array(1) declarations changed to array(*) Parameter adjustments Function Body */ #define DY(I) dy[(I)-1] #define DX(I) dx[(I)-1] if (*n <= 0) { return 0; } if (*incx == 1 && *incy == 1) { goto L20; } /* code for unequal increments or equal increments not equal to 1 */ ix = 1; iy = 1; if (*incx < 0) { ix = (-(*n) + 1) * *incx + 1; } if (*incy < 0) { iy = (-(*n) + 1) * *incy + 1; } i__1 = *n; for (i = 1; i <= *n; ++i) { DY(iy) = DX(ix); ix += *incx; iy += *incy; /* L10: */ } return 0; /* code for both increments equal to 1 clean-up loop */ L20: m = *n % 7; if (m == 0) { goto L40; } i__1 = m; for (i = 1; i <= m; ++i) { DY(i) = DX(i); /* L30: */ } if (*n < 7) { return 0; } L40: mp1 = m + 1; i__1 = *n; for (i = mp1; i <= *n; i += 7) { DY(i) = DX(i); DY(i + 1) = DX(i + 1); DY(i + 2) = DX(i + 2); DY(i + 3) = DX(i + 3); DY(i + 4) = DX(i + 4); DY(i + 5) = DX(i + 5); DY(i + 6) = DX(i + 6); /* L50: */ } return 0; } /* dcopy_ */ #undef DX #undef DY /* Subroutine */ int NL_FORTRAN_WRAP(dgemv)(char *trans, integer *m, integer *n, doublereal * alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, doublereal *beta, doublereal *y, integer *incy) { /* System generated locals */ /* integer a_dim1, a_offset ; */ integer i__1, i__2; /* Local variables */ static integer info; static doublereal temp; static integer lenx, leny, i, j; /* extern logical lsame_(char *, char *); */ static integer ix, iy, jx, jy, kx, ky; /* extern int xerbla_(char *, integer *); */ /* Purpose ======= DGEMV performs one of the matrix-vector operations y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, where alpha and beta are scalars, x and y are vectors and A is an m by n matrix. Parameters ========== TRANS - CHARACTER*1. On entry, TRANS specifies the operation to be performed as follows: TRANS = 'N' or 'n' y := alpha*A*x + beta*y. TRANS = 'T' or 't' y := alpha*A'*x + beta*y. TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. Unchanged on exit. M - INTEGER. On entry, M specifies the number of rows of the matrix A. M must be at least zero. Unchanged on exit. N - INTEGER. On entry, N specifies the number of columns of the matrix A. N must be at least zero. Unchanged on exit. ALPHA - DOUBLE PRECISION. On entry, ALPHA specifies the scalar alpha. Unchanged on exit. A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). Before entry, the leading m by n part of the array A must contain the matrix of coefficients. Unchanged on exit. LDA - INTEGER. On entry, LDA specifies the first dimension of A as declared in the calling (sub) program. LDA must be at least max( 1, m ). Unchanged on exit. X - DOUBLE PRECISION array of DIMENSION at least ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' and at least ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. Before entry, the incremented array X must contain the vector x. Unchanged on exit. INCX - INTEGER. On entry, INCX specifies the increment for the elements of X. INCX must not be zero. Unchanged on exit. BETA - DOUBLE PRECISION. On entry, BETA specifies the scalar beta. When BETA is supplied as zero then Y need not be set on input. Unchanged on exit. Y - DOUBLE PRECISION array of DIMENSION at least ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' and at least ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. Before entry with BETA non-zero, the incremented array Y must contain the vector y. On exit, Y is overwritten by the updated vector y. INCY - INTEGER. On entry, INCY specifies the increment for the elements of Y. INCY must not be zero. Unchanged on exit. Level 2 Blas routine. -- Written on 22-October-1986. Jack Dongarra, Argonne National Lab. Jeremy Du Croz, Nag Central Office. Sven Hammarling, Nag Central Office. Richard Hanson, Sandia National Labs. Test the input parameters. Parameter adjustments Function Body */ #define X(I) x[(I)-1] #define Y(I) y[(I)-1] #define A(I,J) a[(I)-1 + ((J)-1)* ( *lda)] info = 0; if (! NL_FORTRAN_WRAP(lsame)(trans, "N") && ! NL_FORTRAN_WRAP(lsame)(trans, "T") && ! NL_FORTRAN_WRAP(lsame)(trans, "C")) { info = 1; } else if (*m < 0) { info = 2; } else if (*n < 0) { info = 3; } else if (*lda < max(1,*m)) { info = 6; } else if (*incx == 0) { info = 8; } else if (*incy == 0) { info = 11; } if (info != 0) { NL_FORTRAN_WRAP(xerbla)("DGEMV ", &info); return 0; } /* Quick return if possible. */ if (*m == 0 || *n == 0 || (*alpha == 0. && *beta == 1.)) { return 0; } /* Set LENX and LENY, the lengths of the vectors x and y, and set up the start points in X and Y. */ if (NL_FORTRAN_WRAP(lsame)(trans, "N")) { lenx = *n; leny = *m; } else { lenx = *m; leny = *n; } if (*incx > 0) { kx = 1; } else { kx = 1 - (lenx - 1) * *incx; } if (*incy > 0) { ky = 1; } else { ky = 1 - (leny - 1) * *incy; } /* Start the operations. In this version the elements of A are accessed sequentially with one pass through A. First form y := beta*y. */ if (*beta != 1.) { if (*incy == 1) { if (*beta == 0.) { i__1 = leny; for (i = 1; i <= leny; ++i) { Y(i) = 0.; /* L10: */ } } else { i__1 = leny; for (i = 1; i <= leny; ++i) { Y(i) = *beta * Y(i); /* L20: */ } } } else { iy = ky; if (*beta == 0.) { i__1 = leny; for (i = 1; i <= leny; ++i) { Y(iy) = 0.; iy += *incy; /* L30: */ } } else { i__1 = leny; for (i = 1; i <= leny; ++i) { Y(iy) = *beta * Y(iy); iy += *incy; /* L40: */ } } } } if (*alpha == 0.) { return 0; } if (NL_FORTRAN_WRAP(lsame)(trans, "N")) { /* Form y := alpha*A*x + y. */ jx = kx; if (*incy == 1) { i__1 = *n; for (j = 1; j <= *n; ++j) { if (X(jx) != 0.) { temp = *alpha * X(jx); i__2 = *m; for (i = 1; i <= *m; ++i) { Y(i) += temp * A(i,j); /* L50: */ } } jx += *incx; /* L60: */ } } else { i__1 = *n; for (j = 1; j <= *n; ++j) { if (X(jx) != 0.) { temp = *alpha * X(jx); iy = ky; i__2 = *m; for (i = 1; i <= *m; ++i) { Y(iy) += temp * A(i,j); iy += *incy; /* L70: */ } } jx += *incx; /* L80: */ } } } else { /* Form y := alpha*A'*x + y. */ jy = ky; if (*incx == 1) { i__1 = *n; for (j = 1; j <= *n; ++j) { temp = 0.; i__2 = *m; for (i = 1; i <= *m; ++i) { temp += A(i,j) * X(i); /* L90: */ } Y(jy) += *alpha * temp; jy += *incy; /* L100: */ } } else { i__1 = *n; for (j = 1; j <= *n; ++j) { temp = 0.; ix = kx; i__2 = *m; for (i = 1; i <= *m; ++i) { temp += A(i,j) * X(ix); ix += *incx; /* L110: */ } Y(jy) += *alpha * temp; jy += *incy; /* L120: */ } } } return 0; /* End of DGEMV . */ } /* dgemv_ */ #undef X #undef Y #undef A #else extern void NL_FORTRAN_WRAP(daxpy)( int *n, double *alpha, double *x, int *incx, double *y, int *incy ) ; extern double NL_FORTRAN_WRAP(ddot)( int *n, double *x, int *incx, double *y, int *incy ) ; extern double NL_FORTRAN_WRAP(dnrm2)( int *n, double *x, int *incx ) ; extern int NL_FORTRAN_WRAP(dcopy)(int* n, double* dx, int* incx, double* dy, int* incy) ; extern void NL_FORTRAN_WRAP(dscal)(int* n, double* alpha, double *x, int* incx) ; #ifndef NEEDS_DTPSV extern void NL_FORTRAN_WRAP(dtpsv)( char *uplo, char *trans, char *diag, int *n, double *AP, double *x, int *incx ) ; #endif extern void NL_FORTRAN_WRAP(dgemv)( char *trans, int *m, int *n, double *alpha, double *A, int *ldA, double *x, int *incx, double *beta, double *y, int *incy ) ; #endif #ifdef NEEDS_DTPSV /* DECK DTPSV */ /* Subroutine */ int NL_FORTRAN_WRAP(dtpsv)(uplo, trans, diag, n, ap, x, incx, uplo_len, trans_len, diag_len) char *uplo, *trans, *diag; integer *n; doublereal *ap, *x; integer *incx; ftnlen uplo_len; ftnlen trans_len; ftnlen diag_len; { /* System generated locals */ integer i__1, i__2; /* Local variables */ static integer info; static doublereal temp; static integer i__, j, k; /* extern logical lsame_(); */ static integer kk, ix, jx, kx; /* extern int xerbla_(); */ static logical nounit; /* ***BEGIN PROLOGUE DTPSV */ /* ***PURPOSE Solve one of the systems of equations. */ /* ***LIBRARY SLATEC (BLAS) */ /* ***CATEGORY D1B4 */ /* ***TYPE DOUBLE PRECISION (STPSV-S, DTPSV-D, CTPSV-C) */ /* ***KEYWORDS LEVEL 2 BLAS, LINEAR ALGEBRA */ /* ***AUTHOR Dongarra, J. J., (ANL) */ /* Du Croz, J., (NAG) */ /* Hammarling, S., (NAG) */ /* Hanson, R. J., (SNLA) */ /* ***DESCRIPTION */ /* DTPSV solves one of the systems of equations */ /* A*x = b, or A'*x = b, */ /* where b and x are n element vectors and A is an n by n unit, or */ /* non-unit, upper or lower triangular matrix, supplied in packed form. */ /* No test for singularity or near-singularity is included in this */ /* routine. Such tests must be performed before calling this routine. */ /* Parameters */ /* ========== */ /* UPLO - CHARACTER*1. */ /* On entry, UPLO specifies whether the matrix is an upper or */ /* lower triangular matrix as follows: */ /* UPLO = 'U' or 'u' A is an upper triangular matrix. */ /* UPLO = 'L' or 'l' A is a lower triangular matrix. */ /* Unchanged on exit. */ /* TRANS - CHARACTER*1. */ /* On entry, TRANS specifies the equations to be solved as */ /* follows: */ /* TRANS = 'N' or 'n' A*x = b. */ /* TRANS = 'T' or 't' A'*x = b. */ /* TRANS = 'C' or 'c' A'*x = b. */ /* Unchanged on exit. */ /* DIAG - CHARACTER*1. */ /* On entry, DIAG specifies whether or not A is unit */ /* triangular as follows: */ /* DIAG = 'U' or 'u' A is assumed to be unit triangular. */ /* DIAG = 'N' or 'n' A is not assumed to be unit */ /* triangular. */ /* Unchanged on exit. */ /* N - INTEGER. */ /* On entry, N specifies the order of the matrix A. */ /* N must be at least zero. */ /* Unchanged on exit. */ /* AP - DOUBLE PRECISION array of DIMENSION at least */ /* ( ( n*( n + 1))/2). */ /* Before entry with UPLO = 'U' or 'u', the array AP must */ /* contain the upper triangular matrix packed sequentially, */ /* column by column, so that AP( 1 ) contains a( 1, 1 ), */ /* AP( 2 ) and AP( 3 ) contain a( 1, 2 ) and a( 2, 2 ) */ /* respectively, and so on. */ /* Before entry with UPLO = 'L' or 'l', the array AP must */ /* contain the lower triangular matrix packed sequentially, */ /* column by column, so that AP( 1 ) contains a( 1, 1 ), */ /* AP( 2 ) and AP( 3 ) contain a( 2, 1 ) and a( 3, 1 ) */ /* respectively, and so on. */ /* Note that when DIAG = 'U' or 'u', the diagonal elements of */ /* A are not referenced, but are assumed to be unity. */ /* Unchanged on exit. */ /* X - DOUBLE PRECISION array of dimension at least */ /* ( 1 + ( n - 1 )*abs( INCX ) ). */ /* Before entry, the incremented array X must contain the n */ /* element right-hand side vector b. On exit, X is overwritten */ /* with the solution vector x. */ /* INCX - INTEGER. */ /* On entry, INCX specifies the increment for the elements of */ /* X. INCX must not be zero. */ /* Unchanged on exit. */ /* ***REFERENCES Dongarra, J. J., Du Croz, J., Hammarling, S., and */ /* Hanson, R. J. An extended set of Fortran basic linear */ /* algebra subprograms. ACM TOMS, Vol. 14, No. 1, */ /* pp. 1-17, March 1988. */ /* ***ROUTINES CALLED LSAME, XERBLA */ /* ***REVISION HISTORY (YYMMDD) */ /* 861022 DATE WRITTEN */ /* 910605 Modified to meet SLATEC prologue standards. Only comment */ /* lines were modified. (BKS) */ /* ***END PROLOGUE DTPSV */ /* .. Scalar Arguments .. */ /* .. Array Arguments .. */ /* .. Parameters .. */ /* .. Local Scalars .. */ /* .. External Functions .. */ /* .. External Subroutines .. */ /* ***FIRST EXECUTABLE STATEMENT DTPSV */ /* Test the input parameters. */ /* Parameter adjustments */ --x; --ap; /* Function Body */ info = 0; if (!NL_FORTRAN_WRAP(lsame)(uplo, "U") && !NL_FORTRAN_WRAP(lsame)(uplo, "L") ) { info = 1; } else if ( !NL_FORTRAN_WRAP(lsame)(trans, "N") && !NL_FORTRAN_WRAP(lsame)(trans, "T") && !NL_FORTRAN_WRAP(lsame)(trans, "C") ) { info = 2; } else if ( !NL_FORTRAN_WRAP(lsame)(diag, "U") && !NL_FORTRAN_WRAP(lsame)(diag, "N") ) { info = 3; } else if (*n < 0) { info = 4; } else if (*incx == 0) { info = 7; } if (info != 0) { NL_FORTRAN_WRAP(xerbla)("DTPSV ", &info); return 0; } /* Quick return if possible. */ if (*n == 0) { return 0; } nounit = NL_FORTRAN_WRAP(lsame)(diag, "N"); /* Set up the start point in X if the increment is not unity. This */ /* will be ( N - 1 )*INCX too small for descending loops. */ if (*incx <= 0) { kx = 1 - (*n - 1) * *incx; } else if (*incx != 1) { kx = 1; } /* Start the operations. In this version the elements of AP are */ /* accessed sequentially with one pass through AP. */ if (NL_FORTRAN_WRAP(lsame)(trans, "N")) { /* Form x := inv( A )*x. */ if (NL_FORTRAN_WRAP(lsame)(uplo, "U")) { kk = *n * (*n + 1) / 2; if (*incx == 1) { for (j = *n; j >= 1; --j) { if (x[j] != 0.) { if (nounit) { x[j] /= ap[kk]; } temp = x[j]; k = kk - 1; for (i__ = j - 1; i__ >= 1; --i__) { x[i__] -= temp * ap[k]; --k; /* L10: */ } } kk -= j; /* L20: */ } } else { jx = kx + (*n - 1) * *incx; for (j = *n; j >= 1; --j) { if (x[jx] != 0.) { if (nounit) { x[jx] /= ap[kk]; } temp = x[jx]; ix = jx; i__1 = kk - j + 1; for (k = kk - 1; k >= i__1; --k) { ix -= *incx; x[ix] -= temp * ap[k]; /* L30: */ } } jx -= *incx; kk -= j; /* L40: */ } } } else { kk = 1; if (*incx == 1) { i__1 = *n; for (j = 1; j <= i__1; ++j) { if (x[j] != 0.) { if (nounit) { x[j] /= ap[kk]; } temp = x[j]; k = kk + 1; i__2 = *n; for (i__ = j + 1; i__ <= i__2; ++i__) { x[i__] -= temp * ap[k]; ++k; /* L50: */ } } kk += *n - j + 1; /* L60: */ } } else { jx = kx; i__1 = *n; for (j = 1; j <= i__1; ++j) { if (x[jx] != 0.) { if (nounit) { x[jx] /= ap[kk]; } temp = x[jx]; ix = jx; i__2 = kk + *n - j; for (k = kk + 1; k <= i__2; ++k) { ix += *incx; x[ix] -= temp * ap[k]; /* L70: */ } } jx += *incx; kk += *n - j + 1; /* L80: */ } } } } else { /* Form x := inv( A' )*x. */ if (NL_FORTRAN_WRAP(lsame)(uplo, "U")) { kk = 1; if (*incx == 1) { i__1 = *n; for (j = 1; j <= i__1; ++j) { temp = x[j]; k = kk; i__2 = j - 1; for (i__ = 1; i__ <= i__2; ++i__) { temp -= ap[k] * x[i__]; ++k; /* L90: */ } if (nounit) { temp /= ap[kk + j - 1]; } x[j] = temp; kk += j; /* L100: */ } } else { jx = kx; i__1 = *n; for (j = 1; j <= i__1; ++j) { temp = x[jx]; ix = kx; i__2 = kk + j - 2; for (k = kk; k <= i__2; ++k) { temp -= ap[k] * x[ix]; ix += *incx; /* L110: */ } if (nounit) { temp /= ap[kk + j - 1]; } x[jx] = temp; jx += *incx; kk += j; /* L120: */ } } } else { kk = *n * (*n + 1) / 2; if (*incx == 1) { for (j = *n; j >= 1; --j) { temp = x[j]; k = kk; i__1 = j + 1; for (i__ = *n; i__ >= i__1; --i__) { temp -= ap[k] * x[i__]; --k; /* L130: */ } if (nounit) { temp /= ap[kk - *n + j]; } x[j] = temp; kk -= *n - j + 1; /* L140: */ } } else { kx += (*n - 1) * *incx; jx = kx; for (j = *n; j >= 1; --j) { temp = x[jx]; ix = kx; i__1 = kk - (*n - (j + 1)); for (k = kk; k >= i__1; --k) { temp -= ap[k] * x[ix]; ix -= *incx; /* L150: */ } if (nounit) { temp /= ap[kk - *n + j]; } x[jx] = temp; jx -= *incx; kk -= *n - j + 1; /* L160: */ } } } } return 0; /* End of DTPSV . */ } /* dtpsv_ */ #endif /***********************************************************************************/ /* C wrappers for BLAS routines */ /* x <- a*x */ void dscal( int n, double alpha, double *x, int incx ) { NL_FORTRAN_WRAP(dscal)(&n,&alpha,x,&incx); } /* y <- x */ void dcopy( int n, double *x, int incx, double *y, int incy ) { NL_FORTRAN_WRAP(dcopy)(&n,x,&incx,y,&incy); } /* y <- a*x+y */ void daxpy( int n, double alpha, double *x, int incx, double *y, int incy ) { NL_FORTRAN_WRAP(daxpy)(&n,&alpha,x,&incx,y,&incy); } /* returns x^T*y */ double ddot( int n, double *x, int incx, double *y, int incy ) { return NL_FORTRAN_WRAP(ddot)(&n,x,&incx,y,&incy); } /** returns |x|_2 */ double dnrm2( int n, double *x, int incx ) { return NL_FORTRAN_WRAP(dnrm2)(&n,x,&incx); } /** x <- A^{-1}*x, x <- A^{-T}*x */ void dtpsv( MatrixTriangle uplo, MatrixTranspose trans, MatrixUnitTriangular diag, int n, double *AP, double *x, int incx ) { static char *UL[2] = { "U", "L" }; static char *T[3] = { "N", "T", 0 }; static char *D[2] = { "U", "N" }; NL_FORTRAN_WRAP(dtpsv)(UL[(int)uplo],T[(int)trans],D[(int)diag],&n,AP,x,&incx); } /** y <- alpha*A*x + beta*y, y <- alpha*A^T*x + beta*y, A-(m,n) */ void dgemv( MatrixTranspose trans, int m, int n, double alpha, double *A, int ldA, double *x, int incx, double beta, double *y, int incy ) { static char *T[3] = { "N", "T", 0 }; NL_FORTRAN_WRAP(dgemv)(T[(int)trans],&m,&n,&alpha,A,&ldA,x,&incx,&beta,y,&incy); } /************************************************************************/ /* End of BLAS routines */ /************************************************************************/ /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ /************************************************************************/ /* Solvers */ /* * The implementation of the solvers is inspired by * the lsolver library, by Christian Badura, available from: * http://www.mathematik.uni-freiburg.de * /IAM/Research/projectskr/lin_solver/ * * About the Conjugate Gradient, details can be found in: * Ashby, Manteuffel, Saylor * A taxononmy for conjugate gradient methods * SIAM J Numer Anal 27, 1542-1568 (1990) */ NLuint nlSolve_CG() { NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; NLdouble eps = nlCurrentContext->threshold ; NLuint max_iter = nlCurrentContext->max_iterations ; NLint N = nlCurrentContext->n ; NLdouble *g = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *r = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *p = NL_NEW_ARRAY(NLdouble, N) ; NLuint its=0; NLint i; NLdouble t, tau, sig, rho, gam; NLdouble b_square=ddot(N,b,1,b,1); NLdouble err=eps*eps*b_square; NLdouble accu =0.0; NLdouble * Ax=NL_NEW_ARRAY(NLdouble,nlCurrentContext->n); NLdouble curr_err; nlCurrentContext->matrix_vector_prod(x,g); daxpy(N,-1.,b,1,g,1); dscal(N,-1.,g,1); dcopy(N,g,1,r,1); curr_err = ddot(N,g,1,g,1); while ( curr_err >err && its < max_iter) { if(!(its % 100)) { printf ( "%d : %.10e -- %.10e\n", its, curr_err, err ) ; } nlCurrentContext->matrix_vector_prod(r,p); rho=ddot(N,p,1,p,1); sig=ddot(N,r,1,p,1); tau=ddot(N,g,1,r,1); t=tau/sig; daxpy(N,t,r,1,x,1); daxpy(N,-t,p,1,g,1); gam=(t*t*rho-tau)/tau; dscal(N,gam,r,1); daxpy(N,1.,g,1,r,1); ++its; curr_err = ddot(N,g,1,g,1); } nlCurrentContext->matrix_vector_prod(x,Ax); for(i = 0 ; i < N ; ++i) accu+=(Ax[i]-b[i])*(Ax[i]-b[i]); printf("in OpenNL : ||Ax-b||/||b|| = %e\n",sqrt(accu)/sqrt(b_square)); NL_DELETE_ARRAY(Ax); NL_DELETE_ARRAY(g) ; NL_DELETE_ARRAY(r) ; NL_DELETE_ARRAY(p) ; return its; } NLuint nlSolve_CG_precond() { NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; NLdouble eps = nlCurrentContext->threshold ; NLuint max_iter = nlCurrentContext->max_iterations ; NLint N = nlCurrentContext->n ; NLdouble* r = NL_NEW_ARRAY(NLdouble, N) ; NLdouble* d = NL_NEW_ARRAY(NLdouble, N) ; NLdouble* h = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *Ad = h; NLuint its=0; NLdouble rh, alpha, beta; NLdouble b_square = ddot(N,b,1,b,1); NLdouble err=eps*eps*b_square; NLint i; NLdouble * Ax=NL_NEW_ARRAY(NLdouble,nlCurrentContext->n); NLdouble accu =0.0; NLdouble curr_err; nlCurrentContext->matrix_vector_prod(x,r); daxpy(N,-1.,b,1,r,1); nlCurrentContext->precond_vector_prod(r,d); dcopy(N,d,1,h,1); rh=ddot(N,r,1,h,1); curr_err = ddot(N,r,1,r,1); while ( curr_err >err && its < max_iter) { if(!(its % 100)) { printf ( "%d : %.10e -- %.10e\n", its, curr_err, err ) ; } nlCurrentContext->matrix_vector_prod(d,Ad); alpha=rh/ddot(N,d,1,Ad,1); daxpy(N,-alpha,d,1,x,1); daxpy(N,-alpha,Ad,1,r,1); nlCurrentContext->precond_vector_prod(r,h); beta=1./rh; rh=ddot(N,r,1,h,1); beta*=rh; dscal(N,beta,d,1); daxpy(N,1.,h,1,d,1); ++its; // calcul de l'erreur courante curr_err = ddot(N,r,1,r,1); } nlCurrentContext->matrix_vector_prod(x,Ax); for(i = 0 ; i < N ; ++i) accu+=(Ax[i]-b[i])*(Ax[i]-b[i]); printf("in OpenNL : ||Ax-b||/||b|| = %e\n",sqrt(accu)/sqrt(b_square)); NL_DELETE_ARRAY(Ax); NL_DELETE_ARRAY(r) ; NL_DELETE_ARRAY(d) ; NL_DELETE_ARRAY(h) ; return its; } NLuint nlSolve_BICGSTAB() { NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; NLdouble eps = nlCurrentContext->threshold ; NLuint max_iter = nlCurrentContext->max_iterations ; NLint N = nlCurrentContext->n ; NLint i ; NLdouble *rT = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *d = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *h = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *u = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *Ad = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *t = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *s = h; NLdouble rTh, rTAd, rTr, alpha, beta, omega, st, tt ; NLuint its=0; NLdouble b_square = ddot(N,b,1,b,1); NLdouble err=eps*eps*b_square; NLdouble *r = NL_NEW_ARRAY(NLdouble, N) ; NLdouble * Ax=NL_NEW_ARRAY(NLdouble,nlCurrentContext->n); NLdouble accu =0.0; nlCurrentContext->matrix_vector_prod(x,r); daxpy(N,-1.,b,1,r,1); dcopy(N,r,1,d,1); dcopy(N,d,1,h,1); dcopy(N,h,1,rT,1); nl_assert( ddot(N,rT,1,rT,1)>1e-40 ); rTh=ddot(N,rT,1,h,1); rTr=ddot(N,r,1,r,1); while ( rTr>err && its < max_iter) { if(!(its % 100)) { printf ( "%d : %.10e -- %.10e\n", its, rTr, err ) ; } nlCurrentContext->matrix_vector_prod(d,Ad); rTAd=ddot(N,rT,1,Ad,1); nl_assert( fabs(rTAd)>1e-40 ); alpha=rTh/rTAd; daxpy(N,-alpha,Ad,1,r,1); dcopy(N,h,1,s,1); daxpy(N,-alpha,Ad,1,s,1); nlCurrentContext->matrix_vector_prod(s,t); daxpy(N,1.,t,1,u,1); dscal(N,alpha,u,1); st=ddot(N,s,1,t,1); tt=ddot(N,t,1,t,1); if ( fabs(st)<1e-40 || fabs(tt)<1e-40 ) { omega = 0.; } else { omega = st/tt; } daxpy(N,-omega,t,1,r,1); daxpy(N,-alpha,d,1,x,1); daxpy(N,-omega,s,1,x,1); dcopy(N,s,1,h,1); daxpy(N,-omega,t,1,h,1); beta=(alpha/omega)/rTh; rTh=ddot(N,rT,1,h,1); beta*=rTh; dscal(N,beta,d,1); daxpy(N,1.,h,1,d,1); daxpy(N,-beta*omega,Ad,1,d,1); rTr=ddot(N,r,1,r,1); ++its; } nlCurrentContext->matrix_vector_prod(x,Ax); for(i = 0 ; i < N ; ++i){ accu+=(Ax[i]-b[i])*(Ax[i]-b[i]); } printf("in OpenNL : ||Ax-b||/||b|| = %e\n",sqrt(accu)/sqrt(b_square)); NL_DELETE_ARRAY(Ax); NL_DELETE_ARRAY(r) ; NL_DELETE_ARRAY(rT) ; NL_DELETE_ARRAY(d) ; NL_DELETE_ARRAY(h) ; NL_DELETE_ARRAY(u) ; NL_DELETE_ARRAY(Ad) ; NL_DELETE_ARRAY(t) ; return its; } NLuint nlSolve_BICGSTAB_precond() { NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; NLdouble eps = nlCurrentContext->threshold ; NLuint max_iter = nlCurrentContext->max_iterations ; NLint N = nlCurrentContext->n ; NLint i; NLdouble *rT = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *d = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *h = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *u = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *Sd = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *t = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *aux = NL_NEW_ARRAY(NLdouble, N) ; NLdouble *s = h; NLdouble rTh, rTSd, rTr, alpha, beta, omega, st, tt; NLuint its=0; NLdouble b_square = ddot(N,b,1,b,1); NLdouble err = eps*eps*b_square; NLdouble *r = NL_NEW_ARRAY(NLdouble, N); NLdouble * Ax = NL_NEW_ARRAY(NLdouble,nlCurrentContext->n); NLdouble accu =0.0; nlCurrentContext->matrix_vector_prod(x,r); daxpy(N,-1.,b,1,r,1); nlCurrentContext->precond_vector_prod(r,d); dcopy(N,d,1,h,1); dcopy(N,h,1,rT,1); nl_assert( ddot(N,rT,1,rT,1)>1e-40 ); rTh=ddot(N,rT,1,h,1); rTr=ddot(N,r,1,r,1); while ( rTr>err && its < max_iter) { if(!(its % 100)) { printf ( "%d : %.10e -- %.10e\n", its, rTr, err ) ; } nlCurrentContext->matrix_vector_prod(d,aux); nlCurrentContext->precond_vector_prod(aux,Sd); rTSd=ddot(N,rT,1,Sd,1); nl_assert( fabs(rTSd)>1e-40 ); alpha=rTh/rTSd; daxpy(N,-alpha,aux,1,r,1); dcopy(N,h,1,s,1); daxpy(N,-alpha,Sd,1,s,1); nlCurrentContext->matrix_vector_prod(s,aux); nlCurrentContext->precond_vector_prod(aux,t); daxpy(N,1.,t,1,u,1); dscal(N,alpha,u,1); st=ddot(N,s,1,t,1); tt=ddot(N,t,1,t,1); if ( fabs(st)<1e-40 || fabs(tt)<1e-40 ) { omega = 0.; } else { omega = st/tt; } daxpy(N,-omega,aux,1,r,1); daxpy(N,-alpha,d,1,x,1); daxpy(N,-omega,s,1,x,1); dcopy(N,s,1,h,1); daxpy(N,-omega,t,1,h,1); beta=(alpha/omega)/rTh; rTh=ddot(N,rT,1,h,1); beta*=rTh; dscal(N,beta,d,1); daxpy(N,1.,h,1,d,1); daxpy(N,-beta*omega,Sd,1,d,1); rTr=ddot(N,r,1,r,1); ++its; } nlCurrentContext->matrix_vector_prod(x,Ax); for(i = 0 ; i < N ; ++i){ accu+=(Ax[i]-b[i])*(Ax[i]-b[i]); } printf("in OpenNL : ||Ax-b||/||b|| = %e\n",sqrt(accu)/sqrt(b_square)); NL_DELETE_ARRAY(Ax); NL_DELETE_ARRAY(r); NL_DELETE_ARRAY(rT); NL_DELETE_ARRAY(d); NL_DELETE_ARRAY(h); NL_DELETE_ARRAY(u); NL_DELETE_ARRAY(Sd); NL_DELETE_ARRAY(t); NL_DELETE_ARRAY(aux); return its; } NLuint nlSolve_GMRES() { NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; NLdouble eps = nlCurrentContext->threshold ; NLint max_iter = nlCurrentContext->max_iterations ; NLint n = nlCurrentContext->n ; NLint m = nlCurrentContext->inner_iterations ; typedef NLdouble *NLdoubleP; NLdouble *V = NL_NEW_ARRAY(NLdouble, n*(m+1) ) ; NLdouble *U = NL_NEW_ARRAY(NLdouble, m*(m+1)/2 ) ; NLdouble *r = NL_NEW_ARRAY(NLdouble, n ) ; NLdouble *y = NL_NEW_ARRAY(NLdouble, m+1 ) ; NLdouble *c = NL_NEW_ARRAY(NLdouble, m ) ; NLdouble *s = NL_NEW_ARRAY(NLdouble, m ) ; NLdouble **v = NL_NEW_ARRAY(NLdoubleP, m+1 ) ; NLdouble * Ax = NL_NEW_ARRAY(NLdouble,nlCurrentContext->n); NLdouble accu =0.0; NLint i, j, io, uij, u0j ; NLint its = -1 ; NLdouble beta, h, rd, dd, nrm2b ; for ( i=0; i<=m; ++i ){ v[i]=V+i*n ; } nrm2b=dnrm2(n,b,1); io=0; do { /* outer loop */ ++io; nlCurrentContext->matrix_vector_prod(x,r); daxpy(n,-1.,b,1,r,1); beta=dnrm2(n,r,1); dcopy(n,r,1,v[0],1); dscal(n,1./beta,v[0],1); y[0]=beta; j=0; uij=0; do { /* inner loop: j=0,...,m-1 */ u0j=uij; nlCurrentContext->matrix_vector_prod(v[j],v[j+1]); dgemv( Transpose,n,j+1,1.,V,n,v[j+1],1,0.,U+u0j,1 ); dgemv( NoTranspose,n,j+1,-1.,V,n,U+u0j,1,1.,v[j+1],1 ); h=dnrm2(n,v[j+1],1); dscal(n,1./h,v[j+1],1); for (i=0; i=eps*nrm2b ) ; { /* minimiere bzgl Y */ dtpsv( UpperTriangle, NoTranspose, NotUnitTriangular, j,U,y,1 ); /* correct X */ dgemv(NoTranspose,n,j,-1.,V,n,y,1,1.,x,1); } } while ( fabs(y[j])>=eps*nrm2b && (m*(io-1)+j) < max_iter); /* Count the inner iterations */ its = m*(io-1)+j; nlCurrentContext->matrix_vector_prod(x,Ax); for(i = 0 ; i < n ; ++i) accu+=(Ax[i]-b[i])*(Ax[i]-b[i]); printf("in OpenNL : ||Ax-b||/||b|| = %e\n",sqrt(accu)/nrm2b); NL_DELETE_ARRAY(Ax); NL_DELETE_ARRAY(V) ; NL_DELETE_ARRAY(U) ; NL_DELETE_ARRAY(r) ; NL_DELETE_ARRAY(y) ; NL_DELETE_ARRAY(c) ; NL_DELETE_ARRAY(s) ; NL_DELETE_ARRAY(v) ; return its; } /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ /******************************************************************************/ /* preconditioners */ /* Utilities for preconditioners */ void nlMultDiagonal(NLdouble* xy, NLdouble omega) { NLuint N = nlCurrentContext->n ; NLuint i ; NLdouble* diag = nlCurrentContext->M.diag ; for(i=0; in ; NLuint i ; NLdouble* diag = nlCurrentContext->M.diag ; for(i=0; iM) ; NLuint n = A->n ; NLdouble* diag = A->diag ; NLuint i ; NLuint ij ; NLRowColumn* Ri = NULL ; NLCoeff* c = NULL ; NLdouble S ; nl_assert(A->storage & NL_MATRIX_STORE_SYMMETRIC) ; nl_assert(A->storage & NL_MATRIX_STORE_ROWS) ; for(i=0; irow[i]) ; for(ij=0; ij < Ri->size; ij++) { c = &(Ri->coeff[ij]) ; nl_parano_assert(c->index <= i) ; if(c->index != i) { S += c->value * y[c->index] ; } } y[i] = (x[i] - S) * omega / diag[i] ; } } void nlMultUpperInverse(NLdouble* x, NLdouble* y, NLdouble omega) { NLSparseMatrix* A = &(nlCurrentContext->M) ; NLuint n = A->n ; NLdouble* diag = A->diag ; NLint i ; NLuint ij ; NLRowColumn* Ci = NULL ; NLCoeff* c = NULL ; NLdouble S ; nl_assert(A->storage & NL_MATRIX_STORE_SYMMETRIC) ; nl_assert(A->storage & NL_MATRIX_STORE_COLUMNS) ; for(i=n-1; i>=0; i--) { S = 0 ; Ci = &(A->column[i]) ; for(ij=0; ij < Ci->size; ij++) { c = &(Ci->coeff[ij]) ; nl_parano_assert(c->index >= i) ; if(c->index != i) { S += c->value * y[c->index] ; } } y[i] = (x[i] - S) * omega / diag[i] ; } } void nlPreconditioner_Jacobi(NLdouble* x, NLdouble* y) { NLuint N = nlCurrentContext->n ; dcopy(N, x, 1, y, 1) ; nlMultDiagonalInverse(y, 1.0) ; } void nlPreconditioner_SSOR(NLdouble* x, NLdouble* y) { NLdouble omega = nlCurrentContext->omega ; static double* work = NULL ; static int work_size = 0 ; NLuint n = nlCurrentContext->n ; if(n != work_size) { work = NL_RENEW_ARRAY(NLdouble, work, n) ; work_size = n ; } nlMultLowerInverse(x, work, omega) ; nlMultDiagonal(work, omega) ; nlMultUpperInverse(work, y, omega) ; dscal(n, 2.0 - omega, y, 1) ; } /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ /************************************************************************/ /* SuperLU wrapper */ #ifdef NL_USE_SUPERLU /* SuperLU includes */ #include #include /* Note: SuperLU is difficult to call, but it is worth it. */ /* Here is a driver inspired by A. Sheffer's "cow flattener". */ NLboolean nlSolve_SUPERLU() { /* OpenNL Context */ NLSparseMatrix* M = &(nlCurrentContext->M) ; NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; /* Compressed Row Storage matrix representation */ NLuint n = nlCurrentContext->n ; NLuint nnz = nlSparseMatrixNNZ(M) ; /* Number of Non-Zero coeffs */ NLint* xa = NL_NEW_ARRAY(NLint, n+1) ; NLdouble* rhs = NL_NEW_ARRAY(NLdouble, n) ; NLdouble* a = NL_NEW_ARRAY(NLdouble, nnz) ; NLint* asub = NL_NEW_ARRAY(NLint, nnz) ; /* Permutation vector */ NLint* perm_r = NL_NEW_ARRAY(NLint, n) ; NLint* perm = NL_NEW_ARRAY(NLint, n) ; /* SuperLU variables */ SuperMatrix A, B ; /* System */ SuperMatrix L, U ; /* Inverse of A */ NLint info ; /* status code */ DNformat *vals = NULL ; /* access to result */ double *rvals = NULL ; /* access to result */ /* SuperLU options and stats */ superlu_options_t options ; SuperLUStat_t stat ; /* Temporary variables */ NLRowColumn* Ri = NULL ; NLuint i,jj,count ; /* Sanity checks */ nl_assert(!(M->storage & NL_MATRIX_STORE_SYMMETRIC)) ; nl_assert(M->storage & NL_MATRIX_STORE_ROWS) ; nl_assert(M->m == M->n) ; /* * Step 1: convert matrix M into SuperLU compressed column * representation. * ------------------------------------------------------- */ count = 0 ; for(i=0; irow[i]) ; xa[i] = count ; for(jj=0; jjsize; jj++) { a[count] = Ri->coeff[jj].value ; asub[count] = Ri->coeff[jj].index ; count++ ; } } xa[n] = nnz ; /* Save memory for SuperLU */ nlSparseMatrixClear(M) ; /* * Rem: SuperLU does not support symmetric storage. * In fact, for symmetric matrix, what we need * is a SuperLLt algorithm (SuperNodal sparse Cholesky), * but it does not exist, anybody wants to implement it ? * However, this is not a big problem (SuperLU is just * a superset of what we really need. */ dCreate_CompCol_Matrix( &A, n, n, nnz, a, asub, xa, SLU_NR, /* Row_wise, no supernode */ SLU_D, /* doubles */ SLU_GE /* general storage */ ); /* Step 2: create vector */ dCreate_Dense_Matrix( &B, n, 1, b, n, SLU_DN, /* Fortran-type column-wise storage */ SLU_D, /* doubles */ SLU_GE /* general */ ); /* Step 3: set SuperLU options * ------------------------------ */ set_default_options(&options) ; switch(nlCurrentContext->solver) { case NL_SUPERLU_EXT: { options.ColPerm = NATURAL ; } break ; case NL_PERM_SUPERLU_EXT: { options.ColPerm = COLAMD ; } break ; case NL_SYMMETRIC_SUPERLU_EXT: { options.ColPerm = MMD_AT_PLUS_A ; options.SymmetricMode = YES ; } break ; default: { nl_assert_not_reached ; } break ; } StatInit(&stat) ; /* Step 4: call SuperLU main routine * --------------------------------- */ dgssv(&options, &A, perm, perm_r, &L, &U, &B, &stat, &info); /* Step 5: get the solution * ------------------------ * Fortran-type column-wise storage */ vals = (DNformat*)B.Store; rvals = (double*)(vals->nzval); if(info == 0) { for(i = 0; i < n; i++){ x[i] = rvals[i]; } } else { nlError("nlSolve()", "SuperLU failed") ; } /* Step 6: cleanup * --------------- */ /* * For these two ones, only the "store" structure * needs to be deallocated (the arrays have been allocated * by us). */ Destroy_SuperMatrix_Store(&A) ; Destroy_SuperMatrix_Store(&B) ; /* * These ones need to be fully deallocated (they have been * allocated by SuperLU). */ Destroy_SuperNode_Matrix(&L); Destroy_CompCol_Matrix(&U); /* There are some dynamically allocated vectors in the stats */ StatFree(&stat) ; NL_DELETE_ARRAY(xa) ; NL_DELETE_ARRAY(rhs) ; NL_DELETE_ARRAY(a) ; NL_DELETE_ARRAY(asub) ; NL_DELETE_ARRAY(perm_r) ; NL_DELETE_ARRAY(perm) ; return (info == 0) ; } #else NLboolean nlSolve_SUPERLU() { nl_assert_not_reached ; return 0; } #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ NLboolean nlSolverIsCNC(NLint solver){ return solver == NL_CNC_FLOAT_CRS || solver == NL_CNC_DOUBLE_CRS || solver == NL_CNC_FLOAT_BCRS2 || solver == NL_CNC_DOUBLE_BCRS2 || solver == NL_CNC_FLOAT_ELL || solver == NL_CNC_DOUBLE_ELL || solver == NL_CNC_FLOAT_HYB || solver == NL_CNC_DOUBLE_HYB; } /************************************************************************/ /* CNC wrapper */ #ifdef NL_USE_CNC NLuint nlSolve_CNC() { unsigned int i; NLdouble* b = nlCurrentContext->b ; NLdouble* x = nlCurrentContext->x ; NLdouble eps = nlCurrentContext->threshold ; NLuint max_iter = nlCurrentContext->max_iterations ; NLSparseMatrix *M = &(nlCurrentContext->M); // local variables for the final error computation NLuint val_ret; NLdouble * Ax=NL_NEW_ARRAY(NLdouble,nlCurrentContext->n); NLdouble accu = 0.0; NLdouble b_square = 0.0; //nl_assert( M->n == nlCurrentContext->n); // call to cnc solver val_ret=cnc_solve_cg(M, b, x, max_iter, eps, nlCurrentContext->solver); // compute the final error nlCurrentContext->matrix_vector_prod(x,Ax); for(i = 0 ; i < M->n ; ++i) { accu +=(Ax[i]-b[i])*(Ax[i]-b[i]); b_square += b[i]*b[i]; } printf("in OpenNL : ||Ax-b||/||b|| = %e\n",sqrt(accu)/sqrt(b_square)); // cleaning NL_DELETE_ARRAY(Ax); return val_ret; } #else NLuint nlSolve_CNC() { nl_assert_not_reached ; } #endif /* * Copyright (c) 2004-2010, Bruno Levy * 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: Bruno Levy * * levy@loria.fr * * ALICE Project * LORIA, INRIA Lorraine, * Campus Scientifique, BP 239 * 54506 VANDOEUVRE LES NANCY CEDEX * FRANCE * */ NLboolean nlInitExtension(const char* extension) { #ifdef NL_USE_SUPERLU if(!strcmp(extension, "SUPERLU")) { return NL_TRUE ; } #endif #ifdef NL_USE_CNC if(!strcmp(extension, "CNC")) { return NL_TRUE ; } #endif return NL_FALSE ; } /************************************************************************************/ /* Get/Set parameters */ void nlSolverParameterd(NLenum pname, NLdouble param) { nlCheckState(NL_STATE_INITIAL) ; switch(pname) { case NL_SOLVER: { nlCurrentContext->solver = (NLenum)param ; } break ; case NL_NB_VARIABLES: { nl_assert(param > 0) ; nlCurrentContext->nb_variables = (NLuint)param ; } break ; case NL_LEAST_SQUARES: { nlCurrentContext->least_squares = (NLboolean)param ; } break ; case NL_MAX_ITERATIONS: { nl_assert(param > 0) ; nlCurrentContext->max_iterations = (NLuint)param ; } break ; case NL_THRESHOLD: { nl_assert(param >= 0) ; nlCurrentContext->threshold = (NLdouble)param ; } break ; case NL_OMEGA: { nl_range_assert(param,1.0,2.0) ; nlCurrentContext->omega = (NLdouble)param ; } break ; case NL_SYMMETRIC: { nlCurrentContext->symmetric = (NLboolean)param ; } case NL_INNER_ITERATIONS: { nl_assert(param > 0) ; nlCurrentContext->inner_iterations = (NLuint)param ; } break ; case NL_PRECONDITIONER: { nlCurrentContext->preconditioner = (NLuint)param ; } break ; default: { nl_assert_not_reached ; } break ; } } void nlSolverParameteri(NLenum pname, NLint param) { nlCheckState(NL_STATE_INITIAL) ; switch(pname) { case NL_SOLVER: { nlCurrentContext->solver = (NLenum)param ; } break ; case NL_NB_VARIABLES: { nl_assert(param > 0) ; nlCurrentContext->nb_variables = (NLuint)param ; } break ; case NL_LEAST_SQUARES: { nlCurrentContext->least_squares = (NLboolean)param ; } break ; case NL_MAX_ITERATIONS: { nl_assert(param > 0) ; nlCurrentContext->max_iterations = (NLuint)param ; } break ; case NL_THRESHOLD: { nl_assert(param >= 0) ; nlCurrentContext->threshold = (NLdouble)param ; } break ; case NL_OMEGA: { nl_range_assert(param,1,2) ; nlCurrentContext->omega = (NLdouble)param ; } break ; case NL_SYMMETRIC: { nlCurrentContext->symmetric = (NLboolean)param ; } case NL_INNER_ITERATIONS: { nl_assert(param > 0) ; nlCurrentContext->inner_iterations = (NLuint)param ; } break ; case NL_PRECONDITIONER: { nlCurrentContext->preconditioner = (NLuint)param ; } break ; default: { nl_assert_not_reached ; } break ; } } void nlRowParameterd(NLenum pname, NLdouble param) { nlCheckState(NL_STATE_MATRIX) ; switch(pname) { case NL_RIGHT_HAND_SIDE: { nlCurrentContext->right_hand_side = param ; } break ; case NL_ROW_SCALING: { nlCurrentContext->row_scaling = param ; } break ; } } void nlRowParameteri(NLenum pname, NLint param) { nlCheckState(NL_STATE_MATRIX) ; switch(pname) { case NL_RIGHT_HAND_SIDE: { nlCurrentContext->right_hand_side = (NLdouble)param ; } break ; case NL_ROW_SCALING: { nlCurrentContext->row_scaling = (NLdouble)param ; } break ; } } void nlGetBooleanv(NLenum pname, NLboolean* params) { switch(pname) { case NL_LEAST_SQUARES: { *params = nlCurrentContext->least_squares ; } break ; case NL_SYMMETRIC: { *params = nlCurrentContext->symmetric ; } break ; default: { nl_assert_not_reached ; } break ; } } void nlGetDoublev(NLenum pname, NLdouble* params) { switch(pname) { case NL_SOLVER: { *params = (NLdouble)(nlCurrentContext->solver) ; } break ; case NL_NB_VARIABLES: { *params = (NLdouble)(nlCurrentContext->nb_variables) ; } break ; case NL_LEAST_SQUARES: { *params = (NLdouble)(nlCurrentContext->least_squares) ; } break ; case NL_MAX_ITERATIONS: { *params = (NLdouble)(nlCurrentContext->max_iterations) ; } break ; case NL_THRESHOLD: { *params = (NLdouble)(nlCurrentContext->threshold) ; } break ; case NL_OMEGA: { *params = (NLdouble)(nlCurrentContext->omega) ; } break ; case NL_SYMMETRIC: { *params = (NLdouble)(nlCurrentContext->symmetric) ; } break ; case NL_USED_ITERATIONS: { *params = (NLdouble)(nlCurrentContext->used_iterations) ; } break ; case NL_ERROR: { *params = (NLdouble)(nlCurrentContext->error) ; } break ; case NL_ELAPSED_TIME: { *params = (NLdouble)(nlCurrentContext->elapsed_time) ; } break ; case NL_PRECONDITIONER: { *params = (NLdouble)(nlCurrentContext->preconditioner) ; } break ; default: { nl_assert_not_reached ; } break ; } } void nlGetIntergerv(NLenum pname, NLint* params) { switch(pname) { case NL_SOLVER: { *params = (NLint)(nlCurrentContext->solver) ; } break ; case NL_NB_VARIABLES: { *params = (NLint)(nlCurrentContext->nb_variables) ; } break ; case NL_LEAST_SQUARES: { *params = (NLint)(nlCurrentContext->least_squares) ; } break ; case NL_MAX_ITERATIONS: { *params = (NLint)(nlCurrentContext->max_iterations) ; } break ; case NL_THRESHOLD: { *params = (NLint)(nlCurrentContext->threshold) ; } break ; case NL_OMEGA: { *params = (NLint)(nlCurrentContext->omega) ; } break ; case NL_SYMMETRIC: { *params = (NLint)(nlCurrentContext->symmetric) ; } break ; case NL_USED_ITERATIONS: { *params = (NLint)(nlCurrentContext->used_iterations) ; } break ; case NL_PRECONDITIONER: { *params = (NLint)(nlCurrentContext->preconditioner) ; } break ; default: { nl_assert_not_reached ; } break ; } } /************************************************************************************/ /* Enable / Disable */ void nlEnable(NLenum pname) { switch(pname) { case NL_NORMALIZE_ROWS: { nl_assert(nlCurrentContext->state != NL_STATE_ROW) ; nlCurrentContext->normalize_rows = NL_TRUE ; } break ; default: { nl_assert_not_reached ; } } } void nlDisable(NLenum pname) { switch(pname) { case NL_NORMALIZE_ROWS: { nl_assert(nlCurrentContext->state != NL_STATE_ROW) ; nlCurrentContext->normalize_rows = NL_FALSE ; } break ; default: { nl_assert_not_reached ; } } } NLboolean nlIsEnabled(NLenum pname) { switch(pname) { case NL_NORMALIZE_ROWS: { return nlCurrentContext->normalize_rows ; } break ; default: { nl_assert_not_reached ; } } return NL_FALSE ; } /************************************************************************************/ /* NL functions */ void nlSetFunction(NLenum pname, void* param) { switch(pname) { case NL_FUNC_SOLVER: nlCurrentContext->solver_func = (NLSolverFunc)(param) ; break ; case NL_FUNC_MATRIX: nlCurrentContext->matrix_vector_prod = (NLMatrixFunc)(param) ; nlCurrentContext->solver = NL_SOLVER_USER ; break ; case NL_FUNC_PRECONDITIONER: nlCurrentContext->precond_vector_prod = (NLMatrixFunc)(param) ; nlCurrentContext->preconditioner = NL_PRECOND_USER ; break ; default: nl_assert_not_reached ; } } void nlGetFunction(NLenum pname, void** param) { switch(pname) { case NL_FUNC_SOLVER: *param = nlCurrentContext->solver_func ; break ; case NL_FUNC_MATRIX: *param = nlCurrentContext->matrix_vector_prod ; break ; case NL_FUNC_PRECONDITIONER: *param = nlCurrentContext->precond_vector_prod ; break ; default: nl_assert_not_reached ; } } /************************************************************************************/ /* Get/Set Lock/Unlock variables */ void nlSetVariable(NLuint index, NLdouble value) { nlCheckState(NL_STATE_SYSTEM) ; nl_debug_range_assert(index, 0, nlCurrentContext->nb_variables - 1) ; nlCurrentContext->variable[index].value = value ; } NLdouble nlGetVariable(NLuint index) { nl_assert(nlCurrentContext->state != NL_STATE_INITIAL) ; nl_debug_range_assert(index, 0, nlCurrentContext->nb_variables - 1) ; return nlCurrentContext->variable[index].value ; } void nlLockVariable(NLuint index) { nlCheckState(NL_STATE_SYSTEM) ; nl_debug_range_assert(index, 0, nlCurrentContext->nb_variables - 1) ; nlCurrentContext->variable[index].locked = NL_TRUE ; } void nlUnlockVariable(NLuint index) { nlCheckState(NL_STATE_SYSTEM) ; nl_debug_range_assert(index, 0, nlCurrentContext->nb_variables - 1) ; nlCurrentContext->variable[index].locked = NL_FALSE ; } NLboolean nlVariableIsLocked(NLuint index) { nl_assert(nlCurrentContext->state != NL_STATE_INITIAL) ; nl_debug_range_assert(index, 0, nlCurrentContext->nb_variables - 1) ; return nlCurrentContext->variable[index].locked ; } /************************************************************************************/ /* System construction */ void nlVariablesToVector() { NLuint i ; nl_assert(nlCurrentContext->alloc_x) ; nl_assert(nlCurrentContext->alloc_variable) ; for(i=0; inb_variables; i++) { NLVariable* v = &(nlCurrentContext->variable[i]) ; if(!v->locked) { nl_assert(v->index < nlCurrentContext->n) ; nlCurrentContext->x[v->index] = v->value ; } } } void nlVectorToVariables() { NLuint i ; nl_assert(nlCurrentContext->alloc_x) ; nl_assert(nlCurrentContext->alloc_variable) ; for(i=0; inb_variables; i++) { NLVariable* v = &(nlCurrentContext->variable[i]) ; if(!v->locked) { nl_assert(v->index < nlCurrentContext->n) ; v->value = nlCurrentContext->x[v->index] ; } } } void nlBeginSystem() { nlTransition(NL_STATE_INITIAL, NL_STATE_SYSTEM) ; nl_assert(nlCurrentContext->nb_variables > 0) ; nlCurrentContext->variable = NL_NEW_ARRAY( NLVariable, nlCurrentContext->nb_variables ) ; nlCurrentContext->alloc_variable = NL_TRUE ; } void nlEndSystem() { nlTransition(NL_STATE_MATRIX_CONSTRUCTED, NL_STATE_SYSTEM_CONSTRUCTED) ; } void nlBeginMatrix() { NLuint i ; NLuint n = 0 ; NLenum storage = NL_MATRIX_STORE_ROWS ; nlTransition(NL_STATE_SYSTEM, NL_STATE_MATRIX) ; for(i=0; inb_variables; i++) { if(!nlCurrentContext->variable[i].locked) { nlCurrentContext->variable[i].index = n ; n++ ; } else { nlCurrentContext->variable[i].index = ~0 ; } } nlCurrentContext->n = n ; /* SSOR preconditioner requires rows and columns */ if(nlCurrentContext->preconditioner == NL_PRECOND_SSOR) { storage = (storage | NL_MATRIX_STORE_COLUMNS) ; } /* a least squares problem results in a symmetric matrix */ if(nlCurrentContext->least_squares && !nlSolverIsCNC(nlCurrentContext->solver)) { nlCurrentContext->symmetric = NL_TRUE ; } if(nlCurrentContext->symmetric) { storage = (storage | NL_MATRIX_STORE_SYMMETRIC) ; } /* SuperLU storage does not support symmetric storage */ if( nlCurrentContext->solver == NL_SUPERLU_EXT || nlCurrentContext->solver == NL_PERM_SUPERLU_EXT || nlCurrentContext->solver == NL_SYMMETRIC_SUPERLU_EXT ) { storage = (storage & ~NL_SYMMETRIC) ; } nlSparseMatrixConstruct(&nlCurrentContext->M, n, n, storage) ; nlCurrentContext->alloc_M = NL_TRUE ; nlCurrentContext->x = NL_NEW_ARRAY(NLdouble, n) ; nlCurrentContext->alloc_x = NL_TRUE ; nlCurrentContext->b = NL_NEW_ARRAY(NLdouble, n) ; nlCurrentContext->alloc_b = NL_TRUE ; nlVariablesToVector() ; nlRowColumnConstruct(&nlCurrentContext->af) ; nlCurrentContext->alloc_af = NL_TRUE ; nlRowColumnConstruct(&nlCurrentContext->al) ; nlCurrentContext->alloc_al = NL_TRUE ; nlRowColumnConstruct(&nlCurrentContext->xl) ; nlCurrentContext->alloc_xl = NL_TRUE ; nlCurrentContext->current_row = 0 ; } void nlEndMatrix() { nlTransition(NL_STATE_MATRIX, NL_STATE_MATRIX_CONSTRUCTED) ; nlRowColumnDestroy(&nlCurrentContext->af) ; nlCurrentContext->alloc_af = NL_FALSE ; nlRowColumnDestroy(&nlCurrentContext->al) ; nlCurrentContext->alloc_al = NL_FALSE ; nlRowColumnDestroy(&nlCurrentContext->xl) ; nlCurrentContext->alloc_al = NL_FALSE ; if(!nlCurrentContext->least_squares) { nl_assert( nlCurrentContext->current_row == nlCurrentContext->n ) ; } } void nlBeginRow() { nlTransition(NL_STATE_MATRIX, NL_STATE_ROW) ; nlRowColumnZero(&nlCurrentContext->af) ; nlRowColumnZero(&nlCurrentContext->al) ; nlRowColumnZero(&nlCurrentContext->xl) ; } void nlScaleRow(NLdouble s) { NLRowColumn* af = &nlCurrentContext->af ; NLRowColumn* al = &nlCurrentContext->al ; NLuint nf = af->size ; NLuint nl = al->size ; NLuint i ; for(i=0; icoeff[i].value *= s ; } for(i=0; icoeff[i].value *= s ; } nlCurrentContext->right_hand_side *= s ; } void nlNormalizeRow(NLdouble weight) { NLRowColumn* af = &nlCurrentContext->af ; NLRowColumn* al = &nlCurrentContext->al ; NLuint nf = af->size ; NLuint nl = al->size ; NLuint i ; NLdouble norm = 0.0 ; for(i=0; icoeff[i].value * af->coeff[i].value ; } for(i=0; icoeff[i].value * al->coeff[i].value ; } norm = sqrt(norm) ; nlScaleRow(weight / norm) ; } void nlEndRow() { NLRowColumn* af = &nlCurrentContext->af ; NLRowColumn* al = &nlCurrentContext->al ; NLRowColumn* xl = &nlCurrentContext->xl ; NLSparseMatrix* M = &nlCurrentContext->M ; NLdouble* b = nlCurrentContext->b ; NLuint nf = af->size ; NLuint nl = al->size ; NLuint current_row = nlCurrentContext->current_row ; NLuint i ; NLuint j ; NLdouble S ; nlTransition(NL_STATE_ROW, NL_STATE_MATRIX) ; if(nlCurrentContext->normalize_rows) { nlNormalizeRow(nlCurrentContext->row_scaling) ; } else { nlScaleRow(nlCurrentContext->row_scaling) ; } // if least_squares : we want to solve // A'A x = A'b // if(nlCurrentContext->least_squares) { for(i=0; icoeff[i].index, af->coeff[j].index, af->coeff[i].value * af->coeff[j].value ) ; } } S = -nlCurrentContext->right_hand_side ; for(j=0; jcoeff[j].value * xl->coeff[j].value ; } for(i=0; icoeff[i].index ] -= af->coeff[i].value * S ; } } else { for(i=0; icoeff[i].index, af->coeff[i].value ) ; } b[current_row] = -nlCurrentContext->right_hand_side ; for(i=0; icoeff[i].value * xl->coeff[i].value ; } } nlCurrentContext->current_row++ ; nlCurrentContext->right_hand_side = 0.0 ; nlCurrentContext->row_scaling = 1.0 ; } void nlCoefficient(NLuint index, NLdouble value) { NLVariable* v = NULL ; nlCheckState(NL_STATE_ROW) ; nl_debug_range_assert(index, 0, nlCurrentContext->nb_variables - 1) ; v = &(nlCurrentContext->variable[index]) ; if(v->locked) { nlRowColumnAppend(&(nlCurrentContext->al), 0, value) ; nlRowColumnAppend(&(nlCurrentContext->xl), 0, v->value) ; } else { nlRowColumnAppend(&(nlCurrentContext->af), v->index, value) ; } } void nlBegin(NLenum prim) { switch(prim) { case NL_SYSTEM: { nlBeginSystem() ; } break ; case NL_MATRIX: { nlBeginMatrix() ; } break ; case NL_ROW: { nlBeginRow() ; } break ; default: { nl_assert_not_reached ; } } } void nlEnd(NLenum prim) { switch(prim) { case NL_SYSTEM: { nlEndSystem() ; } break ; case NL_MATRIX: { nlEndMatrix() ; } break ; case NL_ROW: { nlEndRow() ; } break ; default: { nl_assert_not_reached ; } } } /************************************************************************/ /* nlSolve() driver routine */ NLboolean nlSolve() { NLboolean result ; NLdouble start_time = nlCurrentTime() ; nlCheckState(NL_STATE_SYSTEM_CONSTRUCTED) ; nlCurrentContext->elapsed_time = 0 ; result = nlCurrentContext->solver_func() ; nlVectorToVariables() ; nlCurrentContext->elapsed_time = nlCurrentTime() - start_time ; nlTransition(NL_STATE_SYSTEM_CONSTRUCTED, NL_STATE_SOLVED) ; return result ; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/0000775000175000017500000000000011757446472016725 5ustar lucalucavmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDataSetItem.cxx0000664000175000017500000000260711757446472023251 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDataSetItem.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkDataSetItem.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkDataSetItem, "$Revision: 1.3 $"); vtkvmtkDataSetItem::vtkvmtkDataSetItem() { this->DataSetPointId = -1; this->DataSet = NULL; this->ReallocateOnBuild = 0; } void vtkvmtkDataSetItem::DeepCopy(vtkvmtkItem* src) { this->Superclass::DeepCopy(src); vtkvmtkDataSetItem* dataSetItemSrc = vtkvmtkDataSetItem::SafeDownCast(src); if (dataSetItemSrc==NULL) { vtkErrorMacro(<<"Trying to deep copy a non-stencil item"); } this->SetDataSet(dataSetItemSrc->GetDataSet()); this->DataSetPointId = dataSetItemSrc->DataSetPointId; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataClampedSmoothingFilter.h0000664000175000017500000000532011757446472026566 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataClampedSmoothingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataClampedSmoothingFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataClampedSmoothingFilter_h #define __vtkvmtkPolyDataClampedSmoothingFilter_h #include "vtkObject.h" #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataClampedSmoothingFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataClampedSmoothingFilter *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataClampedSmoothingFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); vtkSetMacro(SmoothingType,int); vtkGetMacro(SmoothingType,int); void SetSmoothingTypeToLaplacian() { this->SmoothingType = LAPLACIAN; } void SetSmoothingTypeToCurvatureDiffusion() { this->SmoothingType = CURVATURE_DIFFUSION; } vtkSetMacro(NumberOfIterations,int); vtkGetMacro(NumberOfIterations,int); vtkSetMacro(Clamp,int); vtkGetMacro(Clamp,int); vtkBooleanMacro(Clamp,int); vtkSetMacro(ClampThreshold,double); vtkGetMacro(ClampThreshold,double); vtkSetStringMacro(ClampArrayName); vtkGetStringMacro(ClampArrayName); vtkSetMacro(TimeStepFactor,double); vtkGetMacro(TimeStepFactor,double); //BTX enum { LAPLACIAN, CURVATURE_DIFFUSION }; //ETX protected: vtkvmtkPolyDataClampedSmoothingFilter(); ~vtkvmtkPolyDataClampedSmoothingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void LaplacianIteration(vtkPolyData* surface); void CurvatureDiffusionIteration(vtkPolyData* surface); double ComputeTimeStep(vtkPolyData* surface); int SmoothingType; int NumberOfIterations; int Clamp; double ClampThreshold; double TimeStepFactor; char* ClampArrayName; private: vtkvmtkPolyDataClampedSmoothingFilter(const vtkvmtkPolyDataClampedSmoothingFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataClampedSmoothingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkBoundaryConditions.h0000664000175000017500000000365511757446472024353 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryConditions.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkBoundaryConditions - .. // .SECTION Description // .. #ifndef __vtkvmtkBoundaryConditions_h #define __vtkvmtkBoundaryConditions_h #include "vtkObject.h" #include "vtkvmtkLinearSystem.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkBoundaryConditions : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkBoundaryConditions,vtkObject); vtkSetObjectMacro(LinearSystem,vtkvmtkLinearSystem); vtkGetObjectMacro(LinearSystem,vtkvmtkLinearSystem); vtkSetObjectMacro(BoundaryNodes,vtkIdList); vtkGetObjectMacro(BoundaryNodes,vtkIdList); vtkSetObjectMacro(BoundaryValues,vtkDoubleArray); vtkGetObjectMacro(BoundaryValues,vtkDoubleArray); virtual void Apply(); protected: vtkvmtkBoundaryConditions(); ~vtkvmtkBoundaryConditions(); vtkvmtkLinearSystem* LinearSystem; vtkIdList* BoundaryNodes; vtkDoubleArray* BoundaryValues; private: vtkvmtkBoundaryConditions(const vtkvmtkBoundaryConditions&); // Not implemented. void operator=(const vtkvmtkBoundaryConditions&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter.cxx0000664000175000017500000001107411757446472032171 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter.h" #include "vtkvmtkPolyDataCylinderHarmonicMappingFilter.h" #include "vtkPolyData.h" #include "vtkCellArray.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkvmtkPolyDataBranchUtilities.h" vtkCxxRevisionMacro(vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter); vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter::vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter() { this->HarmonicMappingArrayName = NULL; this->GroupIdsArrayName = NULL; } vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter::~vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter() { if (this->HarmonicMappingArrayName) { delete[] this->HarmonicMappingArrayName; this->HarmonicMappingArrayName = NULL; } if (this->GroupIdsArrayName) { delete[] this->GroupIdsArrayName; this->GroupIdsArrayName = NULL; } } int vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter::RequestData( vtkInformation *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->HarmonicMappingArrayName) { vtkErrorMacro(<<"HarmonicMappingArrayName not set."); return 1; } if (!this->GroupIdsArrayName) { vtkErrorMacro(<<"GroupIdsArrayName not set."); return 1; } vtkDataArray* groupIdsArray = input->GetPointData()->GetArray(this->GroupIdsArrayName); if (!groupIdsArray) { vtkErrorMacro(<<"GroupIdsArray with name specified does not exist."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); vtkDoubleArray* harmonicMappingArray = vtkDoubleArray::New(); harmonicMappingArray->SetName(this->HarmonicMappingArrayName); harmonicMappingArray->SetNumberOfComponents(1); harmonicMappingArray->SetNumberOfTuples(numberOfInputPoints); harmonicMappingArray->FillComponent(0,0.0); output->DeepCopy(input); vtkIdList* groupIds = vtkIdList::New(); vtkvmtkPolyDataBranchUtilities::GetGroupsIdList(input,this->GroupIdsArrayName,groupIds); int i, j; for (i=0; iGetNumberOfIds(); i++) { vtkIdType groupId = groupIds->GetId(i); vtkPolyData* cylinder = vtkPolyData::New(); vtkvmtkPolyDataBranchUtilities::ExtractGroup(input,this->GroupIdsArrayName,groupId,false,cylinder); vtkvmtkPolyDataCylinderHarmonicMappingFilter* mappingFilter = vtkvmtkPolyDataCylinderHarmonicMappingFilter::New(); mappingFilter->SetInput(cylinder); mappingFilter->SetHarmonicMappingArrayName(this->HarmonicMappingArrayName); mappingFilter->Update(); vtkDataArray* cylinderMappingArray = mappingFilter->GetOutput()->GetPointData()->GetArray(this->HarmonicMappingArrayName); if (!cylinderMappingArray) { mappingFilter->Delete(); continue; } double mappingValue; for (j=0; j(groupIdsArray->GetComponent(j,0)); if (currentGroupId == groupId) { mappingValue = cylinderMappingArray->GetComponent(j,0); harmonicMappingArray->SetComponent(j,0,mappingValue); } } mappingFilter->Delete(); cylinder->Delete(); } output->GetPointData()->AddArray(harmonicMappingArray); groupIds->Delete(); harmonicMappingArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFELaplaceBeltramiStencil.cxx0000664000175000017500000000246111757446472027317 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFELaplaceBeltramiStencil.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataFELaplaceBeltramiStencil.h" #include "vtkvmtkMath.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataFELaplaceBeltramiStencil, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkPolyDataFELaplaceBeltramiStencil); vtkvmtkPolyDataFELaplaceBeltramiStencil::vtkvmtkPolyDataFELaplaceBeltramiStencil() { this->UseExtendedNeighborhood = 1; } void vtkvmtkPolyDataFELaplaceBeltramiStencil::ScaleWithArea() { this->ScaleWithAreaFactor(1.0/3.0); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataHarmonicMappingFilter.h0000664000175000017500000000527611757446472026417 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataHarmonicMappingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataHarmonicMappingFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataHarmonicMappingFilter_h #define __vtkvmtkPolyDataHarmonicMappingFilter_h #include "vtkvmtkWin32Header.h" #include "vtkPolyDataAlgorithm.h" #include "vtkIdList.h" #include "vtkDoubleArray.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataHarmonicMappingFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataHarmonicMappingFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataHarmonicMappingFilter,vtkPolyDataAlgorithm); vtkSetObjectMacro(BoundaryPointIds,vtkIdList); vtkGetObjectMacro(BoundaryPointIds,vtkIdList); vtkSetObjectMacro(BoundaryValues,vtkDoubleArray); vtkGetObjectMacro(BoundaryValues,vtkDoubleArray); vtkSetStringMacro(HarmonicMappingArrayName); vtkGetStringMacro(HarmonicMappingArrayName); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(AssemblyMode,int); vtkGetMacro(AssemblyMode,int); void SetAssemblyModeToStencils() { this->SetAssemblyMode(VTK_VMTK_ASSEMBLY_STENCILS); } void SetAssemblyModeToFiniteElements() { this->SetAssemblyMode(VTK_VMTK_ASSEMBLY_FINITEELEMENTS); } vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); //BTX enum { VTK_VMTK_ASSEMBLY_STENCILS, VTK_VMTK_ASSEMBLY_FINITEELEMENTS }; //ETX protected: vtkvmtkPolyDataHarmonicMappingFilter(); ~vtkvmtkPolyDataHarmonicMappingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdList* BoundaryPointIds; vtkDoubleArray* BoundaryValues; char* HarmonicMappingArrayName; double ConvergenceTolerance; int AssemblyMode; int QuadratureOrder; private: vtkvmtkPolyDataHarmonicMappingFilter(const vtkvmtkPolyDataHarmonicMappingFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataHarmonicMappingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDataSetItem.h0000664000175000017500000000403611757446472022674 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDataSetItem.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkDataSetItem - .. // .SECTION Description // .. #ifndef __vtkvmtkDataSetItem_h #define __vtkvmtkDataSetItem_h #include "vtkObject.h" #include "vtkvmtkItem.h" #include "vtkDataSet.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkDataSetItem : public vtkvmtkItem { public: vtkTypeRevisionMacro(vtkvmtkDataSetItem,vtkvmtkItem); /* vtkSetObjectMacro(DataSet,vtkDataSet); */ /* vtkGetObjectMacro(DataSet,vtkDataSet); */ void SetDataSet(vtkDataSet* dataSet) {this->DataSet = dataSet;}; vtkDataSet* GetDataSet() {return this->DataSet;}; vtkSetMacro(DataSetPointId,vtkIdType); vtkGetMacro(DataSetPointId,vtkIdType); // Description: // Build the item. virtual void Build() = 0; // Description: // Standard DeepCopy method. virtual void DeepCopy(vtkvmtkItem *src); vtkSetMacro(ReallocateOnBuild,int) vtkGetMacro(ReallocateOnBuild,int) vtkBooleanMacro(ReallocateOnBuild,int) protected: vtkvmtkDataSetItem(); ~vtkvmtkDataSetItem() {}; vtkDataSet *DataSet; vtkIdType DataSetPointId; int ReallocateOnBuild; private: vtkvmtkDataSetItem(const vtkvmtkDataSetItem&); // Not implemented. void operator=(const vtkvmtkDataSetItem&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldExtendedNeighborhood.h0000664000175000017500000000376211757446472027735 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataManifoldExtendedNeighborhood.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataManifoldExtendedNeighborhood - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataManifoldExtendedNeighborhood_h #define __vtkvmtkPolyDataManifoldExtendedNeighborhood_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkPolyDataManifoldNeighborhood.h" #include "vtkPolyData.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataManifoldExtendedNeighborhood : public vtkvmtkPolyDataManifoldNeighborhood { public: static vtkvmtkPolyDataManifoldExtendedNeighborhood *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataManifoldExtendedNeighborhood,vtkvmtkPolyDataManifoldNeighborhood); virtual vtkIdType GetItemType() {return VTK_VMTK_POLYDATA_MANIFOLD_EXTENDED_NEIGHBORHOOD;}; // Description: // Build the neighborhood. virtual void Build(); protected: vtkvmtkPolyDataManifoldExtendedNeighborhood() {}; ~vtkvmtkPolyDataManifoldExtendedNeighborhood() {}; private: vtkvmtkPolyDataManifoldExtendedNeighborhood(const vtkvmtkPolyDataManifoldExtendedNeighborhood&); // Not implemented. void operator=(const vtkvmtkPolyDataManifoldExtendedNeighborhood&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataLaplaceBeltramiStencil.cxx0000664000175000017500000001007011757446472027077 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataLaplaceBeltramiStencil.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataLaplaceBeltramiStencil.h" #include "vtkvmtkMath.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataLaplaceBeltramiStencil, "$Revision: 1.4 $"); vtkvmtkPolyDataLaplaceBeltramiStencil::vtkvmtkPolyDataLaplaceBeltramiStencil() { this->NumberOfComponents = 1; } void vtkvmtkPolyDataLaplaceBeltramiStencil::BuildBoundaryWeights(vtkIdType boundaryPointId, vtkIdType boundaryNeighborPointId, double &boundaryWeight, double &boundaryNeighborWeight) { double point[3], point1[3], point2[3]; double vector1[3], vector2[3]; double triangleArea; if (!this->IsBoundary) return; this->DataSet->GetPoint(this->DataSetPointId,point); this->DataSet->GetPoint(boundaryPointId,point1); this->DataSet->GetPoint(boundaryNeighborPointId,point2); 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]; triangleArea = vtkvmtkMath::TriangleArea(point,point1,point2); boundaryWeight = vtkMath::Distance2BetweenPoints(point,point2); boundaryNeighborWeight = vtkMath::Dot(vector1,vector2); if (triangleAreaSuperclass::Build(); vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet); if (!this->IsBoundary) { firstId = 0; lastId = this->NPoints-1; } else { firstId = 1; lastId = this->NPoints-3; } pdata->GetPoint(this->DataSetPointId,point); for (j=0; jNPoints; j++) this->Weights[j] = 0.0; for (j=firstId; j<=lastId; j++) { pdata->GetPoint(this->PointIds[j],point1); pdata->GetPoint(this->PointIds[(j+1)%this->NPoints],point2); cotangent = vtkvmtkMath::Cotangent(point,point2,point1); this->Weights[j] += cotangent / 2.0; cotangent = vtkvmtkMath::Cotangent(point,point1,point2); this->Weights[(j+1)%this->NPoints] += cotangent / 2.0; } if (this->IsBoundary) { this->BuildBoundaryWeights(this->PointIds[0],this->PointIds[1],boundaryWeight,boundaryNeighborWeight); this->Weights[0] += boundaryWeight; this->Weights[1] += boundaryNeighborWeight; this->BuildBoundaryWeights(this->PointIds[this->NPoints-1],this->PointIds[this->NPoints-2],boundaryWeight,boundaryNeighborWeight); this->Weights[this->NPoints-1] += boundaryWeight; this->Weights[this->NPoints-2] += boundaryNeighborWeight; } this->CenterWeight[0] = 0.0; for (j=0; jNPoints; j++) { this->CenterWeight[0] += this->Weights[j]; } this->ComputeArea(); this->ScaleWithArea(); this->ChangeWeightSign(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldStencil.h0000664000175000017500000000365511757446472025247 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataManifoldStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataManifoldStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataManifoldStencil_h #define __vtkvmtkPolyDataManifoldStencil_h #include "vtkObject.h" #include "vtkvmtkStencil.h" #include "vtkPolyData.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataManifoldStencil : public vtkvmtkStencil { public: vtkTypeRevisionMacro(vtkvmtkPolyDataManifoldStencil,vtkvmtkStencil); vtkGetMacro(Area,double); // Description: // Build the stencil. virtual void Build(); virtual void ComputeArea(); virtual void ScaleWithArea() = 0; void DeepCopy(vtkvmtkPolyDataManifoldStencil *src); vtkGetMacro(UseExtendedNeighborhood,int); vtkSetMacro(UseExtendedNeighborhood,int); vtkBooleanMacro(UseExtendedNeighborhood,int); protected: vtkvmtkPolyDataManifoldStencil(); ~vtkvmtkPolyDataManifoldStencil() {}; void ScaleWithAreaFactor(double factor); double Area; int UseExtendedNeighborhood; private: vtkvmtkPolyDataManifoldStencil(const vtkvmtkPolyDataManifoldStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataManifoldStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkGaussQuadrature.h0000664000175000017500000000563411757446472023655 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkGaussQuadrature.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkGaussQuadrature - .. // .SECTION Description // .. #ifndef __vtkvmtkGaussQuadrature_h #define __vtkvmtkGaussQuadrature_h #include "vtkObject.h" #include "vtkvmtkWin32Header.h" #include "vtkCell.h" #include "vtkDoubleArray.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkGaussQuadrature : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkGaussQuadrature,vtkObject); static vtkvmtkGaussQuadrature* New(); vtkGetObjectMacro(QuadraturePoints,vtkDoubleArray); vtkGetObjectMacro(QuadratureWeights,vtkDoubleArray); vtkSetMacro(Order,int); vtkGetMacro(Order,int); int GetNumberOfQuadraturePoints() { return this->QuadraturePoints->GetNumberOfTuples(); } double* GetQuadraturePoint(vtkIdType id) { return this->QuadraturePoints->GetTuple(id); } void GetQuadraturePoint(vtkIdType id, double* quadraturePoint) { this->QuadraturePoints->GetTuple(id,quadraturePoint); } double GetQuadraturePoint(vtkIdType id, int c) { return this->QuadraturePoints->GetComponent(id,c); } double GetQuadratureWeight(vtkIdType id) { return this->QuadratureWeights->GetValue(id); } void Initialize(vtkIdType cellType); void Initialize(vtkCell* cell) { this->Initialize(cell->GetCellType()); } void Initialize1DGauss(); void Initialize1DJacobi(int alpha, int beta); void ScaleTo01(); protected: vtkvmtkGaussQuadrature(); ~vtkvmtkGaussQuadrature(); void TensorProductQuad(vtkvmtkGaussQuadrature* q1D); void TensorProductTriangle(vtkvmtkGaussQuadrature* gauss1D, vtkvmtkGaussQuadrature* jacA1D); void TensorProductHexahedron(vtkvmtkGaussQuadrature* q1D); void TensorProductWedge(vtkvmtkGaussQuadrature* q1D, vtkvmtkGaussQuadrature* q2D); void TensorProductTetra(vtkvmtkGaussQuadrature* gauss1D, vtkvmtkGaussQuadrature* jacA1D, vtkvmtkGaussQuadrature* jacB1D); vtkDoubleArray* QuadraturePoints; vtkDoubleArray* QuadratureWeights; int Order; int QuadratureType; vtkIdType CellType; int PreviousOrder; private: vtkvmtkGaussQuadrature(const vtkvmtkGaussQuadrature&); // Not implemented. void operator=(const vtkvmtkGaussQuadrature&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridVorticityFilter.h0000664000175000017500000000464011757446472027131 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridVorticityFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridVorticityFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkUnstructuredGridVorticityFilter_h #define __vtkvmtkUnstructuredGridVorticityFilter_h #include "vtkvmtkWin32Header.h" #include "vtkUnstructuredGridAlgorithm.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridVorticityFilter : public vtkUnstructuredGridAlgorithm { public: static vtkvmtkUnstructuredGridVorticityFilter* New(); vtkTypeRevisionMacro(vtkvmtkUnstructuredGridVorticityFilter,vtkUnstructuredGridAlgorithm); vtkSetStringMacro(VelocityArrayName); vtkGetStringMacro(VelocityArrayName); vtkSetStringMacro(VorticityArrayName); vtkGetStringMacro(VorticityArrayName); vtkSetStringMacro(HelicityFactorArrayName); vtkGetStringMacro(HelicityFactorArrayName); vtkSetMacro(ComputeHelicityFactor,int); vtkGetMacro(ComputeHelicityFactor,int); vtkBooleanMacro(ComputeHelicityFactor,int); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); protected: vtkvmtkUnstructuredGridVorticityFilter(); ~vtkvmtkUnstructuredGridVorticityFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* VelocityArrayName; char* VorticityArrayName; char* HelicityFactorArrayName; int ComputeHelicityFactor; double ConvergenceTolerance; int QuadratureOrder; private: vtkvmtkUnstructuredGridVorticityFilter(const vtkvmtkUnstructuredGridVorticityFilter&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridVorticityFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkOpenNLLinearSystemSolver.cxx0000664000175000017500000000626311757446472025775 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkOpenNLLinearSystemSolver.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkOpenNLLinearSystemSolver.h" #include "vtkObjectFactory.h" extern "C" { #include "nl.h" } vtkCxxRevisionMacro(vtkvmtkOpenNLLinearSystemSolver, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkOpenNLLinearSystemSolver); vtkvmtkOpenNLLinearSystemSolver::vtkvmtkOpenNLLinearSystemSolver() { this->SolverType = VTK_VMTK_OPENNL_SOLVER_CG; this->PreconditionerType = VTK_VMTK_OPENNL_PRECONDITIONER_NONE; this->Omega = 0.0; } int vtkvmtkOpenNLLinearSystemSolver::Solve() { vtkvmtkSparseMatrix *system; vtkvmtkDoubleVector *solution, *rhs; if (this->Superclass::Solve()==-1) { return -1; } system = this->LinearSystem->GetA(); rhs = this->LinearSystem->GetB(); solution = this->LinearSystem->GetX(); nlNewContext(); nlSolverParameteri(NL_SOLVER,NL_CG); switch (this->SolverType) { case VTK_VMTK_OPENNL_SOLVER_CG: nlSolverParameteri(NL_SOLVER,NL_CG); break; case VTK_VMTK_OPENNL_SOLVER_BICGSTAB: nlSolverParameteri(NL_SOLVER,NL_BICGSTAB); break; case VTK_VMTK_OPENNL_SOLVER_GMRES: nlSolverParameteri(NL_SOLVER,NL_GMRES); break; } switch (this->PreconditionerType) { case VTK_VMTK_OPENNL_PRECONDITIONER_NONE: nlSolverParameteri(NL_PRECONDITIONER,NL_PRECOND_NONE); break; case VTK_VMTK_OPENNL_PRECONDITIONER_JACOBI: nlSolverParameteri(NL_PRECONDITIONER,NL_PRECOND_JACOBI); break; case VTK_VMTK_OPENNL_PRECONDITIONER_SSOR: nlSolverParameteri(NL_PRECONDITIONER,NL_PRECOND_SSOR); break; } nlSolverParameteri(NL_NB_VARIABLES,rhs->GetNumberOfElements()); nlSolverParameteri(NL_LEAST_SQUARES,NL_FALSE); nlSolverParameteri(NL_MAX_ITERATIONS,this->MaximumNumberOfIterations); nlSolverParameterd(NL_THRESHOLD,this->ConvergenceTolerance); nlBegin(NL_SYSTEM); nlBegin(NL_MATRIX); int i, j; for (i=0; iGetNumberOfRows(); i++) { nlRowParameterd(NL_RIGHT_HAND_SIDE,-rhs->GetElement(i)); vtkvmtkSparseMatrixRow* row = system->GetRow(i); nlBegin(NL_ROW); for (j=0; jGetNumberOfElements(); j++) { nlCoefficient(row->GetElementId(j),row->GetElement(j)); } nlCoefficient(i,row->GetDiagonalElement()); nlEnd(NL_ROW); } nlEnd(NL_MATRIX); nlEnd(NL_SYSTEM); nlSolve(); for (i=0; iGetNumberOfElements(); i++) { solution->SetElement(i,nlGetVariable(i)); } nlDeleteContext(nlGetCurrent()); return 0; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFELaplaceAssembler.h0000664000175000017500000000305611757446472025601 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFELaplaceAssembler.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(vtkvmtkPolyDataFELaplaceAssembler,vtkvmtkFEAssembler); virtual void Build(); protected: vtkvmtkPolyDataFELaplaceAssembler(); ~vtkvmtkPolyDataFELaplaceAssembler(); private: vtkvmtkPolyDataFELaplaceAssembler(const vtkvmtkPolyDataFELaplaceAssembler&); // Not implemented. void operator=(const vtkvmtkPolyDataFELaplaceAssembler&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkSparseMatrix.h0000664000175000017500000000453711757446472023160 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSparseMatrix.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(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 vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkNeighborhood.cxx0000664000175000017500000000425611757446472023516 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNeighborhood.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkNeighborhood.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkNeighborhood, "$Revision: 1.2 $"); vtkvmtkNeighborhood::vtkvmtkNeighborhood() { this->NPoints = 0; this->PointIds = NULL; this->IsBoundary = false; } vtkvmtkNeighborhood::~vtkvmtkNeighborhood() { if (this->PointIds != NULL) { delete [] this->PointIds; this->PointIds = NULL; } } void vtkvmtkNeighborhood::ResizePointList(vtkIdType ptId, int size) { int newSize; vtkIdType *pointIds; newSize = this->NPoints + size; pointIds = new vtkIdType[newSize]; memcpy(pointIds, this->PointIds,this->NPoints*sizeof(vtkIdType)); delete [] this->PointIds; this->PointIds = NULL; this->PointIds = pointIds; this->NPoints = newSize; } void vtkvmtkNeighborhood::DeepCopy(vtkvmtkItem *src) { this->Superclass::DeepCopy(src); vtkvmtkNeighborhood* neighborhoodSrc = vtkvmtkNeighborhood::SafeDownCast(src); if (neighborhoodSrc==NULL) { vtkErrorMacro(<<"Trying to deep copy a non-stencil item"); } this->NPoints = neighborhoodSrc->NPoints; if (this->PointIds != NULL) { delete [] this->PointIds; this->PointIds = NULL; } if (neighborhoodSrc->NPoints>0) { this->PointIds = new vtkIdType[neighborhoodSrc->NPoints]; memcpy(this->PointIds, neighborhoodSrc->PointIds, this->NPoints * sizeof(vtkIdType)); } this->IsBoundary = neighborhoodSrc->IsBoundary; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkNeighborhood.h0000664000175000017500000000362111757446472023136 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNeighborhood.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkNeighborhood - .. // .SECTION Description // .. #ifndef __vtkvmtkNeighborhood_h #define __vtkvmtkNeighborhood_h #include "vtkObject.h" #include "vtkvmtkDataSetItem.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkNeighborhood : public vtkvmtkDataSetItem { public: vtkTypeRevisionMacro(vtkvmtkNeighborhood,vtkvmtkDataSetItem); vtkGetMacro(IsBoundary,bool); vtkIdType GetNumberOfPoints() {return this->NPoints;}; vtkIdType GetPointId(vtkIdType i) {return this->PointIds[i];}; vtkIdType *GetPointer(vtkIdType i) {return this->PointIds+i;}; // Description: // Build the neighborhood. virtual void Build() = 0; // Description: // Standard DeepCopy method. virtual void DeepCopy(vtkvmtkItem *src); protected: vtkvmtkNeighborhood(); ~vtkvmtkNeighborhood(); void ResizePointList(vtkIdType ptId, int size); vtkIdType NPoints; vtkIdType* PointIds; bool IsBoundary; private: vtkvmtkNeighborhood(const vtkvmtkNeighborhood&); // Not implemented. void operator=(const vtkvmtkNeighborhood&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataNeighborhood.cxx0000664000175000017500000000460011757446472025145 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataNeighborhood.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataNeighborhood.h" #include "vtkObjectFactory.h" #include "vtkIdList.h" #include "vtkCell.h" vtkCxxRevisionMacro(vtkvmtkPolyDataNeighborhood, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataNeighborhood); void vtkvmtkPolyDataNeighborhood::Build() { vtkIdType i, j; vtkIdType numCellsInStencil; vtkIdList *cellIds, *ptIds, *stencilIds; vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet); if (pdata==NULL) { vtkErrorMacro(<< "Input data NULL or not poly data"); } vtkIdType 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; } vtkIdType cellPointId; for (i=0; iGetCellPoints(cellIds->GetId(i),ptIds); for (j=0; jGetNumberOfIds(); j++) { cellPointId = ptIds->GetId(j); if (cellPointId != pointId) { stencilIds->InsertUniqueId(ptIds->GetId(j)); } } } 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(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkLinearSystem.h0000664000175000017500000000347211757446472023152 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearSystem.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkLinearSystem - .. // .SECTION Description // .. #ifndef __vtkvmtkLinearSystem_h #define __vtkvmtkLinearSystem_h #include "vtkObject.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkDoubleVector.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkLinearSystem : public vtkObject { public: static vtkvmtkLinearSystem* New(); vtkTypeRevisionMacro(vtkvmtkLinearSystem,vtkObject); vtkSetObjectMacro(A,vtkvmtkSparseMatrix); vtkGetObjectMacro(A,vtkvmtkSparseMatrix); vtkSetObjectMacro(X,vtkvmtkDoubleVector); vtkGetObjectMacro(X,vtkvmtkDoubleVector); vtkSetObjectMacro(B,vtkvmtkDoubleVector); vtkGetObjectMacro(B,vtkvmtkDoubleVector); int CheckSystem(); protected: vtkvmtkLinearSystem(); ~vtkvmtkLinearSystem(); vtkvmtkSparseMatrix* A; vtkvmtkDoubleVector* X; vtkvmtkDoubleVector* B; private: vtkvmtkLinearSystem(const vtkvmtkLinearSystem&); // Not implemented. void operator=(const vtkvmtkLinearSystem&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridGradientFilter.h0000664000175000017500000000450211757446472026667 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridGradientFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(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 *); char* InputArrayName; char* GradientArrayName; double ConvergenceTolerance; int QuadratureOrder; int ComputeIndividualPartialDerivatives; private: vtkvmtkUnstructuredGridGradientFilter(const vtkvmtkUnstructuredGridGradientFilter&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridGradientFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldNeighborhood.cxx0000664000175000017500000001043311757446472026620 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataManifoldNeighborhood.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataManifoldNeighborhood, "$Revision: 1.3 $"); 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; jGetCell(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 (; jGetCell(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(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkItems.h0000664000175000017500000000531011757446472021605 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkItems.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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: vtkTypeRevisionMacro(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 vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkEmptyNeighborhood.h0000664000175000017500000000324311757446472024155 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkEmptyNeighborhood.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(vtkvmtkEmptyNeighborhood,vtkvmtkNeighborhood); virtual vtkIdType GetItemType() {return VTK_VMTK_EMPTY_NEIGHBORHOOD;}; // Description: // Build the stencil. void Build(); protected: vtkvmtkEmptyNeighborhood() {}; ~vtkvmtkEmptyNeighborhood() {}; private: vtkvmtkEmptyNeighborhood(const vtkvmtkEmptyNeighborhood&); // Not implemented. void operator=(const vtkvmtkEmptyNeighborhood&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFVFELaplaceBeltramiStencil.h0000664000175000017500000000370511757446472027202 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFVFELaplaceBeltramiStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataFVFELaplaceBeltramiStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataFVFELaplaceBeltramiStencil_h #define __vtkvmtkPolyDataFVFELaplaceBeltramiStencil_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkPolyDataLaplaceBeltramiStencil.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataFVFELaplaceBeltramiStencil : public vtkvmtkPolyDataLaplaceBeltramiStencil { public: static vtkvmtkPolyDataFVFELaplaceBeltramiStencil *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataFVFELaplaceBeltramiStencil,vtkvmtkPolyDataLaplaceBeltramiStencil); virtual vtkIdType GetItemType() {return VTK_VMTK_FVFE_LAPLACE_BELTRAMI_STENCIL;}; protected: vtkvmtkPolyDataFVFELaplaceBeltramiStencil(); ~vtkvmtkPolyDataFVFELaplaceBeltramiStencil() {}; void ComputeArea(vtkPolyData *data, vtkIdType pointId); void ScaleWithArea(); private: vtkvmtkPolyDataFVFELaplaceBeltramiStencil(const vtkvmtkPolyDataFVFELaplaceBeltramiStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataFVFELaplaceBeltramiStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkOpenNLLinearSystemSolver.h0000664000175000017500000000532711757446472025422 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkOpenNLLinearSystemSolver.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .SECTION Description // .. #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(); vtkTypeRevisionMacro(vtkvmtkOpenNLLinearSystemSolver,vtkvmtkLinearSystemSolver); int Solve(); 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 vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridHarmonicMappingFilter.h0000664000175000017500000000466211757446472030215 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridHarmonicMappingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridHarmonicMappingFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkUnstructuredGridHarmonicMappingFilter_h #define __vtkvmtkUnstructuredGridHarmonicMappingFilter_h #include "vtkvmtkWin32Header.h" #include "vtkUnstructuredGridAlgorithm.h" #include "vtkIdList.h" #include "vtkDoubleArray.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridHarmonicMappingFilter : public vtkUnstructuredGridAlgorithm { public: static vtkvmtkUnstructuredGridHarmonicMappingFilter* New(); vtkTypeRevisionMacro(vtkvmtkUnstructuredGridHarmonicMappingFilter,vtkUnstructuredGridAlgorithm); vtkSetObjectMacro(BoundaryPointIds,vtkIdList); vtkGetObjectMacro(BoundaryPointIds,vtkIdList); vtkSetObjectMacro(BoundaryValues,vtkDoubleArray); vtkGetObjectMacro(BoundaryValues,vtkDoubleArray); vtkSetStringMacro(HarmonicMappingArrayName); vtkGetStringMacro(HarmonicMappingArrayName); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); protected: vtkvmtkUnstructuredGridHarmonicMappingFilter(); ~vtkvmtkUnstructuredGridHarmonicMappingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); vtkIdList* BoundaryPointIds; vtkDoubleArray* BoundaryValues; char* HarmonicMappingArrayName; double ConvergenceTolerance; int QuadratureOrder; private: vtkvmtkUnstructuredGridHarmonicMappingFilter(const vtkvmtkUnstructuredGridHarmonicMappingFilter&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridHarmonicMappingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataSurfaceRemeshing.cxx0000664000175000017500000013763011757446472026002 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataSurfaceRemeshing.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataSurfaceRemeshing.h" #include "vtkvmtkPolyDataUmbrellaStencil.h" #include "vtkvmtkPolyDataBoundaryExtractor.h" #include "vtkPolyDataNormals.h" #include "vtkIdList.h" #include "vtkIntArray.h" #include "vtkCellArray.h" #include "vtkMeshQuality.h" #include "vtkCellLocator.h" #include "vtkTriangle.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataSurfaceRemeshing, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataSurfaceRemeshing); vtkvmtkPolyDataSurfaceRemeshing::vtkvmtkPolyDataSurfaceRemeshing() { this->AspectRatioThreshold = 1.2; this->InternalAngleTolerance = 0.0; this->NormalAngleTolerance = 0.2; this->CollapseAngleThreshold = 0.5; this->Relaxation = 0.5; this->TargetArea = 1.0; this->TargetAreaFactor = 1.0; this->MinAreaFactor = 0.5; this->MaxArea = VTK_VMTK_LARGE_FLOAT; this->MinArea = 0.0; this->TargetAreaArrayName = NULL; this->TargetAreaArray = NULL; this->NumberOfConnectivityOptimizationIterations = 20; this->NumberOfIterations = 10; this->ElementSizeMode = TARGET_AREA; this->PreserveBoundaryEdges = 0; this->CellEntityIdsArrayName = NULL; this->CellEntityIdsArray = NULL; this->Mesh = NULL; this->InputBoundary = NULL; this->InputEntityBoundary = NULL; this->Locator = NULL; this->BoundaryLocator = NULL; this->EntityBoundaryLocator = NULL; this->ExcludedEntityIds = NULL; } vtkvmtkPolyDataSurfaceRemeshing::~vtkvmtkPolyDataSurfaceRemeshing() { if (this->Mesh) { this->Mesh->Delete(); this->Mesh = NULL; } if (this->InputBoundary) { this->InputBoundary->Delete(); this->InputBoundary = NULL; } if (this->InputEntityBoundary) { this->InputEntityBoundary->Delete(); this->InputEntityBoundary = NULL; } if (this->Locator) { this->Locator->Delete(); this->Locator = NULL; } if (this->BoundaryLocator) { this->BoundaryLocator->Delete(); this->BoundaryLocator = NULL; } if (this->EntityBoundaryLocator) { this->EntityBoundaryLocator->Delete(); this->EntityBoundaryLocator = NULL; } if (this->TargetAreaArrayName) { delete[] this->TargetAreaArrayName; this->TargetAreaArrayName = NULL; } if (this->CellEntityIdsArrayName) { delete[] this->CellEntityIdsArrayName; this->CellEntityIdsArrayName = NULL; } if (this->CellEntityIdsArray) { this->CellEntityIdsArray->Delete(); this->CellEntityIdsArray = NULL; } if (this->ExcludedEntityIds) { this->ExcludedEntityIds->Delete(); this->ExcludedEntityIds = NULL; } } int vtkvmtkPolyDataSurfaceRemeshing::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->ElementSizeMode == TARGET_AREA_ARRAY) { if (!this->TargetAreaArrayName) { vtkErrorMacro(<<"TargetAreaArrayName not specified"); return 1; } this->TargetAreaArray = input->GetPointData()->GetArray(this->TargetAreaArrayName); if (!this->TargetAreaArray) { vtkErrorMacro(<<"TargetAreaArray with name specified does not exist"); return 1; } } if (this->CellEntityIdsArray) { this->CellEntityIdsArray->Delete(); this->CellEntityIdsArray = NULL; } this->CellEntityIdsArray = vtkIntArray::New(); if (this->CellEntityIdsArrayName) { vtkDataArray* cellEntityIdsArray = input->GetCellData()->GetArray(this->CellEntityIdsArrayName); if (!cellEntityIdsArray) { vtkErrorMacro(<<"CellEntityIdsArray with name specified does not exist"); return 1; } this->CellEntityIdsArray->DeepCopy(cellEntityIdsArray); } else { this->CellEntityIdsArray->SetNumberOfValues(input->GetNumberOfCells()); this->CellEntityIdsArray->FillComponent(0,0.0); } if (this->Mesh) { this->Mesh->Delete(); this->Mesh = NULL; } vtkPolyDataNormals* normals = vtkPolyDataNormals::New(); normals->SetInput(input); normals->ComputePointNormalsOff(); normals->ComputeCellNormalsOn(); normals->AutoOrientNormalsOn(); normals->ConsistencyOn(); normals->SplittingOff(); normals->Update(); vtkDataArray* cellNormals = normals->GetOutput()->GetCellData()->GetNormals(); this->Mesh = vtkPolyData::New(); vtkPoints* workingPoints = vtkPoints::New(); vtkCellArray* workingCells = vtkCellArray::New(); workingPoints->DeepCopy(input->GetPoints()); double point1[3], point2[3], point3[3]; double cellNormal[3], orientedCellNormal[3]; for (int i=0; iGetNumberOfCells(); i++) { if (input->GetCellType(i) != VTK_TRIANGLE) { continue; } vtkCell* cell = input->GetCell(i); cell->GetPoints()->GetPoint(0,point1); cell->GetPoints()->GetPoint(1,point2); cell->GetPoints()->GetPoint(2,point3); vtkTriangle::ComputeNormal(point1,point2,point3,cellNormal); cellNormals->GetTuple(i,orientedCellNormal); workingCells->InsertNextCell(3); if (vtkMath::Dot(cellNormal,orientedCellNormal) > 0.0) { workingCells->InsertCellPoint(cell->GetPointId(0)); workingCells->InsertCellPoint(cell->GetPointId(1)); workingCells->InsertCellPoint(cell->GetPointId(2)); } else { workingCells->InsertCellPoint(cell->GetPointId(1)); workingCells->InsertCellPoint(cell->GetPointId(0)); workingCells->InsertCellPoint(cell->GetPointId(2)); } } this->Mesh->SetPoints(workingPoints); this->Mesh->SetPolys(workingCells); workingPoints->Delete(); workingCells->Delete(); normals->Delete(); this->Mesh->BuildCells(); this->Mesh->BuildLinks(); if (this->Locator) { this->Locator->Delete(); this->Locator = NULL; } this->Locator = vtkCellLocator::New(); this->Locator->SetDataSet(input); this->Locator->SetNumberOfCellsPerBucket(5); this->Locator->CacheCellBoundsOn(); this->Locator->BuildLocator(); if (this->InputBoundary) { this->InputBoundary->Delete(); this->InputBoundary = NULL; } vtkvmtkPolyDataBoundaryExtractor* boundaryExtractor = vtkvmtkPolyDataBoundaryExtractor::New(); boundaryExtractor->SetInput(input); boundaryExtractor->Update(); this->InputBoundary = vtkPolyData::New(); this->InputBoundary->DeepCopy(boundaryExtractor->GetOutput()); boundaryExtractor->Delete(); if (this->BoundaryLocator) { this->BoundaryLocator->Delete(); this->BoundaryLocator = NULL; } if (this->InputBoundary->GetNumberOfCells() > 0) { this->BoundaryLocator = vtkCellLocator::New(); this->BoundaryLocator->SetDataSet(this->InputBoundary); this->BoundaryLocator->BuildLocator(); } if (this->InputEntityBoundary) { this->InputEntityBoundary->Delete(); this->InputEntityBoundary = NULL; } this->InputEntityBoundary = vtkPolyData::New(); this->BuildEntityBoundary(this->Mesh,this->InputEntityBoundary); if (this->EntityBoundaryLocator) { this->EntityBoundaryLocator->Delete(); this->EntityBoundaryLocator = NULL; } if (this->InputEntityBoundary->GetNumberOfCells() > 0) { this->EntityBoundaryLocator = vtkCellLocator::New(); this->EntityBoundaryLocator->SetDataSet(this->InputEntityBoundary); this->EntityBoundaryLocator->BuildLocator(); } int relocationSuccess = RELOCATE_SUCCESS; for (int n=0; nNumberOfIterations; n++) { cout<<"Iteration "<NumberOfIterations<EdgeCollapseIteration(); this->EdgeFlipIteration(); this->EdgeSplitIteration(); this->EdgeFlipIteration(); relocationSuccess = this->PointRelocationIteration(); if (relocationSuccess == RELOCATE_FAILURE) { break; } this->EdgeFlipIteration(); for (int i=0; iNumberOfConnectivityOptimizationIterations; i++) { this->EdgeFlipConnectivityOptimizationIteration(); } } cout<<"Final mesh improvement"<NumberOfIterations; i++) { if (i == this->NumberOfIterations/2) { projectToSurface = true; } relocationSuccess = this->PointRelocationIteration(projectToSurface); if (relocationSuccess == RELOCATE_FAILURE) { break; } } if (relocationSuccess == RELOCATE_FAILURE) { return 1; } vtkPoints* newPoints = vtkPoints::New(); vtkCellArray* newCells = vtkCellArray::New(); vtkIntArray* newCellEntityIdsArray = vtkIntArray::New(); newCellEntityIdsArray->SetName(this->CellEntityIdsArrayName); newPoints->DeepCopy(this->Mesh->GetPoints()); int numberOfFinalCells = this->Mesh->GetNumberOfCells(); for (int i=0; iMesh->GetCellType(i) == VTK_EMPTY_CELL) { continue; } if (this->GetNumberOfBoundaryEdges(i) > 1) { continue; } newCells->InsertNextCell(this->Mesh->GetCell(i)); newCellEntityIdsArray->InsertNextValue(this->CellEntityIdsArray->GetValue(i)); } output->SetPoints(newPoints); output->SetPolys(newCells); output->GetCellData()->AddArray(newCellEntityIdsArray); newPoints->Delete(); newCells->Delete(); newCellEntityIdsArray->Delete(); return 1; } void vtkvmtkPolyDataSurfaceRemeshing::BuildEntityBoundary(vtkPolyData* input, vtkPolyData* entityBoundary) { vtkPoints* entityBoundaryPoints = vtkPoints::New(); vtkCellArray* entityBoundaryCells = vtkCellArray::New(); vtkIdList* cellIds = vtkIdList::New(); vtkIdType numberOfCells = input->GetNumberOfCells(); vtkIdType npts, *pts; for (int i=0; iGetCellType(i) != VTK_TRIANGLE) { continue; } input->GetCellPoints(i,npts,pts); vtkIdType cellEntityId = this->CellEntityIdsArray->GetValue(i); for (int j=0; jInitialize(); vtkIdType pt1 = pts[j]; vtkIdType pt2 = pts[(j+1)%npts]; input->GetCellEdgeNeighbors(i,pt1,pt2,cellIds); bool entityBoundaryEdge = false; for (int k=0; kGetNumberOfIds(); k++) { if (this->CellEntityIdsArray->GetValue(cellIds->GetId(k)) != cellEntityId) { entityBoundaryEdge = true; break; } } if (entityBoundaryEdge) { vtkIdType pt1Id = entityBoundaryPoints->InsertNextPoint(input->GetPoint(pt1)); vtkIdType pt2Id = entityBoundaryPoints->InsertNextPoint(input->GetPoint(pt2)); entityBoundaryCells->InsertNextCell(2); entityBoundaryCells->InsertCellPoint(pt1Id); entityBoundaryCells->InsertCellPoint(pt2Id); } } } entityBoundary->SetPoints(entityBoundaryPoints); entityBoundary->SetLines(entityBoundaryCells); cellIds->Delete(); entityBoundaryPoints->Delete(); entityBoundaryCells->Delete(); } int vtkvmtkPolyDataSurfaceRemeshing::GetNumberOfBoundaryEdges(vtkIdType cellId) { int numberOfBoundaryEdges = 0; vtkIdList* cellEdgeNeighbors = vtkIdList::New(); vtkIdType npts, *pts; this->Mesh->GetCellPoints(cellId,npts,pts); for (int j=0; jMesh->IsEdge(pts[j],pts[(j+1)%npts])) { this->Mesh->GetCellEdgeNeighbors(cellId,pts[j],pts[(j+1)%npts],cellEdgeNeighbors); if (cellEdgeNeighbors->GetNumberOfIds() == 0) { numberOfBoundaryEdges++; } } } cellEdgeNeighbors->Delete(); return numberOfBoundaryEdges; } int vtkvmtkPolyDataSurfaceRemeshing::IsPointOnBoundary(vtkIdType pointId) { unsigned short ncells; vtkIdType* cells; this->Mesh->GetPointCells(pointId,ncells,cells); vtkIdList* cellEdgeNeighbors = vtkIdList::New(); for (int i=0; iMesh->GetCellPoints(cells[i],npts,pts); for (int j=0; jMesh->IsEdge(pts[j],pointId)) { this->Mesh->GetCellEdgeNeighbors(cells[i],pts[j],pointId,cellEdgeNeighbors); if (cellEdgeNeighbors->GetNumberOfIds() == 0) { cellEdgeNeighbors->Delete(); return 1; } } } } cellEdgeNeighbors->Delete(); return 0; } int vtkvmtkPolyDataSurfaceRemeshing::EdgeFlipConnectivityOptimizationIteration() { //TODO: randomize. int numberOfChanges = 0; int numberOfCells = this->Mesh->GetNumberOfCells(); for (int i=0; iMesh->GetCellType(i) != VTK_TRIANGLE) { continue; } vtkIdType npts, *pts; this->Mesh->GetCellPoints(i,npts,pts); vtkIdType tripts[3]; tripts[0] = pts[0]; tripts[1] = pts[1]; tripts[2] = pts[2]; for (int j=0; j<3; j++) { int test = this->TestConnectivityFlipEdge(tripts[j],tripts[(j+1)%3]); if (test == DO_NOTHING) { continue; } this->FlipEdge(tripts[j],tripts[(j+1)%3]); numberOfChanges++; break; } } return numberOfChanges; } int vtkvmtkPolyDataSurfaceRemeshing::EdgeFlipIteration() { int numberOfChanges = 0; int numberOfCells = this->Mesh->GetNumberOfCells(); for (int i=0; iMesh->GetCellType(i) != VTK_TRIANGLE) { continue; } vtkIdType npts, *pts; this->Mesh->GetCellPoints(i,npts,pts); vtkIdType tripts[3]; tripts[0] = pts[0]; tripts[1] = pts[1]; tripts[2] = pts[2]; for (int j=0; j<3; j++) { int test = this->TestDelaunayFlipEdge(tripts[j],tripts[(j+1)%3]); if (test == DO_NOTHING) { continue; } this->FlipEdge(tripts[j],tripts[(j+1)%3]); numberOfChanges++; break; } } return numberOfChanges; } int vtkvmtkPolyDataSurfaceRemeshing::EdgeCollapseIteration() { int numberOfChanges = 0; int numberOfCells = this->Mesh->GetNumberOfCells(); for (int i=0; iMesh->GetCellType(i) != VTK_TRIANGLE) { continue; } vtkIdType pt1, pt2; int test = this->TestAspectRatioCollapseEdge(i,pt1,pt2); if (test == DO_NOTHING) { continue; } this->CollapseEdge(pt1,pt2); numberOfChanges++; } return numberOfChanges; } int vtkvmtkPolyDataSurfaceRemeshing::EdgeSplitIteration() { int numberOfChanges = 0; int numberOfCells = this->Mesh->GetNumberOfCells(); for (int i=0; iMesh->GetCellType(i) != VTK_TRIANGLE) { continue; } vtkIdType pt1, pt2; int test = this->TestAreaSplitEdge(i,pt1,pt2); if (test == DO_NOTHING) { continue; } this->SplitEdge(pt1,pt2); numberOfChanges++; } return numberOfChanges; } int vtkvmtkPolyDataSurfaceRemeshing::PointRelocationIteration(bool projectToSurface) { int numberOfPoints = this->Mesh->GetNumberOfPoints(); int success = RELOCATE_SUCCESS; for (int i=0; iRelocatePoint(i,projectToSurface); if (success == RELOCATE_FAILURE) { return RELOCATE_FAILURE; } } return RELOCATE_SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::IsElementExcluded(vtkIdType cellId) { int isElementExcluded = 0; if (this->ExcludedEntityIds == NULL) { return isElementExcluded; } vtkIdType cellEntityId = this->CellEntityIdsArray->GetValue(cellId); if (this->ExcludedEntityIds->IsId(cellEntityId) != -1) { isElementExcluded = 1; } return isElementExcluded; } int vtkvmtkPolyDataSurfaceRemeshing::IsPointOnEntityBoundary(vtkIdType pointId) { vtkIdList* ptCells = vtkIdList::New(); this->Mesh->GetPointCells(pointId,ptCells); vtkIdType nptCells = ptCells->GetNumberOfIds(); vtkIdType neighborhoodCellEntityId = -1; bool uniformCellEntityIds = true; for (int i=0; iCellEntityIdsArray->GetValue(ptCells->GetId(i)); if (cellEntityId == -1) { continue; } if (neighborhoodCellEntityId == -1) { neighborhoodCellEntityId = cellEntityId; continue; } if (neighborhoodCellEntityId == cellEntityId) { continue; } uniformCellEntityIds = false; break; } if (!uniformCellEntityIds) { return 1; } return 0; } int vtkvmtkPolyDataSurfaceRemeshing::FindOneRingNeighbors(vtkIdType pointId, vtkIdList* neighborIds) { int pointLocation = INTERNAL_POINT; vtkIdList* cellIds = vtkIdList::New(); this->Mesh->GetPointCells(pointId,cellIds); vtkIdType numberOfCells = cellIds->GetNumberOfIds(); if (numberOfCells < 1) { cellIds->Delete(); return NO_NEIGHBORS; } vtkIdList* ptIds = vtkIdList::New(); this->Mesh->GetCellPoints(cellIds->GetId(0),ptIds); vtkIdType bp1, bp2; vtkIdType i, j; vtkIdType p1, p2; p2 = ptIds->GetId(0); for (i=1; i<3; i++) { p2 = ptIds->GetId(i); if (pointId != p2) { break; } } neighborIds->InsertNextId(p2); this->Mesh->GetCellEdgeNeighbors(-1,pointId,p2,cellIds); vtkIdType startCell; vtkIdType nextCell = cellIds->GetId(0); if (cellIds->GetNumberOfIds() == 1) { startCell = -1; } else { startCell = cellIds->GetId(1); } bp2 = -1; bp1 = p2; // walk around the neighborhood counter-clockwise and get cells vtkCell* cell = NULL; for (j=0; jMesh->GetCell(nextCell); p1 = -1; for (i=0; i<3; i++) { p1 = cell->GetPointId(i); if (p1 != pointId && p1 != p2) { break; } } p2 = p1; neighborIds->InsertNextId(p2); this->Mesh->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 (; jMesh->GetCell(nextCell); p1 = -1; for (i=0; i<3; i++) { p1 = cell->GetPointId(i); if (p1 != pointId && p1 != p2) { break; } } p2 = p1; neighborIds->InsertNextId(p2); this->Mesh->GetCellEdgeNeighbors(nextCell,pointId,p2,cellIds); if (cellIds->GetNumberOfIds() != 1) { bp1 = p2; break; } nextCell = cellIds->GetId(0); } if (bp2 != -1) // boundary edge { pointLocation = POINT_ON_BOUNDARY; vtkIdType id = neighborIds->IsId(bp2); for (i=0; i<=id/2; i++) { p1 = neighborIds->GetId(i); p2 = neighborIds->GetId(id-i); neighborIds->SetId(i,p2); neighborIds->SetId(id-i,p1); } } else { // Remove last id. It's a duplicate of the first neighborIds->SetNumberOfIds(neighborIds->GetNumberOfIds()-1); } cellIds->Delete(); ptIds->Delete(); return pointLocation; } #define USE_STENCIL int vtkvmtkPolyDataSurfaceRemeshing::RelocatePoint(vtkIdType pointId, bool projectToSurface) { vtkIdList* cellIds = vtkIdList::New(); this->Mesh->GetPointCells(pointId,cellIds); int pointOnExcludedEntity = 0; for (int i=0; iGetNumberOfIds(); i++) { if (this->IsElementExcluded(cellIds->GetId(i))) { pointOnExcludedEntity = 1; } } cellIds->Delete(); if (pointOnExcludedEntity) { return RELOCATE_SUCCESS; } #ifndef USE_STENCIL vtkIdList* neighborIds = vtkIdList::New(); int pointLocation = this->FindOneRingNeighbors(pointId,neighborIds); #else vtkvmtkPolyDataUmbrellaStencil* stencil = vtkvmtkPolyDataUmbrellaStencil::New(); stencil->SetDataSet(this->Mesh); stencil->SetDataSetPointId(pointId); stencil->NegateWeightsOff(); stencil->Build(); #endif #ifndef USE_STENCIL if (!pointLocation == INTERNAL_POINT) #else if (!stencil->GetIsBoundary()) #endif { double targetPoint[3]; targetPoint[0] = targetPoint[1] = targetPoint[2] = 0.0; #ifndef USE_STENCIL int numberOfNeighbors = neighborIds->GetNumberOfIds(); double stencilWeight = 1.0 / numberOfNeighbors; for (int i=0; iMesh->GetPoint(neighborIds->GetId(i),stencilPoint); targetPoint[0] += stencilWeight * stencilPoint[0]; targetPoint[1] += stencilWeight * stencilPoint[1]; targetPoint[2] += stencilWeight * stencilPoint[2]; } #else for (int i=0; iGetNumberOfPoints(); i++) { double stencilPoint[3]; this->Mesh->GetPoint((stencil->GetPointId(i)),stencilPoint); double stencilWeight = stencil->GetWeight(i); targetPoint[0] += stencilWeight * stencilPoint[0]; targetPoint[1] += stencilWeight * stencilPoint[1]; targetPoint[2] += stencilWeight * stencilPoint[2]; } #endif double point[3]; this->Mesh->GetPoint(pointId,point); double relocatedPoint[3]; relocatedPoint[0] = point[0] + this->Relaxation * (targetPoint[0] - point[0]); relocatedPoint[1] = point[1] + this->Relaxation * (targetPoint[1] - point[1]); relocatedPoint[2] = point[2] + this->Relaxation * (targetPoint[2] - point[2]); double projectedRelocatedPoint[3]; vtkIdType cellId; int subId; double dist2; if (this->IsPointOnEntityBoundary(pointId)) { this->EntityBoundaryLocator->FindClosestPoint(relocatedPoint,projectedRelocatedPoint,cellId,subId,dist2); } else { if (projectToSurface) { this->Locator->FindClosestPoint(relocatedPoint,projectedRelocatedPoint,cellId,subId,dist2); } else { projectedRelocatedPoint[0] = relocatedPoint[0]; projectedRelocatedPoint[1] = relocatedPoint[1]; projectedRelocatedPoint[2] = relocatedPoint[2]; } } this->Mesh->GetPoints()->SetPoint(pointId,projectedRelocatedPoint); } else { double targetPoint[3]; targetPoint[0] = targetPoint[1] = targetPoint[2] = 0.0; double stencilPoint[3]; #ifndef USE_STENCIL this->Mesh->GetPoint(neighborIds->GetId(0),stencilPoint); #else this->Mesh->GetPoint((stencil->GetPointId(0)),stencilPoint); #endif double stencilWeight = 0.5; targetPoint[0] += stencilWeight * stencilPoint[0]; targetPoint[1] += stencilWeight * stencilPoint[1]; targetPoint[2] += stencilWeight * stencilPoint[2]; #ifndef USE_STENCIL this->Mesh->GetPoint(neighborIds->GetId(neighborIds->GetNumberOfIds()-1),stencilPoint); #else this->Mesh->GetPoint((stencil->GetPointId(stencil->GetNumberOfPoints()-1)),stencilPoint); #endif targetPoint[0] += stencilWeight * stencilPoint[0]; targetPoint[1] += stencilWeight * stencilPoint[1]; targetPoint[2] += stencilWeight * stencilPoint[2]; double point[3]; this->Mesh->GetPoint(pointId,point); double relocatedPoint[3]; relocatedPoint[0] = point[0] + this->Relaxation * (targetPoint[0] - point[0]); relocatedPoint[1] = point[1] + this->Relaxation * (targetPoint[1] - point[1]); relocatedPoint[2] = point[2] + this->Relaxation * (targetPoint[2] - point[2]); double projectedRelocatedPoint[3]; vtkIdType cellId; int subId; double dist2; if (this->BoundaryLocator) { this->BoundaryLocator->FindClosestPoint(relocatedPoint,projectedRelocatedPoint,cellId,subId,dist2); } else { // vtkErrorMacro(<<"Something's wrong: point on boundary but no BoundaryLocator is allocated."); projectedRelocatedPoint[0] = relocatedPoint[0]; projectedRelocatedPoint[1] = relocatedPoint[1]; projectedRelocatedPoint[2] = relocatedPoint[2]; // return RELOCATE_FAILURE; } this->Mesh->GetPoints()->SetPoint(pointId,projectedRelocatedPoint); } #ifndef USE_STENCIL neighborIds->Delete(); #else stencil->Delete(); #endif return RELOCATE_SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(vtkIdType pt1, vtkIdType pt2, vtkIdType& cell1, vtkIdType& cell2, vtkIdType& pt3, vtkIdType& pt4) { cell1 = cell2 = -1; pt3 = pt4 = -1; if (!this->Mesh->IsEdge(pt1,pt2)) { return NOT_EDGE; } vtkIdList* cellIds = vtkIdList::New(); this->Mesh->GetCellEdgeNeighbors(-1,pt1,pt2,cellIds); int numberOfCellEdgeNeighbors = cellIds->GetNumberOfIds(); int numberOfNeighborTriangles = 0; for (int i=0; iGetId(i); if (this->Mesh->GetCellType(cellId) == VTK_TRIANGLE) { if (numberOfNeighborTriangles==0) { cell1 = cellId; } else if (numberOfNeighborTriangles==1) { cell2 = cellId; } numberOfNeighborTriangles++; } } cellIds->Delete(); if (numberOfNeighborTriangles == 0) { return NOT_TRIANGLES; } else if (numberOfNeighborTriangles == 1) { vtkIdType npts, *pts; this->Mesh->GetCellPoints(cell1,npts,pts); for (int i=0; i<3; i++) { if ((pts[i]==pt1 && pts[(i+1)%3]==pt2) || (pts[i]==pt2 && pts[(i+1)%3]==pt1)) { pt3 = pts[(i+2)%3]; break; } } return EDGE_ON_BOUNDARY; } else if (numberOfNeighborTriangles > 2) { return NON_MANIFOLD; } vtkIdType pt3tmp = -1; vtkIdType pt4tmp = -1; bool reverse = false; vtkIdType npts, *pts; this->Mesh->GetCellPoints(cell1,npts,pts); for (int i=0; i<3; i++) { if ((pts[i]==pt1 && pts[(i+1)%3]==pt2) || (pts[i]==pt2 && pts[(i+1)%3]==pt1)) { pt3tmp = pts[(i+2)%3]; if (pts[i]==pt2 && pts[(i+1)%3]==pt1) { reverse = true; } break; } } this->Mesh->GetCellPoints(cell2,npts,pts); for (int i=0; i<3; i++) { if ((pts[i]==pt1 && pts[(i+1)%3]==pt2) || (pts[i]==pt2 && pts[(i+1)%3]==pt1)) { pt4tmp = pts[(i+2)%3]; break; } } if (pt3tmp==-1 || pt4tmp==-1) { return DEGENERATE_TRIANGLES; } pt3 = pt3tmp; pt4 = pt4tmp; if (reverse) { vtkIdType tmp; tmp = pt3; pt3 = pt4; pt4 = tmp; tmp = cell1; cell1 = cell2; cell2 = tmp; } if (this->CellEntityIdsArray->GetValue(cell1) != this->CellEntityIdsArray->GetValue(cell2)) { return EDGE_BETWEEN_ENTITIES; } return SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::SplitTriangle(vtkIdType cellId) { if (this->Mesh->GetCellType(cellId) != VTK_TRIANGLE) { return NOT_TRIANGLES; } if (this->IsElementExcluded(cellId)) { return TRIANGLE_LOCKED; } vtkIdType npts, *pts; this->Mesh->GetCellPoints(cellId,npts,pts); vtkIdType pt1 = pts[0]; vtkIdType pt2 = pts[1]; vtkIdType pt3 = pts[2]; vtkIdType cellEntityId = this->CellEntityIdsArray->GetValue(cellId); double point1[3], point2[3], point3[3], newPoint[3]; this->Mesh->GetPoint(pt1,point1); this->Mesh->GetPoint(pt2,point2); this->Mesh->GetPoint(pt3,point3); vtkTriangle::TriangleCenter(point1,point2,point3,newPoint); double projectedNewPoint[3]; vtkIdType closestCellId; int subId; double dist2; this->Locator->FindClosestPoint(newPoint,projectedNewPoint,closestCellId,subId,dist2); vtkIdType newpt = this->Mesh->InsertNextLinkedPoint(projectedNewPoint,1); this->Mesh->ReplaceCellPoint(cellId,pt3,newpt); this->Mesh->RemoveReferenceToCell(pt3,cellId); this->Mesh->AddReferenceToCell(newpt,cellId); vtkIdType tri[3]; tri[0] = pt2; tri[1] = pt3; tri[2] = newpt; vtkIdType cell1 = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell1,cellEntityId); tri[0] = pt3; tri[1] = pt1; tri[2] = newpt; vtkIdType cell2 = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell2,cellEntityId); return SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::CollapseTriangle(vtkIdType cellId) { vtkErrorMacro(<<"CollapseTriangle not yet implemented."); return -1; } int vtkvmtkPolyDataSurfaceRemeshing::SplitEdge(vtkIdType pt1, vtkIdType pt2) { vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); if (this->IsElementExcluded(cell1) || this->IsElementExcluded(cell2)) { return EDGE_LOCKED; } bool proceed = false; if (success == SUCCESS) { proceed = true; } if (!this->PreserveBoundaryEdges && success == EDGE_ON_BOUNDARY) { proceed = true; } if (success == EDGE_BETWEEN_ENTITIES) { proceed = true; } if (!proceed) { return success; } double point1[3], point2[3]; this->Mesh->GetPoint(pt1,point1); this->Mesh->GetPoint(pt2,point2); double newPoint[3]; newPoint[0] = 0.5 * (point1[0] + point2[0]); newPoint[1] = 0.5 * (point1[1] + point2[1]); newPoint[2] = 0.5 * (point1[2] + point2[2]); if (success != EDGE_ON_BOUNDARY) { double projectedNewPoint[3]; vtkIdType cellId; int subId; double dist2; if (success == EDGE_BETWEEN_ENTITIES) { this->EntityBoundaryLocator->FindClosestPoint(newPoint,projectedNewPoint,cellId,subId,dist2); } else { this->Locator->FindClosestPoint(newPoint,projectedNewPoint,cellId,subId,dist2); } vtkIdType newpt = this->Mesh->InsertNextLinkedPoint(projectedNewPoint,2); this->Mesh->ReplaceCellPoint(cell1,pt2,newpt); this->Mesh->ReplaceCellPoint(cell2,pt2,newpt); this->Mesh->RemoveReferenceToCell(pt2,cell1); this->Mesh->RemoveReferenceToCell(pt2,cell2); this->Mesh->AddReferenceToCell(newpt,cell1); this->Mesh->AddReferenceToCell(newpt,cell2); vtkIdType tri[3]; tri[0] = pt3; tri[1] = newpt; tri[2] = pt2; vtkIdType cell3 = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell3,this->CellEntityIdsArray->GetValue(cell1)); tri[0] = pt2; tri[1] = newpt; tri[2] = pt4; vtkIdType cell4 = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell4,this->CellEntityIdsArray->GetValue(cell2)); } else { double projectedNewPoint[3]; vtkIdType cellId; int subId; double dist2; if (this->BoundaryLocator) { this->BoundaryLocator->FindClosestPoint(newPoint,projectedNewPoint,cellId,subId,dist2); } else { vtkErrorMacro(<<"Something's wrong: point on boundary but no BoundaryLocator is allocated."); projectedNewPoint[0] = newPoint[0]; projectedNewPoint[1] = newPoint[1]; projectedNewPoint[2] = newPoint[2]; } vtkIdType newpt = this->Mesh->InsertNextLinkedPoint(projectedNewPoint,2); this->Mesh->ReplaceCellPoint(cell1,pt2,newpt); this->Mesh->RemoveReferenceToCell(pt2,cell1); this->Mesh->AddReferenceToCell(newpt,cell1); vtkIdType tri[3]; tri[0] = pt3; tri[1] = newpt; tri[2] = pt2; vtkIdType cell3 = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell3,this->CellEntityIdsArray->GetValue(cell1)); } return SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::CollapseEdge(vtkIdType pt1, vtkIdType pt2) { vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); if (this->IsElementExcluded(cell1) || this->IsElementExcluded(cell2)) { return EDGE_LOCKED; } bool proceed = false; if (success == SUCCESS) { proceed = true; } if (!this->PreserveBoundaryEdges && success == EDGE_ON_BOUNDARY) { proceed = true; } if (success == EDGE_BETWEEN_ENTITIES) { proceed = true; } if (!proceed) { return success; } if (success != EDGE_ON_BOUNDARY) { bool swappedForBoundary = false; int pt1OnBoundary = this->IsPointOnBoundary(pt1); int pt2OnBoundary = this->IsPointOnBoundary(pt2); if (!pt1OnBoundary && pt2OnBoundary) { vtkIdType tmp = pt1; pt1 = pt2; pt2 = tmp; swappedForBoundary = true; } int pt1OnEntityBoundary = this->IsPointOnEntityBoundary(pt1); int pt2OnEntityBoundary = this->IsPointOnEntityBoundary(pt2); if (!pt1OnEntityBoundary && pt2OnEntityBoundary) { if (swappedForBoundary) { return EDGE_LOCKED; } vtkIdType tmp = pt1; pt1 = pt2; pt2 = tmp; } vtkIdList* pt2Cells = vtkIdList::New(); this->Mesh->GetPointCells(pt2,pt2Cells); vtkIdType npt2Cells = pt2Cells->GetNumberOfIds(); this->Mesh->RemoveReferenceToCell(pt1,cell1); this->Mesh->RemoveReferenceToCell(pt1,cell2); this->Mesh->RemoveReferenceToCell(pt3,cell1); this->Mesh->RemoveReferenceToCell(pt4,cell2); this->Mesh->DeletePoint(pt2); this->Mesh->DeleteCell(cell1); this->CellEntityIdsArray->InsertValue(cell1,-1); this->Mesh->DeleteCell(cell2); this->CellEntityIdsArray->InsertValue(cell2,-1); this->Mesh->ResizeCellList(pt1,npt2Cells-2); for (int i=0; iGetId(i); if (pt2Cell == cell1 || pt2Cell == cell2) { continue; } this->Mesh->AddReferenceToCell(pt1,pt2Cell); this->Mesh->ReplaceCellPoint(pt2Cell,pt2,pt1); } pt2Cells->Delete(); } else { vtkIdList* pt2Cells = vtkIdList::New(); this->Mesh->GetPointCells(pt2,pt2Cells); vtkIdType npt2Cells = pt2Cells->GetNumberOfIds(); this->Mesh->RemoveReferenceToCell(pt1,cell1); this->Mesh->RemoveReferenceToCell(pt3,cell1); this->Mesh->DeletePoint(pt2); this->Mesh->DeleteCell(cell1); this->CellEntityIdsArray->InsertValue(cell1,-1); this->Mesh->ResizeCellList(pt1,npt2Cells-1); for (int i=0; iGetId(i); if (pt2Cell == cell1) { continue; } this->Mesh->AddReferenceToCell(pt1,pt2Cell); this->Mesh->ReplaceCellPoint(pt2Cell,pt2,pt1); } pt2Cells->Delete(); } return SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::FlipEdge(vtkIdType pt1, vtkIdType pt2) { vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); if (this->IsElementExcluded(cell1) || this->IsElementExcluded(cell2)) { return EDGE_LOCKED; } if (success != SUCCESS) { return success; } this->Mesh->RemoveCellReference(cell1); this->Mesh->RemoveCellReference(cell2); this->Mesh->DeleteCell(cell1); vtkIdType cell1EntityId = this->CellEntityIdsArray->GetValue(cell1); this->CellEntityIdsArray->InsertValue(cell1,-1); this->Mesh->DeleteCell(cell2); vtkIdType cell2EntityId = this->CellEntityIdsArray->GetValue(cell2); this->CellEntityIdsArray->InsertValue(cell2,-1); vtkIdType tri[3]; tri[0] = pt3; tri[1] = pt1; tri[2] = pt4; vtkIdType cell1b = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell1b,cell1EntityId); tri[0] = pt2; tri[1] = pt3; tri[2] = pt4; vtkIdType cell2b = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell2b,cell2EntityId); vtkIdType pt3b, pt4b; if (vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt3,pt4,cell1,cell2,pt3b,pt4b) != SUCCESS) { this->Mesh->RemoveCellReference(cell1b); this->Mesh->RemoveCellReference(cell2b); this->Mesh->DeleteCell(cell1b); this->CellEntityIdsArray->InsertValue(cell1b,-1); this->Mesh->DeleteCell(cell2b); this->CellEntityIdsArray->InsertValue(cell2b,-1); tri[0] = pt1; tri[1] = pt2; tri[2] = pt3; vtkIdType cell1c = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell1c,cell1EntityId); tri[0] = pt1; tri[1] = pt4; tri[2] = pt2; vtkIdType cell2c = this->Mesh->InsertNextLinkedCell(VTK_TRIANGLE,3,tri); this->CellEntityIdsArray->InsertValue(cell2c,cell2EntityId); } return SUCCESS; } int vtkvmtkPolyDataSurfaceRemeshing::TestFlipEdgeValidity(vtkIdType pt1, vtkIdType pt2, vtkIdType cell1, vtkIdType cell2, vtkIdType pt3, vtkIdType pt4) { vtkIdType tri[4][3]; tri[0][0] = pt1; tri[0][1] = pt2; tri[0][2] = pt3; tri[1][0] = pt1; tri[1][1] = pt4; tri[1][2] = pt2; tri[2][0] = pt3; tri[2][1] = pt1; tri[2][2] = pt4; tri[3][0] = pt2; tri[3][1] = pt3; tri[3][2] = pt4; double point1[3], point2[3], point3[3]; double normal1[3], normal2[3], normal3[3], normal4[3]; this->Mesh->GetPoint(tri[0][0],point1); this->Mesh->GetPoint(tri[0][1],point2); this->Mesh->GetPoint(tri[0][2],point3); vtkTriangle::ComputeNormal(point1,point2,point3,normal1); this->Mesh->GetPoint(tri[1][0],point1); this->Mesh->GetPoint(tri[1][1],point2); this->Mesh->GetPoint(tri[1][2],point3); vtkTriangle::ComputeNormal(point1,point2,point3,normal2); this->Mesh->GetPoint(tri[2][0],point1); this->Mesh->GetPoint(tri[2][1],point2); this->Mesh->GetPoint(tri[2][2],point3); vtkTriangle::ComputeNormal(point1,point2,point3,normal3); this->Mesh->GetPoint(tri[3][0],point1); this->Mesh->GetPoint(tri[3][1],point2); this->Mesh->GetPoint(tri[3][2],point3); vtkTriangle::ComputeNormal(point1,point2,point3,normal4); if (vtkMath::Dot(normal3,normal1)<0.0 || vtkMath::Dot(normal4,normal1)<0.0 || vtkMath::Dot(normal3,normal2)<0.0 || vtkMath::Dot(normal4,normal2)<0.0) { return DO_NOTHING; } if (fabs(acos(vtkMath::Dot(normal3,normal4)) - acos(vtkMath::Dot(normal1,normal2))) > this->NormalAngleTolerance) { return DO_NOTHING; } return DO_CHANGE; } int vtkvmtkPolyDataSurfaceRemeshing::TestConnectivityFlipEdge(vtkIdType pt1, vtkIdType pt2) { vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); if (success != SUCCESS) { return DO_NOTHING; } if (this->TestFlipEdgeValidity(pt1,pt2,cell1,cell2,pt3,pt4) == DO_NOTHING) { return DO_NOTHING; } unsigned short ncells1, ncells2, ncells3, ncells4; vtkIdType* cells; this->Mesh->GetPointCells(pt1,ncells1,cells); this->Mesh->GetPointCells(pt2,ncells2,cells); this->Mesh->GetPointCells(pt3,ncells3,cells); this->Mesh->GetPointCells(pt4,ncells4,cells); int targetValence = 6; //TODO: if ncells1 < targetValence and ncells2 < targetValence, then the edge should be collapsed. //TODO: if ncells1 > targetValence and ncells2 > targetValence, then the edge should be split. int currentCost = (ncells1-targetValence)*(ncells1-targetValence) + (ncells2-targetValence)*(ncells2-targetValence) + (ncells3-targetValence)*(ncells3-targetValence) + (ncells4-targetValence)*(ncells4-targetValence); int flippedCost = (ncells1-1-targetValence)*(ncells1-1-targetValence) + (ncells2-1-targetValence)*(ncells2-1-targetValence) + (ncells3+1-targetValence)*(ncells3+1-targetValence) + (ncells4+1-targetValence)*(ncells4+1-targetValence); if (flippedCost >= currentCost) { return DO_NOTHING; } return DO_CHANGE; } int vtkvmtkPolyDataSurfaceRemeshing::TestDelaunayFlipEdge(vtkIdType pt1, vtkIdType pt2) { vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); if (success != SUCCESS) { return DO_NOTHING; } if (this->TestFlipEdgeValidity(pt1,pt2,cell1,cell2,pt3,pt4) == DO_NOTHING) { return DO_NOTHING; } vtkIdType tri[4][3]; tri[0][0] = pt1; tri[0][1] = pt2; tri[0][2] = pt3; tri[1][0] = pt1; tri[1][1] = pt4; tri[1][2] = pt2; tri[2][0] = pt3; tri[2][1] = pt1; tri[2][2] = pt4; tri[3][0] = pt2; tri[3][1] = pt3; tri[3][2] = pt4; double point1[3], point2[3], point3[3]; double direction1[3], direction2[3]; double maxAngle01 = 0.0; double maxAngle23 = 0.0; for (int n=0; n<4; n++) { for (int i=0; i<3; i++) { this->Mesh->GetPoint(tri[n][i],point1); this->Mesh->GetPoint(tri[n][(i+1)%3],point2); this->Mesh->GetPoint(tri[n][(i+2)%3],point3); direction1[0] = point2[0] - point1[0]; direction1[1] = point2[1] - point1[1]; direction1[2] = point2[2] - point1[2]; vtkMath::Normalize(direction1); direction2[0] = point3[0] - point1[0]; direction2[1] = point3[1] - point1[1]; direction2[2] = point3[2] - point1[2]; vtkMath::Normalize(direction2); double angle = acos(vtkMath::Dot(direction1,direction2)); if ((n==0 || n==1) && (angle > maxAngle01)) { maxAngle01 = angle; } else if ((n==2 || n==3) && (angle > maxAngle23)) { maxAngle23 = angle; } } } if (maxAngle01 < maxAngle23 + this->InternalAngleTolerance) { return DO_NOTHING; } return DO_CHANGE; } double vtkvmtkPolyDataSurfaceRemeshing::ComputeTriangleTargetArea(vtkIdType cellId) { double targetArea = 0.0; if (this->ElementSizeMode == TARGET_AREA) { targetArea = this->TargetArea; } else if (this->ElementSizeMode == TARGET_AREA_ARRAY) { vtkIdType npts, *pts; this->Mesh->GetCellPoints(cellId,npts,pts); double point1[3], point2[3], point3[3]; this->Mesh->GetPoint(pts[0],point1); this->Mesh->GetPoint(pts[1],point2); this->Mesh->GetPoint(pts[2],point3); double center[3]; vtkTriangle::TriangleCenter(point1,point2,point3,center); double projectedCenter[3]; vtkIdType centerCellId; int subId; double dist2; this->Locator->FindClosestPoint(center,projectedCenter,centerCellId,subId,dist2); vtkTriangle* centerCell = vtkTriangle::SafeDownCast(vtkPolyData::SafeDownCast(this->Locator->GetDataSet())->GetCell(centerCellId)); double pcoords[3], weights[3]; centerCell->EvaluatePosition(projectedCenter,NULL,subId,pcoords,dist2,weights); for (int i=0; i<3; i++) { targetArea += weights[i] * this->TargetAreaArray->GetTuple1(centerCell->GetPointId(i)); } targetArea *= this->TargetAreaFactor; } else { vtkErrorMacro(<<"ElementSizeMode specified is unknown"); return 0.0; } if (targetArea > this->MaxArea) { targetArea = this->MaxArea; } if (targetArea < this->MinArea) { targetArea = this->MinArea; } return targetArea; } int vtkvmtkPolyDataSurfaceRemeshing::TestAspectRatioCollapseEdge(vtkIdType cellId, vtkIdType& pt1, vtkIdType& pt2) { pt1 = -1; pt2 = -1; vtkIdType npts, *pts; this->Mesh->GetCellPoints(cellId,npts,pts); vtkIdType tri[3]; tri[0] = pts[0]; tri[1] = pts[1]; tri[2] = pts[2]; double point1[3], point2[3], point3[3]; this->Mesh->GetPoint(tri[0],point1); this->Mesh->GetPoint(tri[1],point2); this->Mesh->GetPoint(tri[2],point3); double area = vtkTriangle::TriangleArea(point1,point2,point3); double targetArea = this->ComputeTriangleTargetArea(cellId); if (area > targetArea) { return DO_NOTHING; } double side1Squared = vtkMath::Distance2BetweenPoints(point1,point2); double side2Squared = vtkMath::Distance2BetweenPoints(point2,point3); double side3Squared = vtkMath::Distance2BetweenPoints(point3,point1); double frobeniusAspectRatio = (side1Squared + side2Squared + side3Squared) / (4.0 * sqrt(3.0) * area); if (frobeniusAspectRatio < this->AspectRatioThreshold && area > targetArea * this->MinAreaFactor) { return DO_NOTHING; } if (side1Squared < side2Squared && side1Squared < side3Squared) { pt1 = tri[0]; pt2 = tri[1]; } else if (side2Squared < side1Squared && side2Squared < side3Squared) { pt1 = tri[1]; pt2 = tri[2]; } else { pt1 = tri[2]; pt2 = tri[0]; } vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); if (pt3 == pt4) { return DO_NOTHING; } bool proceed = false; if (success == SUCCESS) { proceed = true; } if (!this->PreserveBoundaryEdges && success == EDGE_ON_BOUNDARY) { proceed = true; } if (success == EDGE_BETWEEN_ENTITIES) { proceed = true; } if (!proceed) { return DO_NOTHING; } unsigned short ncells3, ncells4; ncells3 = ncells4 = 0; vtkIdType *cells; this->Mesh->GetPointCells(pt3,ncells3,cells); if (success != EDGE_ON_BOUNDARY) { this->Mesh->GetPointCells(pt4,ncells4,cells); } if (ncells3==3 || ncells4==3) { return DO_NOTHING; } unsigned short ncells2; this->Mesh->GetPointCells(pt2,ncells2,cells); for (int i=0; iMesh->GetCellPoints(cells[i],npts,pts); double normal1[3], normal2[3]; this->Mesh->GetPoint(pts[0],point1); this->Mesh->GetPoint(pts[1],point2); this->Mesh->GetPoint(pts[2],point3); vtkTriangle::ComputeNormal(point1,point2,point3,normal1); for (int j=0; j<3; j++) { if (pts[j] != pt2) { tri[j] = pts[j]; } else { tri[j] = pt1; } } this->Mesh->GetPoint(tri[0],point1); this->Mesh->GetPoint(tri[1],point2); this->Mesh->GetPoint(tri[2],point3); vtkTriangle::ComputeNormal(point1,point2,point3,normal2); if (vtkMath::Dot(normal1,normal2) < 0.0) { return DO_NOTHING; } if (acos(vtkMath::Dot(normal1,normal2)) > this->CollapseAngleThreshold) { return DO_NOTHING; } } return DO_CHANGE; } int vtkvmtkPolyDataSurfaceRemeshing::TestAreaSplitEdge(vtkIdType cellId, vtkIdType& pt1, vtkIdType& pt2) { pt1 = -1; pt2 = -1; vtkIdType npts, *pts; this->Mesh->GetCellPoints(cellId,npts,pts); vtkIdType tri[3]; tri[0] = pts[0]; tri[1] = pts[1]; tri[2] = pts[2]; double point1[3], point2[3], point3[3]; this->Mesh->GetPoint(tri[0],point1); this->Mesh->GetPoint(tri[1],point2); this->Mesh->GetPoint(tri[2],point3); double area = vtkTriangle::TriangleArea(point1,point2,point3); double side1Squared = vtkMath::Distance2BetweenPoints(point1,point2); double side2Squared = vtkMath::Distance2BetweenPoints(point2,point3); double side3Squared = vtkMath::Distance2BetweenPoints(point3,point1); double targetArea = this->ComputeTriangleTargetArea(cellId); if (area < targetArea) { return DO_NOTHING; } if (side1Squared >= side2Squared && side1Squared >= side3Squared) { pt1 = tri[0]; pt2 = tri[1]; } else if (side2Squared >= side1Squared && side2Squared >= side3Squared) { pt1 = tri[1]; pt2 = tri[2]; } else if (side3Squared >= side1Squared && side3Squared >= side1Squared) { pt1 = tri[2]; pt2 = tri[0]; } vtkIdType cell1, cell2, pt3, pt4; int success = vtkvmtkPolyDataSurfaceRemeshing::GetEdgeCellsAndOppositeEdge(pt1,pt2,cell1,cell2,pt3,pt4); bool proceed = false; if (success == SUCCESS) { proceed = true; } if (!this->PreserveBoundaryEdges && success == EDGE_ON_BOUNDARY) { proceed = true; } if (success == EDGE_BETWEEN_ENTITIES) { proceed = true; } if (!proceed) { return DO_NOTHING; } return DO_CHANGE; } void vtkvmtkPolyDataSurfaceRemeshing::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkItem.h0000664000175000017500000000272311757446472021427 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkItem.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkItem - .. // .SECTION Description // .. #ifndef __vtkvmtkItem_h #define __vtkvmtkItem_h #include "vtkObject.h" #include "vtkDataSet.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkItem : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkItem,vtkObject); virtual vtkIdType GetItemType() = 0; // Description: // Standard DeepCopy method. Since this object contains no reference // to other objects, there is no ShallowCopy. virtual void DeepCopy(vtkvmtkItem *src); protected: vtkvmtkItem() {}; ~vtkvmtkItem() {}; private: vtkvmtkItem(const vtkvmtkItem&); // Not implemented. void operator=(const vtkvmtkItem&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataRigidSurfaceModelling.cxx0000664000175000017500000000315311757446472026742 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataRigidSurfaceModelling.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataRigidSurfaceModelling.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataRigidSurfaceModelling, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataRigidSurfaceModelling); vtkvmtkPolyDataRigidSurfaceModelling::vtkvmtkPolyDataRigidSurfaceModelling() { } vtkvmtkPolyDataRigidSurfaceModelling::~vtkvmtkPolyDataRigidSurfaceModelling() { } int vtkvmtkPolyDataRigidSurfaceModelling::RequestData( vtkInformation *vtkNotUsed(request), vtkInformationVector **inputVector, vtkInformationVector *outputVector) { vtkErrorMacro(<< "vtkvmtkPolyDataRigidSurfaceModelling hasn't been implemented yet."); return 1; } void vtkvmtkPolyDataRigidSurfaceModelling::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataAreaWeightedUmbrellaStencil.cxx0000664000175000017500000000656111757446472030105 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataAreaWeightedUmbrellaStencil.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataAreaWeightedUmbrellaStencil, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkPolyDataAreaWeightedUmbrellaStencil); vtkvmtkPolyDataAreaWeightedUmbrellaStencil::vtkvmtkPolyDataAreaWeightedUmbrellaStencil() { this->UseExtendedNeighborhood = 0; } void vtkvmtkPolyDataAreaWeightedUmbrellaStencil::Build() { this->Superclass::Build(); for (vtkIdType i=0; iNPoints; i++) { this->Weights[i] = 1.0/double(this->NPoints); } vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet); int j; for (j=0; jNPoints; 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; jNPoints; 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; jNPoints; 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; jNPoints; j++) { this->CenterWeight[0] += this->Weights[j]; } this->Area = this->CenterWeight[0]; this->ScaleWithArea(); this->ChangeWeightSign(); } void vtkvmtkPolyDataAreaWeightedUmbrellaStencil::ScaleWithArea() { this->ScaleWithAreaFactor(1.0); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataUmbrellaStencil.h0000664000175000017500000000330311757446472025247 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataUmbrellaStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataUmbrellaStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataUmbrellaStencil_h #define __vtkvmtkPolyDataUmbrellaStencil_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkPolyDataManifoldStencil.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataUmbrellaStencil : public vtkvmtkPolyDataManifoldStencil { public: static vtkvmtkPolyDataUmbrellaStencil *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataUmbrellaStencil,vtkvmtkPolyDataManifoldStencil); virtual vtkIdType GetItemType() {return VTK_VMTK_UMBRELLA_STENCIL;}; void Build(); protected: vtkvmtkPolyDataUmbrellaStencil(); ~vtkvmtkPolyDataUmbrellaStencil() {}; void ScaleWithArea() {}; private: vtkvmtkPolyDataUmbrellaStencil(const vtkvmtkPolyDataUmbrellaStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataUmbrellaStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataStencilFlowFilter.h0000664000175000017500000000564611757446472025575 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataStencilFlowFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataStencilFlowFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataStencilFlowFilter_h #define __vtkvmtkPolyDataStencilFlowFilter_h #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkConstants.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class vtkvmtkStencils; class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataStencilFlowFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataStencilFlowFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataStencilFlowFilter,vtkPolyDataAlgorithm); vtkSetMacro(StencilType,int); vtkGetMacro(StencilType,int); void SetStencilTypeToUmbrellaStencil() {this->SetStencilType(VTK_VMTK_UMBRELLA_STENCIL);}; void SetStencilTypeToAreaWeightedUmbrellaStencil() {this->SetStencilType(VTK_VMTK_AREA_WEIGHTED_UMBRELLA_STENCIL);}; void SetStencilTypeToFELaplaceBeltramiStencil() {this->SetStencilType(VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL);}; void SetStencilTypeToFVFELaplaceBeltramiStencil() {this->SetStencilType(VTK_VMTK_FVFE_LAPLACE_BELTRAMI_STENCIL);}; vtkSetMacro(NumberOfIterations,int); vtkGetMacro(NumberOfIterations,int); vtkSetMacro(RelaxationFactor,double); vtkGetMacro(RelaxationFactor,double); vtkSetMacro(ProcessBoundary,int); vtkGetMacro(ProcessBoundary,int); vtkBooleanMacro(ProcessBoundary,int); vtkSetMacro(ConstrainOnSurface,int); vtkGetMacro(ConstrainOnSurface,int); vtkBooleanMacro(ConstrainOnSurface,int); vtkSetMacro(MaximumDisplacement,double); vtkGetMacro(MaximumDisplacement,double); protected: vtkvmtkPolyDataStencilFlowFilter(); ~vtkvmtkPolyDataStencilFlowFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ReleaseStencils(); int StencilType; vtkvmtkStencils* Stencils; int NumberOfIterations; double RelaxationFactor; double MaximumDisplacement; int ProcessBoundary; int ConstrainOnSurface; private: vtkvmtkPolyDataStencilFlowFilter(const vtkvmtkPolyDataStencilFlowFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataStencilFlowFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter.h0000664000175000017500000000420211757446472031611 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter_h #define __vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter_h #include "vtkPolyDataAlgorithm.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter,vtkPolyDataAlgorithm); vtkSetStringMacro(HarmonicMappingArrayName); vtkGetStringMacro(HarmonicMappingArrayName); vtkSetStringMacro(GroupIdsArrayName); vtkGetStringMacro(GroupIdsArrayName); protected: vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter(); ~vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* HarmonicMappingArrayName; char* GroupIdsArrayName; private: vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter(const vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridVorticityFilter.cxx0000664000175000017500000001476511757446472027515 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridVorticityFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridVorticityFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkUnstructuredGridFEVorticityAssembler.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkOpenNLLinearSystemSolver.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridVorticityFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridVorticityFilter); vtkvmtkUnstructuredGridVorticityFilter::vtkvmtkUnstructuredGridVorticityFilter() { this->VelocityArrayName = NULL; this->VorticityArrayName = NULL; this->HelicityFactorArrayName = NULL; this->ComputeHelicityFactor = 0; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; } vtkvmtkUnstructuredGridVorticityFilter::~vtkvmtkUnstructuredGridVorticityFilter() { if (this->VelocityArrayName) { delete[] this->VelocityArrayName; this->VelocityArrayName = NULL; } if (this->VorticityArrayName) { delete[] this->VorticityArrayName; this->VorticityArrayName = NULL; } if (this->HelicityFactorArrayName) { delete[] this->HelicityFactorArrayName; this->HelicityFactorArrayName = NULL; } } int vtkvmtkUnstructuredGridVorticityFilter::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())); if (!this->VelocityArrayName) { vtkErrorMacro(<<"VelocityArrayName not set."); return 1; } if (!this->VorticityArrayName) { vtkErrorMacro(<<"VorticityArrayName not set."); return 1; } if (this->ComputeHelicityFactor) { if (!this->HelicityFactorArrayName) { vtkErrorMacro(<<"HelicityFactorArrayName not set."); return 1; } } int numberOfInputPoints = input->GetNumberOfPoints(); vtkDataArray* velocityArray = input->GetPointData()->GetArray(this->VelocityArrayName); if (!velocityArray) { vtkErrorMacro("VelocityArray with name specified doesn not exist!"); return 0; } int numberOfInputComponents = velocityArray->GetNumberOfComponents(); if (numberOfInputComponents != 3) { vtkErrorMacro("VelocityArray must have 3 components!"); return 0; } vtkDoubleArray* vorticityArray = vtkDoubleArray::New(); vorticityArray->SetName(this->VorticityArrayName); vorticityArray->SetNumberOfComponents(numberOfInputComponents); vorticityArray->SetNumberOfTuples(numberOfInputPoints); vtkvmtkSparseMatrix* sparseMatrix = vtkvmtkSparseMatrix::New(); vtkvmtkDoubleVector* rhsVector = vtkvmtkDoubleVector::New(); rhsVector->SetNormTypeToLInf(); vtkvmtkDoubleVector* solutionVector = vtkvmtkDoubleVector::New(); solutionVector->SetNormTypeToLInf(); int i; for (i=0; i<3; i++) { vtkvmtkUnstructuredGridFEVorticityAssembler* assembler = vtkvmtkUnstructuredGridFEVorticityAssembler::New(); assembler->SetDataSet(input); assembler->SetVelocityArrayName(this->VelocityArrayName); assembler->SetMatrix(sparseMatrix); assembler->SetRHSVector(rhsVector); assembler->SetSolutionVector(solutionVector); assembler->SetQuadratureOrder(this->QuadratureOrder); assembler->SetDirection(i); assembler->Build(); vtkvmtkLinearSystem* linearSystem = vtkvmtkLinearSystem::New(); linearSystem->SetA(sparseMatrix); linearSystem->SetB(rhsVector); linearSystem->SetX(solutionVector); vtkvmtkOpenNLLinearSystemSolver* solver = vtkvmtkOpenNLLinearSystemSolver::New(); solver->SetLinearSystem(linearSystem); solver->SetConvergenceTolerance(this->ConvergenceTolerance); solver->SetMaximumNumberOfIterations(numberOfInputPoints); solver->SetSolverTypeToCG(); solver->SetPreconditionerTypeToJacobi(); solver->Solve(); // solutionVector->CopyVariableIntoArrayComponent(vorticityArray,0,0); // solutionVector->CopyVariableIntoArrayComponent(vorticityArray,1,1); // solutionVector->CopyVariableIntoArrayComponent(vorticityArray,2,2); solutionVector->CopyIntoArrayComponent(vorticityArray,i); assembler->Delete(); linearSystem->Delete(); solver->Delete(); } sparseMatrix->Delete(); rhsVector->Delete(); solutionVector->Delete(); output->DeepCopy(input); output->GetPointData()->AddArray(vorticityArray); if (this->ComputeHelicityFactor) { vtkDoubleArray* helicityFactorArray = vtkDoubleArray::New(); helicityFactorArray->SetName(this->HelicityFactorArrayName); helicityFactorArray->SetNumberOfTuples(numberOfInputPoints); double velocity[3], vorticity[3], velocityMagnitude, vorticityMagnitude, helicityFactor; int i; for (i=0; iGetTuple(i,velocity); vorticityArray->GetTuple(i,vorticity); velocityMagnitude = vtkMath::Norm(velocity); vorticityMagnitude = vtkMath::Norm(vorticity); helicityFactor = 0.0; if (velocityMagnitude > 0.0 && vorticityMagnitude > 0.0) { helicityFactor = vtkMath::Dot(velocity,vorticity) / (velocityMagnitude * vorticityMagnitude); } helicityFactorArray->SetValue(i,helicityFactor); } output->GetPointData()->AddArray(helicityFactorArray); helicityFactorArray->Delete(); } vorticityArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridNeighborhood.cxx0000664000175000017500000000503611757446472026751 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridNeighborhood.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridNeighborhood.h" #include "vtkObjectFactory.h" #include "vtkIdList.h" #include "vtkCell.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridNeighborhood, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridNeighborhood); void vtkvmtkUnstructuredGridNeighborhood::Build() { vtkIdType i, j; vtkIdType numCellsInStencil; vtkIdList *cellIds, *ptIds, *stencilIds; vtkUnstructuredGrid* ugdata = vtkUnstructuredGrid::SafeDownCast(this->DataSet); if (ugdata==NULL) { vtkErrorMacro(<< "Input data NULL or not poly data"); } vtkIdType pointId = this->DataSetPointId; this->NPoints = 0; cellIds = vtkIdList::New(); ptIds = vtkIdList::New(); stencilIds = vtkIdList::New(); ugdata->GetPointCells (pointId, cellIds); numCellsInStencil = cellIds->GetNumberOfIds(); if (numCellsInStencil < 1) { // vtkWarningMacro("numCellsInStencil < 1: " << numCellsInStencil); cellIds->Delete(); ptIds->Delete(); stencilIds->Delete(); return; } vtkIdType cellPointId; for (i=0; iGetCell(cellIds->GetId(i))->GetCellDimension() != 3) { continue; } ugdata->GetCellPoints(cellIds->GetId(i),ptIds); for (j=0; jGetNumberOfIds(); j++) { cellPointId = ptIds->GetId(j); if (cellPointId != pointId) { stencilIds->InsertUniqueId(cellPointId); } } } 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(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkEmptyNeighborhood.cxx0000664000175000017500000000214611757446472024531 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkEmptyNeighborhood.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkEmptyNeighborhood.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkEmptyNeighborhood, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkEmptyNeighborhood); void vtkvmtkEmptyNeighborhood::Build() { this->NPoints = 0; if (this->PointIds!=NULL) { delete[] this->PointIds; this->PointIds = NULL; } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkItems.cxx0000664000175000017500000000621511757446472022165 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkItems.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkItems, "$Revision: 1.4 $"); 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; iArray[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; iSize; 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; iSize; i++) { newArray[i] = this->Array[i]; } for (i=this->Size; iInstantiateNewItem(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; iGetItem(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; iSize; i++) { this->Array[i] = src->Array[i]; this->Array[i]->Register(this); } this->MaxId = src->MaxId; this->Extend = src->Extend; this->Size = src->Size; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataAreaWeightedUmbrellaStencil.h0000664000175000017500000000362411757446472027527 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataAreaWeightedUmbrellaStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataAreaWeightedUmbrellaStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataAreaWeightedUmbrellaStencil_h #define __vtkvmtkPolyDataAreaWeightedUmbrellaStencil_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkPolyDataManifoldStencil.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataAreaWeightedUmbrellaStencil : public vtkvmtkPolyDataManifoldStencil { public: static vtkvmtkPolyDataAreaWeightedUmbrellaStencil *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataAreaWeightedUmbrellaStencil,vtkvmtkPolyDataManifoldStencil); virtual vtkIdType GetItemType() {return VTK_VMTK_AREA_WEIGHTED_UMBRELLA_STENCIL;}; void Build(); protected: vtkvmtkPolyDataAreaWeightedUmbrellaStencil(); ~vtkvmtkPolyDataAreaWeightedUmbrellaStencil() {}; void ScaleWithArea(); private: vtkvmtkPolyDataAreaWeightedUmbrellaStencil(const vtkvmtkPolyDataAreaWeightedUmbrellaStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataAreaWeightedUmbrellaStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataStencilFlowFilter.cxx0000664000175000017500000001347111757446472026143 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataStencilFlowFilter.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.1 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataStencilFlowFilter.h" #include "vtkvmtkStencils.h" #include "vtkvmtkStencil.h" #include "vtkIdList.h" #include "vtkCell.h" #include "vtkCellLocator.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkFieldData.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataStencilFlowFilter, "$Revision: 1.1 $"); vtkStandardNewMacro(vtkvmtkPolyDataStencilFlowFilter); vtkvmtkPolyDataStencilFlowFilter::vtkvmtkPolyDataStencilFlowFilter() { this->StencilType = VTK_VMTK_UMBRELLA_STENCIL; this->Stencils = NULL; this->NumberOfIterations = 100; this->RelaxationFactor = 0.1; this->MaximumDisplacement = VTK_VMTK_LARGE_DOUBLE; this->ProcessBoundary = 0; this->ConstrainOnSurface = 0; } vtkvmtkPolyDataStencilFlowFilter::~vtkvmtkPolyDataStencilFlowFilter() { this->ReleaseStencils(); } void vtkvmtkPolyDataStencilFlowFilter::ReleaseStencils() { if (this->Stencils) { this->Stencils->UnRegister(this); this->Stencils = NULL; } } int vtkvmtkPolyDataStencilFlowFilter::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())); output->CopyStructure(input); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); output->GetFieldData()->PassData(input->GetFieldData()); if (this->Stencils) { this->ReleaseStencils(); } this->Stencils = vtkvmtkStencils::New(); this->Stencils->SetItemType(this->StencilType); this->Stencils->SetDataSet(input); this->Stencils->ReallocateOnBuildOff(); this->Stencils->WeightScalingOn(); vtkCellLocator *cellLocator = NULL; double* weights = NULL; if (this->ConstrainOnSurface) { weights = new double[input->GetMaxCellSize()]; cellLocator = vtkCellLocator::New(); cellLocator->SetDataSet(input); cellLocator->BuildLocator(); } vtkIdType numberOfPoints = input->GetNumberOfPoints(); double displacement[3], stencilPoint[3], weight; double point[3], newPoint[3]; vtkIdList* constrainCellIds = vtkIdList::New(); constrainCellIds->SetNumberOfIds(input->GetNumberOfPoints()); for (vtkIdType pointId=0; pointIdSetId(pointId,0); } for (int iteration=0; iterationNumberOfIterations; iteration++) { this->Stencils->Build(); for (vtkIdType pointId=0; pointIdStencils->GetStencil(pointId); if (stencil->GetIsBoundary() && (!this->ProcessBoundary)) { continue; } displacement[0] = displacement[1] = displacement[2] = 0.0; int numberOfStencilPoints = stencil->GetNumberOfPoints(); for (int j=0; jGetPoint(stencil->GetPointId(j),stencilPoint); weight = stencil->GetWeight(j); displacement[0] += weight * stencilPoint[0]; displacement[1] += weight * stencilPoint[1]; displacement[2] += weight * stencilPoint[2]; } weight = stencil->GetCenterWeight(); output->GetPoint(pointId,point); displacement[0] -= weight * point[0]; displacement[1] -= weight * point[1]; displacement[2] -= weight * point[2]; if (vtkMath::Norm(displacement) > this->MaximumDisplacement) { vtkMath::Normalize(displacement); displacement[0] *= this->MaximumDisplacement; displacement[1] *= this->MaximumDisplacement; displacement[2] *= this->MaximumDisplacement; } newPoint[0] = point[0] + this->RelaxationFactor * displacement[0]; newPoint[1] = point[1] + this->RelaxationFactor * displacement[1]; newPoint[2] = point[2] + this->RelaxationFactor * displacement[2]; if (this->ConstrainOnSurface) { double closestPoint[3]; vtkIdType cellId; int subId; double dist2, pcoords[3]; if (input->GetCell(constrainCellIds->GetId(pointId))->EvaluatePosition(newPoint,closestPoint,subId,pcoords,dist2,weights)==0) { cellLocator->FindClosestPoint(newPoint,closestPoint,cellId,subId,dist2); constrainCellIds->SetId(pointId,cellId); } newPoint[0] = closestPoint[0]; newPoint[1] = closestPoint[1]; newPoint[2] = closestPoint[2]; } output->GetPoints()->SetPoint(pointId,newPoint); } } constrainCellIds->Delete(); if (weights) { delete[] weights; weights = NULL; } if (cellLocator) { cellLocator->Delete(); cellLocator = NULL; } return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkEmptyStencil.h0000664000175000017500000000312311757446472023144 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkEmptyStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkEmptyStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkEmptyStencil_h #define __vtkvmtkEmptyStencil_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkStencil.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkEmptyStencil : public vtkvmtkStencil { public: static vtkvmtkEmptyStencil* New(); vtkTypeRevisionMacro(vtkvmtkEmptyStencil,vtkvmtkStencil); // Description: // Build the stencil. void Build(); virtual vtkIdType GetItemType() {return VTK_VMTK_EMPTY_STENCIL;}; protected: vtkvmtkEmptyStencil() {}; ~vtkvmtkEmptyStencil() {}; private: vtkvmtkEmptyStencil(const vtkvmtkEmptyStencil&); // Not implemented. void operator=(const vtkvmtkEmptyStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataDiscreteElasticaFilter.h0000664000175000017500000000336411757446472026547 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDiscreteElasticaFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataDiscreteElasticaFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataDiscreteElasticaFilter_h #define __vtkvmtkPolyDataDiscreteElasticaFilter_h #include "vtkObject.h" #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataDiscreteElasticaFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataDiscreteElasticaFilter *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataDiscreteElasticaFilter,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); protected: vtkvmtkPolyDataDiscreteElasticaFilter(); ~vtkvmtkPolyDataDiscreteElasticaFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); private: vtkvmtkPolyDataDiscreteElasticaFilter(const vtkvmtkPolyDataDiscreteElasticaFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataDiscreteElasticaFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDoubleVector.h0000664000175000017500000000574611757446472023136 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDoubleVector.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkDoubleVector - .. // .SECTION Description // .. #ifndef __vtkvmtkDoubleVector_h #define __vtkvmtkDoubleVector_h #include "vtkObject.h" #include "vtkDataArray.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" #define VTK_VMTK_L2_NORM 0 #define VTK_VMTK_LINF_NORM 1 class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkDoubleVector : public vtkObject { public: static vtkvmtkDoubleVector* New(); vtkTypeRevisionMacro(vtkvmtkDoubleVector,vtkObject); vtkSetMacro(NormType,int); vtkGetMacro(NormType,int); void SetNormTypeToL2() {this->SetNormType(VTK_VMTK_L2_NORM);}; void SetNormTypeToLInf() {this->SetNormType(VTK_VMTK_LINF_NORM);}; vtkGetMacro(NumberOfElements,vtkIdType); vtkGetMacro(NumberOfElementsPerVariable,vtkIdType); vtkGetMacro(NumberOfVariables,vtkIdType); void Allocate(vtkIdType numberOfElementsPerVariable, vtkIdType numberOfVariables=1); void Fill(double value); void Assign(vtkvmtkDoubleVector *src); void Assign(vtkIdType numberOfElements, const double *array); double GetElement(vtkIdType i) {return this->Array[i];}; void SetElement(vtkIdType i, double value) {this->Array[i] = value;}; void AddElement(vtkIdType i, double value) {this->Array[i] += value;}; //bool GetLocked(vtkIdType i) {return this->Locked[i];} //void SetLocked(vtkIdType i, bool locked) {this->Locked[i] = locked;} //void UnlockAll(); const double* GetArray() {return this->Array;}; void CopyIntoArrayComponent(vtkDataArray *array, int component); void CopyVariableIntoArrayComponent(vtkDataArray *array, int variable, int component); double ComputeNorm(); void Add(vtkvmtkDoubleVector* vectorToAdd); void Subtract(vtkvmtkDoubleVector* vectorToSubtract); void MultiplyBy(double scalar); double Dot(vtkvmtkDoubleVector* vectorToDotWith); void DeepCopy(vtkvmtkDoubleVector *src); protected: vtkvmtkDoubleVector(); ~vtkvmtkDoubleVector(); vtkIdType NumberOfElements; vtkIdType NumberOfElementsPerVariable; vtkIdType NumberOfVariables; int NormType; double* Array; //bool* Locked; private: vtkvmtkDoubleVector(const vtkvmtkDoubleVector&); // Not implemented. void operator=(const vtkvmtkDoubleVector&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkBoundaryConditions.cxx0000664000175000017500000000376211757446472024725 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkBoundaryConditions.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkBoundaryConditions.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkBoundaryConditions, "$Revision: 1.2 $"); vtkvmtkBoundaryConditions::vtkvmtkBoundaryConditions() { this->LinearSystem = NULL; this->BoundaryNodes = NULL; this->BoundaryValues = NULL; } vtkvmtkBoundaryConditions::~vtkvmtkBoundaryConditions() { if (this->LinearSystem) { this->LinearSystem->Delete(); this->LinearSystem = NULL; } if (this->BoundaryNodes) { this->BoundaryNodes->Delete(); this->BoundaryNodes = NULL; } if (this->BoundaryValues) { this->BoundaryValues->Delete(); this->BoundaryValues = NULL; } } void vtkvmtkBoundaryConditions::Apply() { if (this->LinearSystem==NULL) { vtkErrorMacro(<< "Linear system not set!"); return; } if (this->BoundaryNodes==NULL) { vtkErrorMacro(<< "Boundary nodes not set!"); return; } if (this->BoundaryValues==NULL) { vtkErrorMacro(<< "Boundary values not set!"); return; } if (this->BoundaryNodes->GetNumberOfIds() != this->BoundaryValues->GetNumberOfTuples()) { vtkErrorMacro(<< "Boundary nodes list and boundary values array do not have the same size!"); return; } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDataSetItems.cxx0000664000175000017500000000325511757446472023434 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDataSetItems.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkDataSetItems.h" #include "vtkObjectFactory.h" #include "vtkvmtkDataSetItem.h" vtkCxxRevisionMacro(vtkvmtkDataSetItems, "$Revision: 1.3 $"); void vtkvmtkDataSetItems::Build() { vtkIdType numPts; vtkIdType pointId; vtkvmtkDataSetItem *dataSetItem; if (this->DataSet==NULL) { vtkErrorMacro(<<"No DataSet specified."); return; } numPts = this->DataSet->GetNumberOfPoints(); if (!this->Array || (this->Array && this->ReallocateOnBuild)) { this->Allocate(numPts); this->MaxId = numPts - 1; } for (pointId=0; pointIdArray[pointId]); if (dataSetItem==NULL) { vtkErrorMacro(<<"Cannot build non-vtkvmtkDataSetItem item."); return; } dataSetItem->SetDataSet(this->DataSet); dataSetItem->SetDataSetPointId(pointId); dataSetItem->Build(); } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkFEShapeFunctions.h0000664000175000017500000000512411757446472023673 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFEShapeFunctions.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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: vtkTypeRevisionMacro(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 vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataMeanCurvature.cxx0000664000175000017500000001421111757446472025316 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataMeanCurvature.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataMeanCurvature.h" #include "vtkvmtkStencils.h" #include "vtkvmtkStencil.h" #include "vtkDoubleArray.h" #include "vtkPointData.h" #include "vtkCellData.h" #include "vtkvmtkMath.h" #include "vtkvmtkConstants.h" #include "vtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataMeanCurvature, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataMeanCurvature); vtkvmtkPolyDataMeanCurvature::vtkvmtkPolyDataMeanCurvature() { this->StencilType = VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL; this->MeanCurvatureScalarsArrayName = NULL; this->MeanCurvatureNormalsArrayName = NULL; this->ComputeMeanCurvatureScalars = 0; this->ComputeMeanCurvatureNormals = 0; } vtkvmtkPolyDataMeanCurvature::~vtkvmtkPolyDataMeanCurvature() { this->ReleaseStencils(); } void vtkvmtkPolyDataMeanCurvature::ReleaseStencils() { if (this->Stencils) { this->Stencils->UnRegister(this); this->Stencils = NULL; } } void vtkvmtkPolyDataMeanCurvature::ComputePointMeanCurvatureVector(vtkPolyData* input, vtkIdType pointId, double* meanCurvatureVector) { double point[3], stencilPoint[3]; vtkIdType j; vtkvmtkStencil* stencil; meanCurvatureVector[0] = 0.0; meanCurvatureVector[1] = 0.0; meanCurvatureVector[2] = 0.0; input->GetPoint(pointId,point); stencil = this->Stencils->GetStencil(pointId); for (j=0; jGetNumberOfPoints(); j++) { input->GetPoint(stencil->GetPointId(j),stencilPoint); meanCurvatureVector[0] += stencil->GetWeight(j) * stencilPoint[0]; meanCurvatureVector[1] += stencil->GetWeight(j) * stencilPoint[1]; meanCurvatureVector[2] += stencil->GetWeight(j) * stencilPoint[2]; } meanCurvatureVector[0] += stencil->GetCenterWeight() * point[0]; meanCurvatureVector[1] += stencil->GetCenterWeight() * point[1]; meanCurvatureVector[2] += stencil->GetCenterWeight() * point[2]; meanCurvatureVector[0] *= 0.5; meanCurvatureVector[1] *= 0.5; meanCurvatureVector[2] *= 0.5; } int vtkvmtkPolyDataMeanCurvature::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 pointId, numberOfPoints; double meanCurvatureVector[3], meanCurvature; vtkDoubleArray* meanCurvatureScalarsArray = NULL; vtkDoubleArray* meanCurvatureNormalsArray = NULL; if ((this->ComputeMeanCurvatureScalars) && (!this->MeanCurvatureScalarsArrayName)) { vtkErrorMacro(<< "No mean curvature scalars array name specified!"); return 1; } if ((this->ComputeMeanCurvatureNormals) && (!this->MeanCurvatureNormalsArrayName)) { vtkErrorMacro(<< "No mean curvature vectors array name specified!"); return 1; } this->Stencils = vtkvmtkStencils::New(); this->Stencils->SetItemType(this->StencilType); this->Stencils->SetDataSet(input); this->Stencils->Build(); if (this->ComputeMeanCurvatureScalars) { meanCurvatureScalarsArray = vtkDoubleArray::New(); meanCurvatureScalarsArray->SetName(this->MeanCurvatureScalarsArrayName); meanCurvatureScalarsArray->SetNumberOfTuples(input->GetNumberOfPoints()); meanCurvatureScalarsArray->FillComponent(0,0.0); meanCurvatureScalarsArray->Register(this); meanCurvatureScalarsArray->Delete(); } if (this->ComputeMeanCurvatureNormals) { meanCurvatureNormalsArray = vtkDoubleArray::New(); meanCurvatureNormalsArray->SetName(this->MeanCurvatureNormalsArrayName); meanCurvatureNormalsArray->SetNumberOfComponents(3); meanCurvatureNormalsArray->SetNumberOfTuples(input->GetNumberOfPoints()); meanCurvatureNormalsArray->FillComponent(0,0.0); meanCurvatureNormalsArray->FillComponent(1,0.0); meanCurvatureNormalsArray->FillComponent(2,0.0); meanCurvatureNormalsArray->Register(this); meanCurvatureNormalsArray->Delete(); } numberOfPoints = input->GetNumberOfPoints(); for (pointId=0; pointIdComputePointMeanCurvatureVector(input,pointId,meanCurvatureVector); if (this->ComputeMeanCurvatureScalars) { meanCurvature = vtkMath::Norm(meanCurvatureVector); meanCurvatureScalarsArray->SetComponent(pointId,0,meanCurvature); } if (this->ComputeMeanCurvatureNormals) { vtkMath::Normalize(meanCurvatureVector); meanCurvatureNormalsArray->SetTuple(pointId,meanCurvatureVector); } } output->CopyStructure(input); output->GetPointData()->PassData(input->GetPointData()); output->GetCellData()->PassData(input->GetCellData()); if (this->ComputeMeanCurvatureScalars) { output->GetPointData()->AddArray(meanCurvatureScalarsArray); output->GetPointData()->SetActiveScalars(this->MeanCurvatureScalarsArrayName); } if (this->ComputeMeanCurvatureNormals) { output->GetPointData()->AddArray(meanCurvatureNormalsArray); output->GetPointData()->SetActiveNormals(this->MeanCurvatureNormalsArrayName); } return 1; } void vtkvmtkPolyDataMeanCurvature::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataNeighborhood.h0000664000175000017500000000327311757446472024577 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataNeighborhood.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataNeighborhood - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataNeighborhood_h #define __vtkvmtkPolyDataNeighborhood_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkNeighborhood.h" #include "vtkPolyData.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataNeighborhood : public vtkvmtkNeighborhood { public: static vtkvmtkPolyDataNeighborhood *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataNeighborhood,vtkvmtkNeighborhood); virtual vtkIdType GetItemType() {return VTK_VMTK_POLYDATA_NEIGHBORHOOD;}; // Description: // Build the neighborhood. virtual void Build(); protected: vtkvmtkPolyDataNeighborhood() {}; ~vtkvmtkPolyDataNeighborhood() {}; private: vtkvmtkPolyDataNeighborhood(const vtkvmtkPolyDataNeighborhood&); // Not implemented. void operator=(const vtkvmtkPolyDataNeighborhood&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkStencils.cxx0000664000175000017500000000467411757446472022677 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStencils.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkStencils.h" #include "vtkObjectFactory.h" #include "vtkvmtkEmptyStencil.h" #include "vtkvmtkPolyDataUmbrellaStencil.h" #include "vtkvmtkPolyDataAreaWeightedUmbrellaStencil.h" #include "vtkvmtkPolyDataFELaplaceBeltramiStencil.h" #include "vtkvmtkPolyDataFVFELaplaceBeltramiStencil.h" #include "vtkvmtkPolyDataGradientStencil.h" vtkCxxRevisionMacro(vtkvmtkStencils, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkStencils); vtkvmtkStencils::vtkvmtkStencils() { this->WeightScaling = 1; this->NegateWeights = 1; this->ReallocateOnBuild = 0; } vtkvmtkItem* vtkvmtkStencils::InstantiateNewItem(int itemType) { vtkvmtkStencil* newStencil; switch(itemType) { case VTK_VMTK_EMPTY_STENCIL: newStencil = vtkvmtkEmptyStencil::New(); break; case VTK_VMTK_UMBRELLA_STENCIL: newStencil = vtkvmtkPolyDataUmbrellaStencil::New(); break; case VTK_VMTK_AREA_WEIGHTED_UMBRELLA_STENCIL: newStencil = vtkvmtkPolyDataAreaWeightedUmbrellaStencil::New(); break; case VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL: newStencil = vtkvmtkPolyDataFELaplaceBeltramiStencil::New(); break; case VTK_VMTK_FVFE_LAPLACE_BELTRAMI_STENCIL: newStencil = vtkvmtkPolyDataFVFELaplaceBeltramiStencil::New(); break; case VTK_VMTK_GRADIENT_STENCIL: newStencil = vtkvmtkPolyDataGradientStencil::New(); break; default: vtkErrorMacro(<<"Invalid stencil type"); return NULL; } newStencil->SetWeightScaling(this->WeightScaling); newStencil->SetNegateWeights(this->NegateWeights); newStencil->SetReallocateOnBuild(this->ReallocateOnBuild); newStencil->Register(this); newStencil->Delete(); return newStencil; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridFEVorticityAssembler.h0000664000175000017500000000354111757446472030033 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridFEVorticityAssembler.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridFEVorticityAssembler - .. // .SECTION Description // .. #ifndef __vtkvmtkUnstructuredGridFEVorticityAssembler_h #define __vtkvmtkUnstructuredGridFEVorticityAssembler_h #include "vtkvmtkFEAssembler.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridFEVorticityAssembler : public vtkvmtkFEAssembler { public: static vtkvmtkUnstructuredGridFEVorticityAssembler* New(); vtkTypeRevisionMacro(vtkvmtkUnstructuredGridFEVorticityAssembler,vtkvmtkFEAssembler); virtual void Build(); vtkSetStringMacro(VelocityArrayName); vtkGetStringMacro(VelocityArrayName); vtkSetMacro(Direction,int); vtkGetMacro(Direction,int); protected: vtkvmtkUnstructuredGridFEVorticityAssembler(); ~vtkvmtkUnstructuredGridFEVorticityAssembler(); char* VelocityArrayName; int Direction; private: vtkvmtkUnstructuredGridFEVorticityAssembler(const vtkvmtkUnstructuredGridFEVorticityAssembler&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridFEVorticityAssembler&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldExtendedNeighborhood.cxx0000664000175000017500000000727011757446472030306 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataManifoldExtendedNeighborhood.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataManifoldExtendedNeighborhood.h" #include "vtkObjectFactory.h" #include "vtkIdList.h" #include "vtkCell.h" #include "vtkMath.h" vtkCxxRevisionMacro(vtkvmtkPolyDataManifoldExtendedNeighborhood, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataManifoldExtendedNeighborhood); void vtkvmtkPolyDataManifoldExtendedNeighborhood::Build() { vtkIdType i, j, k; vtkIdType p, p1, p2, outerP; vtkIdType pointId; double outerPoint[3], point1[3], point2[3]; double edgeVector[3], outerVector1[3], outerVector2[3]; vtkIdList *cellIds, *ptIds, *extendedStencilIds; vtkCell* cell; vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet); if (pdata==NULL) { vtkErrorMacro(<< "Input data NULL or not poly data"); } pointId = this->DataSetPointId; this->Superclass::Build(); cellIds = vtkIdList::New(); ptIds = vtkIdList::New(); extendedStencilIds = vtkIdList::New(); if (!this->IsBoundary) { if ((this->NPoints==3)||(this->NPoints==4)) { for (i=0; iNPoints; i++) { extendedStencilIds->InsertNextId(this->PointIds[i]); p1 = this->PointIds[i]; p2 = this->PointIds[(i+1)%this->NPoints]; pdata->GetCellEdgeNeighbors (-1, p1, p2, cellIds); if (cellIds->GetNumberOfIds()>1) { outerP = -1; for (j=0; j<2; j++) { cell = pdata->GetCell(cellIds->GetId(j)); for (k=0; k<3; k++) { p = cell->GetPointId(k); if (p!=pointId && p!=p1 && p!=p2) { outerP = p; break; } } if (outerP != -1) { break; } } pdata->GetPoint(p1,point1); pdata->GetPoint(p2,point2); pdata->GetPoint(outerP,outerPoint); edgeVector[0] = point1[0] - point2[0]; edgeVector[1] = point1[1] - point2[1]; edgeVector[2] = point1[2] - point2[2]; outerVector1[0] = outerPoint[0] - point1[0]; outerVector1[1] = outerPoint[1] - point1[1]; outerVector1[2] = outerPoint[2] - point1[2]; outerVector2[0] = outerPoint[0] - point2[0]; outerVector2[1] = outerPoint[1] - point2[1]; outerVector2[2] = outerPoint[2] - point2[2]; if (vtkMath::Dot(edgeVector,outerVector1)*vtkMath::Dot(edgeVector,outerVector2) < 0.0) extendedStencilIds->InsertNextId(outerP); } } this->NPoints = extendedStencilIds->GetNumberOfIds(); if (this->PointIds!=NULL) { delete[] this->PointIds; this->PointIds = NULL; } this->PointIds = new vtkIdType[this->NPoints]; memcpy(this->PointIds,extendedStencilIds->GetPointer(0),this->NPoints*sizeof(vtkIdType)); } } cellIds->Delete(); ptIds->Delete(); extendedStencilIds->Delete(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkStencils.h0000664000175000017500000000546511757446472022323 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStencils.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(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); int WeightScaling; int NegateWeights; private: vtkvmtkStencils(const vtkvmtkStencils&); // Not implemented. void operator=(const vtkvmtkStencils&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridFEVorticityAssembler.cxx0000664000175000017500000001307611757446472030412 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridFEVorticityAssembler.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridFEVorticityAssembler.h" #include "vtkvmtkGaussQuadrature.h" #include "vtkvmtkFEShapeFunctions.h" #include "vtkPointData.h" #include "vtkDataArray.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridFEVorticityAssembler, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridFEVorticityAssembler); vtkvmtkUnstructuredGridFEVorticityAssembler::vtkvmtkUnstructuredGridFEVorticityAssembler() { this->VelocityArrayName = NULL; this->Direction = 0; } vtkvmtkUnstructuredGridFEVorticityAssembler::~vtkvmtkUnstructuredGridFEVorticityAssembler() { if (this->VelocityArrayName) { delete[] this->VelocityArrayName; this->VelocityArrayName = NULL; } } void vtkvmtkUnstructuredGridFEVorticityAssembler::Build() { if (!this->VelocityArrayName) { vtkErrorMacro("VelocityArrayName not specified!"); return; } vtkDataArray* velocityArray = this->DataSet->GetPointData()->GetArray(this->VelocityArrayName); if (!velocityArray) { vtkErrorMacro("VelocityArray with name specified does not exist!"); return; } if (velocityArray->GetNumberOfComponents() != 3) { vtkErrorMacro("VelocityArray must have 3 components!"); return; } // int numberOfVariables = 3; int numberOfVariables = 1; this->Initialize(numberOfVariables); vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New(); gaussQuadrature->SetOrder(this->QuadratureOrder); vtkvmtkFEShapeFunctions* feShapeFunctions = vtkvmtkFEShapeFunctions::New(); int dimension = 3; int numberOfCells = this->DataSet->GetNumberOfCells(); int k; for (k=0; kDataSet->GetCell(k); if (cell->GetCellDimension() != dimension) { continue; } gaussQuadrature->Initialize(cell->GetCellType()); feShapeFunctions->Initialize(cell,gaussQuadrature->GetQuadraturePoints()); int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints(); double quadraturePCoords[3]; int numberOfCellPoints = cell->GetNumberOfPoints(); int i, j; int q; for (q=0; qGetQuadraturePoint(q,quadraturePCoords); double quadratureWeight = gaussQuadrature->GetQuadratureWeight(q); double jacobian = feShapeFunctions->GetJacobian(q); double phii, phij; double dphii[3]; double velocityValue[3]; // double vorticityValue[3]; // vorticityValue[0] = vorticityValue[1] = vorticityValue[2] = 0.0; double vorticityComponent = 0.0; for (i=0; iGetPointId(i); feShapeFunctions->GetDPhi(q,i,dphii); velocityArray->GetTuple(iId,velocityValue); // vorticityValue[0] += velocityValue[2] * dphii[1] - velocityValue[1] * dphii[2]; // vorticityValue[1] += velocityValue[0] * dphii[2] - velocityValue[2] * dphii[0]; // vorticityValue[2] += velocityValue[1] * dphii[0] - velocityValue[0] * dphii[1]; if (this->Direction == 0) { vorticityComponent += velocityValue[2] * dphii[1] - velocityValue[1] * dphii[2]; } else if (this->Direction == 1) { vorticityComponent += velocityValue[0] * dphii[2] - velocityValue[2] * dphii[0]; } else if (this->Direction == 2) { vorticityComponent += velocityValue[1] * dphii[0] - velocityValue[0] * dphii[1]; } } for (i=0; iGetPointId(i); phii = feShapeFunctions->GetPhi(q,i); // double value0 = jacobian * quadratureWeight * vorticityValue[0] * phii; // double value1 = jacobian * quadratureWeight * vorticityValue[1] * phii; // double value2 = jacobian * quadratureWeight * vorticityValue[2] * phii; double value = jacobian * quadratureWeight * vorticityComponent * phii; // this->RHSVector->AddElement(iId,value0); // this->RHSVector->AddElement(iId+numberOfPoints,value1); // this->RHSVector->AddElement(iId+2*numberOfPoints,value2); this->RHSVector->AddElement(iId,value); for (j=0; jGetPointId(j); phij = feShapeFunctions->GetPhi(q,j); double value = jacobian * quadratureWeight * phii * phij; // this->Matrix->AddElement(iId,jId,value); // this->Matrix->AddElement(iId+numberOfPoints,jId+numberOfPoints,value); // this->Matrix->AddElement(iId+2*numberOfPoints,jId+2*numberOfPoints,value); this->Matrix->AddElement(iId,jId,value); } } } } gaussQuadrature->Delete(); feShapeFunctions->Delete(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFELaplaceAssembler.cxx0000664000175000017500000000574111757446472026157 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFELaplaceAssembler.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataFELaplaceAssembler.h" #include "vtkvmtkGaussQuadrature.h" #include "vtkvmtkFEShapeFunctions.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataFELaplaceAssembler, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataFELaplaceAssembler); vtkvmtkPolyDataFELaplaceAssembler::vtkvmtkPolyDataFELaplaceAssembler() { } vtkvmtkPolyDataFELaplaceAssembler::~vtkvmtkPolyDataFELaplaceAssembler() { } void vtkvmtkPolyDataFELaplaceAssembler::Build() { int numberOfVariables = 1; this->Initialize(numberOfVariables); vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New(); gaussQuadrature->SetOrder(this->QuadratureOrder); vtkvmtkFEShapeFunctions* feShapeFunctions = vtkvmtkFEShapeFunctions::New(); int dimension = 2; int numberOfCells = this->DataSet->GetNumberOfCells(); int k; for (k=0; kDataSet->GetCell(k); if (cell->GetCellDimension() != dimension) { continue; } gaussQuadrature->Initialize(cell->GetCellType()); feShapeFunctions->Initialize(cell,gaussQuadrature->GetQuadraturePoints()); int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints(); double quadraturePCoords[3]; int numberOfCellPoints = cell->GetNumberOfPoints(); int i, j; int q; for (q=0; qGetQuadraturePoint(q,quadraturePCoords); double quadratureWeight = gaussQuadrature->GetQuadratureWeight(q); double jacobian = feShapeFunctions->GetJacobian(q); double dphii[3], dphij[3]; for (i=0; iGetPointId(i); feShapeFunctions->GetDPhi(q,i,dphii); for (j=0; jGetPointId(j); feShapeFunctions->GetDPhi(q,j,dphij); double gradphii_gradphij = vtkMath::Dot(dphii,dphij); double value = jacobian * quadratureWeight * gradphii_gradphij; this->Matrix->AddElement(iId,jId,value); } } } } gaussQuadrature->Delete(); feShapeFunctions->Delete(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataGradientStencil.h0000664000175000017500000000341611757446472025246 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataGradientStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataGradientStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataGradientStencil_h #define __vtkvmtkPolyDataGradientStencil_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkPolyDataManifoldStencil.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataGradientStencil : public vtkvmtkPolyDataManifoldStencil { public: static vtkvmtkPolyDataGradientStencil *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataGradientStencil,vtkvmtkPolyDataManifoldStencil); virtual vtkIdType GetItemType() {return VTK_VMTK_GRADIENT_STENCIL;}; void Build(); protected: vtkvmtkPolyDataGradientStencil(); ~vtkvmtkPolyDataGradientStencil() {}; void ScaleWithArea(); void Gamma(double p0[3], double p1[3], double p2[3], double gamma[3]); private: vtkvmtkPolyDataGradientStencil(const vtkvmtkPolyDataGradientStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataGradientStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridFEGradientAssembler.h0000664000175000017500000000455311757446472027600 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridFEGradientAssembler.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridFEGradientAssembler - .. // .SECTION Description // .. #ifndef __vtkvmtkUnstructuredGridFEGradientAssembler_h #define __vtkvmtkUnstructuredGridFEGradientAssembler_h #include "vtkvmtkFEAssembler.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridFEGradientAssembler : public vtkvmtkFEAssembler { public: static vtkvmtkUnstructuredGridFEGradientAssembler* New(); vtkTypeRevisionMacro(vtkvmtkUnstructuredGridFEGradientAssembler,vtkvmtkFEAssembler); virtual void Build(); vtkSetStringMacro(ScalarsArrayName); vtkGetStringMacro(ScalarsArrayName); vtkSetMacro(ScalarsComponent,int); vtkGetMacro(ScalarsComponent,int); vtkSetMacro(Direction,int); vtkGetMacro(Direction,int); vtkSetMacro(AssemblyMode,int); vtkGetMacro(AssemblyMode,int); void SetAssemblyModeToGradient() { this->SetAssemblyMode(VTKVMTK_GRADIENTASSEMBLY); } void SetAssemblyModeToPartialDerivative() { this->SetAssemblyMode(VTKVMTK_PARTIALDERIVATIVEASSEMBLY); } //BTX enum { VTKVMTK_GRADIENTASSEMBLY, VTKVMTK_PARTIALDERIVATIVEASSEMBLY }; //ETX protected: vtkvmtkUnstructuredGridFEGradientAssembler(); ~vtkvmtkUnstructuredGridFEGradientAssembler(); void BuildGradient(); void BuildPartialDerivative(); char* ScalarsArrayName; int ScalarsComponent; int AssemblyMode; int Direction; private: vtkvmtkUnstructuredGridFEGradientAssembler(const vtkvmtkUnstructuredGridFEGradientAssembler&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridFEGradientAssembler&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDirichletBoundaryConditions.h0000664000175000017500000000327011757446472026174 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDirichletBoundaryConditions.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(vtkvmtkDirichletBoundaryConditions,vtkvmtkBoundaryConditions); void Apply(); protected: vtkvmtkDirichletBoundaryConditions() {}; ~vtkvmtkDirichletBoundaryConditions() {}; private: vtkvmtkDirichletBoundaryConditions(const vtkvmtkDirichletBoundaryConditions&); // Not implemented. void operator=(const vtkvmtkDirichletBoundaryConditions&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFELaplaceBeltramiStencil.h0000664000175000017500000000347311757446472026750 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFELaplaceBeltramiStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataFELaplaceBeltramiStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataFELaplaceBeltramiStencil_h #define __vtkvmtkPolyDataFELaplaceBeltramiStencil_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkPolyDataLaplaceBeltramiStencil.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataFELaplaceBeltramiStencil : public vtkvmtkPolyDataLaplaceBeltramiStencil { public: static vtkvmtkPolyDataFELaplaceBeltramiStencil *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataFELaplaceBeltramiStencil,vtkvmtkPolyDataLaplaceBeltramiStencil); virtual vtkIdType GetItemType() {return VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL;}; protected: vtkvmtkPolyDataFELaplaceBeltramiStencil(); ~vtkvmtkPolyDataFELaplaceBeltramiStencil() {}; void ScaleWithArea(); private: vtkvmtkPolyDataFELaplaceBeltramiStencil(const vtkvmtkPolyDataFELaplaceBeltramiStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataFELaplaceBeltramiStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataClampedSmoothingFilter.cxx0000664000175000017500000002022411757446472027141 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataClampedSmoothingFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataClampedSmoothingFilter.h" #include "vtkvmtkPolyDataManifoldNeighborhood.h" #include "vtkCurvatures.h" #include "vtkPolyDataNormals.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataClampedSmoothingFilter, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataClampedSmoothingFilter); vtkvmtkPolyDataClampedSmoothingFilter::vtkvmtkPolyDataClampedSmoothingFilter() { this->SetSmoothingTypeToLaplacian(); this->NumberOfIterations = 100; this->Clamp = 0; this->ClampArrayName = NULL; this->ClampThreshold = 0.0; this->TimeStepFactor = 1E-1; } vtkvmtkPolyDataClampedSmoothingFilter::~vtkvmtkPolyDataClampedSmoothingFilter() { if (this->ClampArrayName) { delete[] this->ClampArrayName; this->ClampArrayName = NULL; } } double vtkvmtkPolyDataClampedSmoothingFilter::ComputeTimeStep(vtkPolyData* surface) { int numberOfCells = surface->GetNumberOfCells(); vtkIdType npts, *pts; double point0[3], point1[3], point2[3]; double minTriangleArea = 1E20; for (int i=0; iGetCellPoints(i,npts,pts); if (npts < 3) { continue; } else if (npts > 3) { vtkErrorMacro(<<"Not triangle"); return 0.0; } surface->GetPoint(pts[0],point0); surface->GetPoint(pts[1],point1); surface->GetPoint(pts[2],point2); double triangleArea = vtkvmtkMath::TriangleArea(point0,point1,point2); if (triangleArea < minTriangleArea) { minTriangleArea = triangleArea; } } return this->TimeStepFactor * minTriangleArea; } void vtkvmtkPolyDataClampedSmoothingFilter::LaplacianIteration(vtkPolyData* surface) { vtkDataArray* clampArray = surface->GetPointData()->GetArray(this->ClampArrayName); vtkvmtkPolyDataManifoldNeighborhood* neighborhood = vtkvmtkPolyDataManifoldNeighborhood::New(); neighborhood->SetDataSet(surface); int numberOfPoints = surface->GetNumberOfPoints(); vtkPoints* newPoints = vtkPoints::New(); newPoints->DeepCopy(surface->GetPoints()); double deltaT = this->ComputeTimeStep(surface); for (int i=0; iGetTuple1(i) > this->ClampThreshold) { continue; } neighborhood->SetDataSetPointId(i); neighborhood->Build(); if (neighborhood->GetIsBoundary()) { continue; } double point[3]; surface->GetPoint(i,point); double neighborPoint[3]; double laplace[3]; laplace[0] = laplace[1] = laplace[2] = 0.0; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); double weight = 1.0 / double(numberOfNeighborhoodPoints); for (int j=0; jGetPoint(neighborhood->GetPointId(j),neighborPoint); laplace[0] += weight * (neighborPoint[0] - point[0]); laplace[1] += weight * (neighborPoint[1] - point[1]); laplace[2] += weight * (neighborPoint[2] - point[2]); } double newPoint[3]; newPoint[0] = point[0]; newPoint[1] = point[1]; newPoint[2] = point[2]; newPoint[0] += deltaT * laplace[0]; newPoint[1] += deltaT * laplace[1]; newPoint[2] += deltaT * laplace[2]; newPoints->SetPoint(i,newPoint); } surface->GetPoints()->DeepCopy(newPoints); neighborhood->Delete(); newPoints->Delete(); } void vtkvmtkPolyDataClampedSmoothingFilter::CurvatureDiffusionIteration(vtkPolyData* surface) { vtkDataArray* clampArray = surface->GetPointData()->GetArray(this->ClampArrayName); vtkPolyDataNormals* normalsFilter = vtkPolyDataNormals::New(); normalsFilter->SetInput(surface); normalsFilter->FlipNormalsOff(); normalsFilter->ConsistencyOn(); normalsFilter->ComputePointNormalsOn(); normalsFilter->ComputeCellNormalsOn(); normalsFilter->Update(); vtkDataArray* normals = normalsFilter->GetOutput()->GetPointData()->GetNormals(); vtkCurvatures* curvaturesFilter = vtkCurvatures::New(); curvaturesFilter->SetInput(surface); // curvaturesFilter->InvertMeanCurvatureOn(); curvaturesFilter->SetCurvatureTypeToMean(); curvaturesFilter->Update(); vtkDataArray* meanCurvatureArray = curvaturesFilter->GetOutput()->GetPointData()->GetScalars(); vtkvmtkPolyDataManifoldNeighborhood* neighborhood = vtkvmtkPolyDataManifoldNeighborhood::New(); neighborhood->SetDataSet(surface); int numberOfPoints = surface->GetNumberOfPoints(); vtkPoints* newPoints = vtkPoints::New(); newPoints->DeepCopy(surface->GetPoints()); double deltaT = this->ComputeTimeStep(surface); for (int i=0; iGetTuple1(i) > this->ClampThreshold) { continue; } neighborhood->SetDataSetPointId(i); neighborhood->Build(); if (neighborhood->GetIsBoundary()) { continue; } double point[3]; surface->GetPoint(i,point); double meanCurvature = meanCurvatureArray->GetTuple1(i); double laplaceH = 0.0; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); double weight = 1.0 / double(numberOfNeighborhoodPoints); for (int j=0; jGetTuple1(neighborhood->GetPointId(j)); laplaceH += weight * (neighborMeanCurvature - meanCurvature); } double normal[3]; normals->GetTuple(i,normal); double newPoint[3]; newPoint[0] = point[0]; newPoint[1] = point[1]; newPoint[2] = point[2]; newPoint[0] += deltaT * laplaceH * normal[0]; newPoint[1] += deltaT * laplaceH * normal[1]; newPoint[2] += deltaT * laplaceH * normal[2]; newPoints->SetPoint(i,newPoint); } surface->GetPoints()->DeepCopy(newPoints); normalsFilter->Delete(); curvaturesFilter->Delete(); neighborhood->Delete(); newPoints->Delete(); } int vtkvmtkPolyDataClampedSmoothingFilter::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())); vtkDataArray* clampArray = NULL; if (this->Clamp) { if (!this->ClampArrayName) { vtkErrorMacro(<<"Clamp is on but ClampArrayName has not been specified"); return 1; } if (this->ClampArrayName) { clampArray = input->GetPointData()->GetArray(this->ClampArrayName); } if (!clampArray) { vtkErrorMacro(<<"ClampArray with name specified does not exist"); return 1; } } vtkPolyData* surface = vtkPolyData::New(); surface->DeepCopy(input); surface->BuildCells(); for (int n=0; nNumberOfIterations; n++) { if (this->SmoothingType == LAPLACIAN) { this->LaplacianIteration(surface); } else if (this->SmoothingType == CURVATURE_DIFFUSION) { this->CurvatureDiffusionIteration(surface); } } output->DeepCopy(surface); surface->Delete(); return 1; } void vtkvmtkPolyDataClampedSmoothingFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataRigidSurfaceModelling.h0000664000175000017500000000335011757446472026366 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataRigidSurfaceModelling.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataRigidSurfaceModelling - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataRigidSurfaceModelling_h #define __vtkvmtkPolyDataRigidSurfaceModelling_h #include "vtkObject.h" #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataRigidSurfaceModelling : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataRigidSurfaceModelling *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataRigidSurfaceModelling,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); protected: vtkvmtkPolyDataRigidSurfaceModelling(); ~vtkvmtkPolyDataRigidSurfaceModelling(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); private: vtkvmtkPolyDataRigidSurfaceModelling(const vtkvmtkPolyDataRigidSurfaceModelling&); // Not implemented. void operator=(const vtkvmtkPolyDataRigidSurfaceModelling&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridFELaplaceAssembler.h0000664000175000017500000000321611757446472027377 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridFELaplaceAssembler.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridFELaplaceAssembler - .. // .SECTION Description // .. #ifndef __vtkvmtkUnstructuredGridFELaplaceAssembler_h #define __vtkvmtkUnstructuredGridFELaplaceAssembler_h #include "vtkvmtkFEAssembler.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridFELaplaceAssembler : public vtkvmtkFEAssembler { public: static vtkvmtkUnstructuredGridFELaplaceAssembler* New(); vtkTypeRevisionMacro(vtkvmtkUnstructuredGridFELaplaceAssembler,vtkvmtkFEAssembler); virtual void Build(); protected: vtkvmtkUnstructuredGridFELaplaceAssembler(); ~vtkvmtkUnstructuredGridFELaplaceAssembler(); private: vtkvmtkUnstructuredGridFELaplaceAssembler(const vtkvmtkUnstructuredGridFELaplaceAssembler&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridFELaplaceAssembler&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkStencil.cxx0000664000175000017500000000762211757446472022510 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStencil.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkStencil, "$Revision: 1.5 $"); 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; jNumberOfComponents*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)NumberOfComponents*this->NPoints; j++) { this->Weights[j] = 0.0; } for (j=0; jNumberOfComponents; j++) { this->CenterWeight[j] = 0.0; } return; } else if (fabs(factor)>VTK_VMTK_LARGE_DOUBLE) { for (j=0; jNumberOfComponents*this->NPoints; j++) { this->Weights[j] = VTK_VMTK_LARGE_DOUBLE; } for (j=0; jNumberOfComponents; j++) { this->CenterWeight[j] = VTK_VMTK_LARGE_DOUBLE; } return; } for (j=0; jNumberOfComponents*this->NPoints; j++) { this->Weights[j] *= factor; if (fabs(this->Weights[j])Weights[j] = 0.0; } } for (j=0; jNumberOfComponents; j++) { this->CenterWeight[j] *= factor; if (fabs(this->CenterWeight[j])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; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataMeanCurvature.h0000664000175000017500000000606211757446472024750 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataMeanCurvature.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataMeanCurvature - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataMeanCurvature_h #define __vtkvmtkPolyDataMeanCurvature_h #include "vtkObject.h" #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkStencils.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataMeanCurvature : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataMeanCurvature *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataMeanCurvature,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); vtkSetMacro(StencilType,int); vtkGetMacro(StencilType,int); void SetStencilTypeToUmbrellaStencil() {this->SetStencilType(VTK_VMTK_UMBRELLA_STENCIL);}; void SetStencilTypeToAreaWeightedUmbrellaStencil() {this->SetStencilType(VTK_VMTK_AREA_WEIGHTED_UMBRELLA_STENCIL);}; void SetStencilTypeToFELaplaceBeltramiStencil() {this->SetStencilType(VTK_VMTK_FE_LAPLACE_BELTRAMI_STENCIL);}; void SetStencilTypeToFVFELaplaceBeltramiStencil() {this->SetStencilType(VTK_VMTK_FVFE_LAPLACE_BELTRAMI_STENCIL);}; vtkSetStringMacro(MeanCurvatureScalarsArrayName); vtkGetStringMacro(MeanCurvatureScalarsArrayName); vtkSetStringMacro(MeanCurvatureNormalsArrayName); vtkGetStringMacro(MeanCurvatureNormalsArrayName); vtkSetMacro(ComputeMeanCurvatureScalars,int); vtkGetMacro(ComputeMeanCurvatureScalars,int); vtkBooleanMacro(ComputeMeanCurvatureScalars,int); vtkSetMacro(ComputeMeanCurvatureNormals,int); vtkGetMacro(ComputeMeanCurvatureNormals,int); vtkBooleanMacro(ComputeMeanCurvatureNormals,int); protected: vtkvmtkPolyDataMeanCurvature(); ~vtkvmtkPolyDataMeanCurvature(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void ComputePointMeanCurvatureVector(vtkPolyData* input, vtkIdType pointId, double* meanCurvatureVector); void ReleaseStencils(); char* MeanCurvatureScalarsArrayName; char* MeanCurvatureNormalsArrayName; int StencilType; vtkvmtkStencils* Stencils; int ComputeMeanCurvatureScalars; int ComputeMeanCurvatureNormals; private: vtkvmtkPolyDataMeanCurvature(const vtkvmtkPolyDataMeanCurvature&); // Not implemented. void operator=(const vtkvmtkPolyDataMeanCurvature&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/CMakeLists.txt0000664000175000017500000001441111757446472021466 0ustar lucalucaSET (VTK_VMTK_DIFFERENTIALGEOMETRY_SRCS vtkvmtkBoundaryConditions.cxx vtkvmtkDataSetItem.cxx vtkvmtkDataSetItems.cxx vtkvmtkDirichletBoundaryConditions.cxx vtkvmtkDoubleVector.cxx vtkvmtkEllipticProblem.cxx vtkvmtkEmptyNeighborhood.cxx vtkvmtkEmptyStencil.cxx vtkvmtkFEAssembler.cxx vtkvmtkFEShapeFunctions.cxx vtkvmtkGaussQuadrature.cxx vtkvmtkItem.cxx vtkvmtkItems.cxx vtkvmtkLinearSystem.cxx vtkvmtkLinearSystemSolver.cxx vtkvmtkNeighborhood.cxx vtkvmtkNeighborhoods.cxx vtkvmtkOpenNLLinearSystemSolver.cxx vtkvmtkPolyDataAreaWeightedUmbrellaStencil.cxx vtkvmtkPolyDataClampedSmoothingFilter.cxx vtkvmtkPolyDataCylinderHarmonicMappingFilter.cxx vtkvmtkPolyDataDiscreteElasticaFilter.cxx vtkvmtkPolyDataFEGradientAssembler.cxx vtkvmtkPolyDataFELaplaceAssembler.cxx vtkvmtkPolyDataFELaplaceBeltramiStencil.cxx vtkvmtkPolyDataFVFELaplaceBeltramiStencil.cxx vtkvmtkPolyDataGradientFilter.cxx vtkvmtkPolyDataGradientStencil.cxx vtkvmtkPolyDataHarmonicMappingFilter.cxx vtkvmtkPolyDataLaplaceBeltramiStencil.cxx vtkvmtkPolyDataManifoldExtendedNeighborhood.cxx vtkvmtkPolyDataManifoldNeighborhood.cxx vtkvmtkPolyDataManifoldStencil.cxx vtkvmtkPolyDataMeanCurvature.cxx vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter.cxx vtkvmtkPolyDataNeighborhood.cxx vtkvmtkPolyDataRigidSurfaceModelling.cxx vtkvmtkPolyDataStencilFlowFilter.cxx vtkvmtkPolyDataSurfaceRemeshing.cxx vtkvmtkPolyDataUmbrellaStencil.cxx vtkvmtkSparseMatrix.cxx vtkvmtkSparseMatrixRow.cxx vtkvmtkStencil.cxx vtkvmtkStencils.cxx vtkvmtkUnstructuredGridFEGradientAssembler.cxx vtkvmtkUnstructuredGridFELaplaceAssembler.cxx vtkvmtkUnstructuredGridFEVorticityAssembler.cxx vtkvmtkUnstructuredGridGradientFilter.cxx vtkvmtkUnstructuredGridVorticityFilter.cxx vtkvmtkUnstructuredGridHarmonicMappingFilter.cxx vtkvmtkUnstructuredGridNeighborhood.cxx ) SET_SOURCE_FILES_PROPERTIES ( vtkvmtkBoundaryConditions.cxx vtkvmtkDataSetItem.cxx vtkvmtkDataSetItems.cxx vtkvmtkFEAssembler.cxx vtkvmtkItem.cxx vtkvmtkItems.cxx vtkvmtkNeighborhood.cxx vtkvmtkPolyDataLaplaceBeltramiStencil.cxx vtkvmtkPolyDataManifoldStencil.cxx vtkvmtkStencil.cxx ABSTRACT ) INCLUDE_DIRECTORIES(${VTK_VMTK_SOURCE_DIR}/Utilities/OpenNL) SET(VTK_VMTK_DIFFERENTIALGEOMETRY_TARGET_LINK_LIBRARIES vtkvmtkDifferentialGeometry vtkCommon vtkFiltering vtkGraphics vtkvmtkComputationalGeometry nl) ADD_LIBRARY (vtkvmtkDifferentialGeometry ${VTK_VMTK_DIFFERENTIALGEOMETRY_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkDifferentialGeometry PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkDifferentialGeometry ${VTK_VMTK_DIFFERENTIALGEOMETRY_TARGET_LINK_LIBRARIES}) INSTALL(TARGETS vtkvmtkDifferentialGeometry LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) #FILE(GLOB files "${VTK_VMTK_DIFFERENTIALGEOMETRY_SRCS}/*.h") FILE(GLOB files "${VTK_VMTK_SOURCE_DIR}/DifferentialGeometry/*.h") INSTALL(FILES ${files} DESTINATION ${VTK_VMTK_INSTALL_INCLUDE_DIR} COMPONENT Development) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkDifferentialGeometry) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### IF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) VTK_WRAP_PYTHON3(vtkvmtkDifferentialGeometryPython VTK_VMTK_DIFFERENTIALGEOMETRY_PYTHON_SRCS "${VTK_VMTK_DIFFERENTIALGEOMETRY_SRCS}") ADD_LIBRARY(vtkvmtkDifferentialGeometryPythonD ${VTK_VMTK_DIFFERENTIALGEOMETRY_PYTHON_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkDifferentialGeometryPythonD PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) ADD_LIBRARY(vtkvmtkDifferentialGeometryPython MODULE vtkvmtkDifferentialGeometryPythonInit.cxx) TARGET_LINK_LIBRARIES(vtkvmtkDifferentialGeometryPythonD vtkvmtkDifferentialGeometry vtkvmtkComputationalGeometryPythonD vtkCommonPythonD vtkFilteringPythonD vtkGraphicsPythonD) TARGET_LINK_LIBRARIES (vtkvmtkDifferentialGeometryPython vtkvmtkDifferentialGeometryPythonD) IF(WIN32 AND NOT CYGWIN) SET_TARGET_PROPERTIES(vtkvmtkDifferentialGeometryPython PROPERTIES SUFFIX ".pyd") ENDIF(WIN32 AND NOT CYGWIN) INSTALL(TARGETS vtkvmtkDifferentialGeometryPythonD LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) INSTALL(TARGETS vtkvmtkDifferentialGeometryPython LIBRARY DESTINATION ${VTK_VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ) ENDIF (VTK_WRAP_PYTHON AND VTK_VMTK_WRAP_PYTHON) IF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_HINTS ${VTK_VMTK_SOURCE_DIR}/Wrapping/Tcl/hints) VTK_WRAP_TCL3(vtkvmtkDifferentialGeometryTCL VTK_VMTK_DIFFERENTIALGEOMETRY_TCL_SRCS "${VTK_VMTK_DIFFERENTIALGEOMETRY_SRCS}" "") ADD_LIBRARY(vtkvmtkDifferentialGeometryTCL ${VTK_VMTK_DIFFERENTIALGEOMETRY_TCL_SRCS}) IF(VMTK_LIBRARY_PROPERTIES) SET_TARGET_PROPERTIES(vtkvmtkDifferentialGeometryTCL PROPERTIES ${VMTK_LIBRARY_PROPERTIES}) ENDIF(VMTK_LIBRARY_PROPERTIES) TARGET_LINK_LIBRARIES(vtkvmtkDifferentialGeometryTCL vtkvmtkDifferentialGeometry vtkvmtkComputationalGeometryTCL vtkvmtkComputationalGeometry vtkvmtkCommon vtkvmtkCommonTCL vtkCommon vtkCommonTCL vtkFiltering vtkFilteringTCL vtkGraphics vtkGraphicsTCL) INSTALL(TARGETS vtkvmtkDifferentialGeometryTCL LIBRARY DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries ARCHIVE DESTINATION ${VTK_VMTK_INSTALL_LIB_DIR} COMPONENT Development RUNTIME DESTINATION ${VTK_VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables ) ### START VMTK IN SLICER PATCH ### IF (VTK_VMTK_IN_SLICER) SET(LIBS vtkvmtkDifferentialGeometryTCL) FOREACH(LIB ${LIBS}) slicer3_set_modules_output_path(${LIB}) ENDFOREACH(LIB ${LIBS}) slicer3_install_modules(${LIBS}) ENDIF (VTK_VMTK_IN_SLICER) ### END VMTK IN SLICER PATCH ### ENDIF (VTK_WRAP_TCL AND VTK_VMTK_WRAP_TCL) vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataGradientFilter.h0000664000175000017500000000376211757446472025076 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataGradientFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataGradientFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataGradientFilter_h #define __vtkvmtkPolyDataGradientFilter_h #include "vtkvmtkWin32Header.h" #include "vtkPolyDataAlgorithm.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataGradientFilter : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataGradientFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataGradientFilter,vtkPolyDataAlgorithm); vtkSetStringMacro(InputArrayName); vtkGetStringMacro(InputArrayName); vtkSetStringMacro(GradientArrayName); vtkGetStringMacro(GradientArrayName); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); protected: vtkvmtkPolyDataGradientFilter(); ~vtkvmtkPolyDataGradientFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); char* InputArrayName; char* GradientArrayName; double ConvergenceTolerance; int QuadratureOrder; private: vtkvmtkPolyDataGradientFilter(const vtkvmtkPolyDataGradientFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataGradientFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldNeighborhood.h0000664000175000017500000000353211757446472026247 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataManifoldNeighborhood.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataManifoldNeighborhood - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataManifoldNeighborhood_h #define __vtkvmtkPolyDataManifoldNeighborhood_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkNeighborhood.h" #include "vtkPolyData.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataManifoldNeighborhood : public vtkvmtkNeighborhood { public: static vtkvmtkPolyDataManifoldNeighborhood *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataManifoldNeighborhood,vtkvmtkNeighborhood); virtual vtkIdType GetItemType() {return VTK_VMTK_POLYDATA_MANIFOLD_NEIGHBORHOOD;}; // Description: // Build the neighborhood. virtual void Build(); protected: vtkvmtkPolyDataManifoldNeighborhood() {}; ~vtkvmtkPolyDataManifoldNeighborhood() {}; private: vtkvmtkPolyDataManifoldNeighborhood(const vtkvmtkPolyDataManifoldNeighborhood&); // Not implemented. void operator=(const vtkvmtkPolyDataManifoldNeighborhood&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkFEShapeFunctions.cxx0000664000175000017500000003426411757446472024255 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFEShapeFunctions.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkFEShapeFunctions.h" #include "vtkObjectFactory.h" #include "vtkCellType.h" #include "vtkLine.h" #include "vtkQuadraticEdge.h" #include "vtkQuad.h" #include "vtkQuadraticQuad.h" #include "vtkTriangle.h" #include "vtkQuadraticTriangle.h" #include "vtkHexahedron.h" #include "vtkQuadraticHexahedron.h" #include "vtkWedge.h" #include "vtkQuadraticWedge.h" #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) #include "vtkBiQuadraticQuadraticWedge.h" #endif #include "vtkTetra.h" #include "vtkQuadraticTetra.h" #include "vtkPoints.h" #include "vtkMath.h" //#define VTKVMTKFESHAPEFUNCTIONS_NEGATIVE_JACOBIAN_WARNING vtkStandardNewMacro(vtkvmtkFEShapeFunctions); vtkCxxRevisionMacro(vtkvmtkFEShapeFunctions, "$Revision: 1.2 $"); vtkvmtkFEShapeFunctions::vtkvmtkFEShapeFunctions() { this->Phi = vtkDoubleArray::New(); this->DPhi = vtkDoubleArray::New(); this->Jacobians = vtkDoubleArray::New(); this->NumberOfCellPoints = -1; } vtkvmtkFEShapeFunctions::~vtkvmtkFEShapeFunctions() { this->Phi->Delete(); this->DPhi->Delete(); this->Jacobians->Delete(); } void vtkvmtkFEShapeFunctions::Initialize(vtkCell* cell, vtkDoubleArray* pcoords) { vtkIdType cellDimension = cell->GetCellDimension(); vtkIdType numberOfPCoords = pcoords->GetNumberOfTuples(); vtkIdType numberOfCellPoints = cell->GetNumberOfPoints(); this->NumberOfCellPoints = numberOfCellPoints; this->Phi->Initialize(); this->Phi->SetNumberOfTuples(numberOfCellPoints*numberOfPCoords); this->DPhi->Initialize(); this->DPhi->SetNumberOfComponents(3); this->DPhi->SetNumberOfTuples(numberOfCellPoints*numberOfPCoords); this->Jacobians->Initialize(); this->Jacobians->SetNumberOfTuples(numberOfPCoords); int i; //Phi for (i=0; iGetInterpolationFunctions(cell,pcoords->GetTuple(i),sf); int j; for (j=0; jPhi->SetValue(i*numberOfCellPoints+j,sf[j]); } delete[] sf; //DPhi double* derivs = new double[cellDimension*numberOfCellPoints]; this->GetInterpolationDerivs(cell,pcoords->GetTuple(i),derivs); if (cellDimension == 2) { double inverseJacobianMatrix[2][3]; this->ComputeInverseJacobianMatrix2D(cell,pcoords->GetTuple(i),inverseJacobianMatrix); for (j=0; jDPhi->SetComponent(i*numberOfCellPoints+j,k,dphik); } } } else if (cellDimension == 3) { double inverseJacobianMatrix[3][3]; this->ComputeInverseJacobianMatrix3D(cell,pcoords->GetTuple(i),inverseJacobianMatrix); for (j=0; jDPhi->SetComponent(i*numberOfCellPoints+j,k,dphik); } } } delete[] derivs; //Jacobians double jacobian = this->ComputeJacobian(cell,pcoords->GetTuple(i)); this->Jacobians->SetValue(i,jacobian); } } void vtkvmtkFEShapeFunctions::ComputeInverseJacobianMatrix2D(vtkCell* cell, double* pcoords, double inverseJacobianMatrix[2][3]) { int cellDimension = cell->GetCellDimension(); if (cellDimension != 2) { vtkGenericWarningMacro("Error: ComputeInverseJacobian2D only works for 2D cells."); return; } int numberOfCellPoints = cell->GetNumberOfPoints(); double* derivs = new double[2*numberOfCellPoints]; vtkvmtkFEShapeFunctions::GetInterpolationDerivs(cell,pcoords,derivs); int i, j; double jacobianMatrixTr[2][3]; for (i=0; i<3; i++) { jacobianMatrixTr[0][i] = jacobianMatrixTr[1][i] = 0.0; } double x[3]; for (j=0; jGetPoints()->GetPoint(j,x); for (i=0; i<3; i++) { jacobianMatrixTr[0][i] += x[i] * derivs[j]; jacobianMatrixTr[1][i] += x[i] * derivs[numberOfCellPoints+j]; } } delete[] derivs; double jacobianMatrixSquared[2][2]; jacobianMatrixSquared[0][0] = vtkMath::Dot(jacobianMatrixTr[0],jacobianMatrixTr[0]); jacobianMatrixSquared[0][1] = vtkMath::Dot(jacobianMatrixTr[0],jacobianMatrixTr[1]); jacobianMatrixSquared[1][0] = vtkMath::Dot(jacobianMatrixTr[1],jacobianMatrixTr[0]); jacobianMatrixSquared[1][1] = vtkMath::Dot(jacobianMatrixTr[1],jacobianMatrixTr[1]); double jacobianSquared = vtkMath::Determinant2x2(jacobianMatrixSquared[0],jacobianMatrixSquared[1]); if (jacobianSquared < 0.0) { #ifdef VTKVMTKFESHAPEFUNCTIONS_NEGATIVE_JACOBIAN_WARNING vtkGenericWarningMacro("Warning: negative determinant of squared Jacobian, taking absolute value."); #endif jacobianSquared = fabs(jacobianSquared); } double inverseJacobianSquared = 1.0 / jacobianSquared; double inverseJacobianMatrixSquared[2][2]; inverseJacobianMatrixSquared[0][0] = jacobianMatrixSquared[1][1] * inverseJacobianSquared; inverseJacobianMatrixSquared[0][1] = -jacobianMatrixSquared[0][1] * inverseJacobianSquared; inverseJacobianMatrixSquared[1][0] = -jacobianMatrixSquared[1][0] * inverseJacobianSquared; inverseJacobianMatrixSquared[1][1] = jacobianMatrixSquared[0][0] * inverseJacobianSquared; inverseJacobianMatrix[0][0] = inverseJacobianMatrixSquared[0][0] * jacobianMatrixTr[0][0] + inverseJacobianMatrixSquared[0][1] * jacobianMatrixTr[1][0]; inverseJacobianMatrix[0][1] = inverseJacobianMatrixSquared[0][0] * jacobianMatrixTr[0][1] + inverseJacobianMatrixSquared[0][1] * jacobianMatrixTr[1][1]; inverseJacobianMatrix[0][2] = inverseJacobianMatrixSquared[0][0] * jacobianMatrixTr[0][2] + inverseJacobianMatrixSquared[0][1] * jacobianMatrixTr[1][2]; inverseJacobianMatrix[1][0] = inverseJacobianMatrixSquared[1][0] * jacobianMatrixTr[0][0] + inverseJacobianMatrixSquared[1][1] * jacobianMatrixTr[1][0]; inverseJacobianMatrix[1][1] = inverseJacobianMatrixSquared[1][0] * jacobianMatrixTr[0][1] + inverseJacobianMatrixSquared[1][1] * jacobianMatrixTr[1][1]; inverseJacobianMatrix[1][2] = inverseJacobianMatrixSquared[1][0] * jacobianMatrixTr[0][2] + inverseJacobianMatrixSquared[1][1] * jacobianMatrixTr[1][2]; } void vtkvmtkFEShapeFunctions::ComputeInverseJacobianMatrix3D(vtkCell* cell, double* pcoords, double inverseJacobianMatrix[3][3]) { int cellDimension = cell->GetCellDimension(); if (cellDimension != 3) { vtkGenericWarningMacro("Error: ComputeInverseJacobian3D only works for 3D cells."); return; } 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; jGetPoints()->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; vtkMath::Invert3x3(jacobianMatrix,inverseJacobianMatrix); vtkMath::Transpose3x3(inverseJacobianMatrix,inverseJacobianMatrix); } void vtkvmtkFEShapeFunctions::GetInterpolationFunctions(vtkCell* cell, double* pcoords, double* sf) { switch (cell->GetCellType()) { case VTK_QUAD: vtkQuad::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_QUADRATIC_QUAD: vtkQuadraticQuad::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_TRIANGLE: vtkTriangle::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_QUADRATIC_TRIANGLE: vtkQuadraticTriangle::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_HEXAHEDRON: vtkHexahedron::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_QUADRATIC_HEXAHEDRON: vtkQuadraticHexahedron::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_WEDGE: vtkWedge::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_QUADRATIC_WEDGE: vtkQuadraticWedge::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: vtkBiQuadraticQuadraticWedge::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; #endif case VTK_TETRA: vtkTetra::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; case VTK_QUADRATIC_TETRA: vtkQuadraticTetra::SafeDownCast(cell)->InterpolationFunctions(pcoords,sf); break; default: vtkGenericWarningMacro("Error: unsupported cell type."); return; } } void vtkvmtkFEShapeFunctions::GetInterpolationDerivs(vtkCell* cell, double* pcoords, double* derivs) { switch (cell->GetCellType()) { case VTK_QUAD: vtkQuad::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_QUADRATIC_QUAD: vtkQuadraticQuad::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_TRIANGLE: vtkTriangle::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_QUADRATIC_TRIANGLE: vtkQuadraticTriangle::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_HEXAHEDRON: vtkHexahedron::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_QUADRATIC_HEXAHEDRON: vtkQuadraticHexahedron::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_WEDGE: vtkWedge::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; case VTK_QUADRATIC_WEDGE: vtkQuadraticWedge::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: vtkBiQuadraticQuadraticWedge::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; #endif case VTK_TETRA: #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) vtkTetra::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); #else vtkTetra::SafeDownCast(cell)->InterpolationDerivs(derivs); #endif break; case VTK_QUADRATIC_TETRA: vtkQuadraticTetra::SafeDownCast(cell)->InterpolationDerivs(pcoords,derivs); break; default: vtkGenericWarningMacro("Error: unsupported cell type."); return; } } double vtkvmtkFEShapeFunctions::ComputeJacobian(vtkCell* cell, double* pcoords) { double jacobian = 0.0; int cellDimension = cell->GetCellDimension(); if (cellDimension == 2) { int numberOfCellPoints = cell->GetNumberOfPoints(); double* derivs = new double[2*numberOfCellPoints]; vtkvmtkFEShapeFunctions::GetInterpolationDerivs(cell,pcoords,derivs); int i, j; double jacobianMatrixTr[2][3]; for (i=0; i<3; i++) { jacobianMatrixTr[0][i] = jacobianMatrixTr[1][i] = 0.0; } double x[3]; for (j=0; jGetPoints()->GetPoint(j,x); for (i=0; i<3; i++) { jacobianMatrixTr[0][i] += x[i] * derivs[j]; jacobianMatrixTr[1][i] += x[i] * derivs[numberOfCellPoints+j]; } } delete[] derivs; double jacobianMatrixSquared[2][2]; jacobianMatrixSquared[0][0] = vtkMath::Dot(jacobianMatrixTr[0],jacobianMatrixTr[0]); jacobianMatrixSquared[0][1] = vtkMath::Dot(jacobianMatrixTr[0],jacobianMatrixTr[1]); jacobianMatrixSquared[1][0] = vtkMath::Dot(jacobianMatrixTr[1],jacobianMatrixTr[0]); jacobianMatrixSquared[1][1] = vtkMath::Dot(jacobianMatrixTr[1],jacobianMatrixTr[1]); double jacobianSquared = vtkMath::Determinant2x2(jacobianMatrixSquared[0],jacobianMatrixSquared[1]); if (jacobianSquared < 0.0) { #ifdef VTKVMTKFESHAPEFUNCTIONS_NEGATIVE_JACOBIAN_WARNING vtkGenericWarningMacro("Warning: negative determinant of squared Jacobian, taking absolute value."); #endif jacobianSquared = fabs(jacobianSquared); } jacobian = sqrt(jacobianSquared); } else if (cellDimension == 3) { 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; jGetPoints()->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); if (jacobian < 0.0) { #ifdef VTKVMTKFESHAPEFUNCTIONS_NEGATIVE_JACOBIAN_WARNING vtkGenericWarningMacro("Warning: negative Jacobian, taking absolute value."); #endif jacobian = fabs(jacobian); } } return jacobian; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkItem.cxx0000664000175000017500000000176511757446472022007 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkItem.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkItem.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkItem, "$Revision: 1.2 $"); void vtkvmtkItem::DeepCopy(vtkvmtkItem *src) { if (src==NULL) { vtkErrorMacro(<<"Cannot copy null item"); return; } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkEllipticProblem.h0000664000175000017500000000306011757446472023612 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkEllipticProblem.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkEllipticProblem - .. // .SECTION Description // .. #ifndef __vtkvmtkEllipticProblem_h #define __vtkvmtkEllipticProblem_h #include "vtkObject.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkDirichletBoundaryConditions.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkEllipticProblem : public vtkObject { public: static vtkvmtkEllipticProblem* New(); vtkTypeRevisionMacro(vtkvmtkEllipticProblem,vtkObject); protected: vtkvmtkEllipticProblem(); ~vtkvmtkEllipticProblem(); vtkvmtkLinearSystem* LinearSystem; vtkvmtkDirichletBoundaryConditions* DirichletBoundaryConditions; private: vtkvmtkEllipticProblem(const vtkvmtkEllipticProblem&); // Not implemented. void operator=(const vtkvmtkEllipticProblem&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkSparseMatrix.cxx0000664000175000017500000002067211757446472023531 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSparseMatrix.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSparseMatrix.h" #include "vtkvmtkUnstructuredGridNeighborhood.h" #include "vtkvmtkPolyDataNeighborhood.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkConstants.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSparseMatrix, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkSparseMatrix); vtkvmtkSparseMatrix::vtkvmtkSparseMatrix() { this->NumberOfRows = 0; this->Array = NULL; } vtkvmtkSparseMatrix::~vtkvmtkSparseMatrix() { if (this->Array) { for (int i=0; iNumberOfRows; i++) { this->Array[i]->Delete(); } delete[] this->Array; this->Array = NULL; } } void vtkvmtkSparseMatrix::Initialize() { if (this->Array) { for (int i=0; iNumberOfRows; i++) { this->Array[i]->Delete(); } delete[] this->Array; this->Array = NULL; } this->NumberOfRows = 0; } void vtkvmtkSparseMatrix::SetNumberOfRows(vtkIdType numberOfRows) { //deallocate previous rows, allocate new ones if (this->Array) { for (int i=0; iNumberOfRows; i++) { this->Array[i]->Delete(); } delete[] this->Array; this->Array = NULL; } this->NumberOfRows = numberOfRows; this->Array = new vtkvmtkSparseMatrixRow*[numberOfRows]; for (int i=0; iNumberOfRows; i++) { this->Array[i] = vtkvmtkSparseMatrixRow::New(); } } void vtkvmtkSparseMatrix::CopyRowsFromStencils(vtkvmtkStencils *stencils) { vtkIdType i; vtkIdType numberOfStencils; if (stencils==NULL) { vtkErrorMacro(<<"No stencils provided."); return; } numberOfStencils = stencils->GetNumberOfStencils(); this->Initialize(); this->SetNumberOfRows(numberOfStencils); for (i=0; iGetRow(i)->CopyStencil(stencils->GetStencil(i)); } } void vtkvmtkSparseMatrix::AllocateRowsFromNeighborhoods(vtkvmtkNeighborhoods *neighborhoods, int numberOfVariables) { if (neighborhoods==NULL) { vtkErrorMacro(<<"No neighborhoods provided."); return; } int numberOfNeighborhoods = neighborhoods->GetNumberOfNeighborhoods(); int numberOfRows = numberOfVariables*numberOfNeighborhoods; this->Initialize(); this->SetNumberOfRows(numberOfRows); int i; for (i=0; iGetRow(i); vtkIdType pointId = i % numberOfNeighborhoods; vtkIdType variableId = i / numberOfNeighborhoods; vtkvmtkNeighborhood* neighborhood = neighborhoods->GetNeighborhood(pointId); int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); int numberOfElements = numberOfNeighborhoodPoints + (numberOfVariables-1)*(numberOfNeighborhoodPoints+1); row->SetNumberOfElements(numberOfElements); int index = 0; for (int n=0; nSetElementId(index,neighborhood->GetPointId(j)+n*numberOfNeighborhoods); row->SetElement(index,0.0); index++; } if (n != variableId) { row->SetElementId(index,pointId+n*numberOfNeighborhoods); row->SetElement(index,0.0); index++; } } } } void vtkvmtkSparseMatrix::AllocateRowsFromDataSet(vtkDataSet* dataSet, int numberOfVariables) { if (dataSet==NULL) { vtkErrorMacro(<<"No dataSet provided."); return; } vtkvmtkNeighborhood* neighborhood; if (vtkPolyData::SafeDownCast(dataSet)) { neighborhood = vtkvmtkPolyDataNeighborhood::New(); } else if (vtkUnstructuredGrid::SafeDownCast(dataSet)) { neighborhood = vtkvmtkUnstructuredGridNeighborhood::New(); } else { vtkErrorMacro("DataSet not vtkPolyData or vtkUnstructuredGrid"); return; } neighborhood->SetDataSet(dataSet); int numberOfNeighborhoods = dataSet->GetNumberOfPoints(); int numberOfRows = numberOfVariables*numberOfNeighborhoods; this->Initialize(); this->SetNumberOfRows(numberOfRows); int i; for (i=0; iGetRow(i); vtkIdType pointId = i % numberOfNeighborhoods; vtkIdType variableId = i / numberOfNeighborhoods; neighborhood->SetDataSetPointId(pointId); neighborhood->Build(); int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); int numberOfElements = numberOfNeighborhoodPoints + (numberOfVariables-1)*(numberOfNeighborhoodPoints+1); row->SetNumberOfElements(numberOfElements); int index = 0; for (int n=0; nSetElementId(index,neighborhood->GetPointId(j)+n*numberOfNeighborhoods); row->SetElement(index,0.0); index++; } if (n != variableId) { row->SetElementId(index,pointId+n*numberOfNeighborhoods); row->SetElement(index,0.0); index++; } } } neighborhood->Delete(); } double vtkvmtkSparseMatrix::GetElement(vtkIdType i, vtkIdType j) { vtkvmtkSparseMatrixRow* row = this->GetRow(i); if (i != j) { return row->GetElement(row->GetElementIndex(j)); } else { return row->GetDiagonalElement(); } } void vtkvmtkSparseMatrix::SetElement(vtkIdType i, vtkIdType j, double value) { vtkvmtkSparseMatrixRow* row = this->GetRow(i); if (i != j) { return row->SetElement(row->GetElementIndex(j),value); } else { return row->SetDiagonalElement(value); } } void vtkvmtkSparseMatrix::AddElement(vtkIdType i, vtkIdType j, double value) { double currentValue = this->GetElement(i,j); this->SetElement(i,j,currentValue+value); } void vtkvmtkSparseMatrix::Multiply(vtkvmtkDoubleVector* x, vtkvmtkDoubleVector* y) { vtkIdType i, j, numberOfRows, numberOfRowElements; double yValue, xValue; numberOfRows = this->GetNumberOfRows(); for (i=0; iGetRow(i)->GetNumberOfElements(); for (j=0; jGetElement(this->GetRow(i)->GetElementId(j)); yValue += this->GetRow(i)->GetElement(j) * xValue; } xValue = x->GetElement(i); yValue += this->GetRow(i)->GetDiagonalElement() * xValue; if (fabs(yValue)VTK_VMTK_LARGE_DOUBLE) { yValue = VTK_VMTK_LARGE_DOUBLE; } else if (yValue<-VTK_VMTK_LARGE_DOUBLE) { yValue = -VTK_VMTK_LARGE_DOUBLE; } y->SetElement(i,yValue); } } void vtkvmtkSparseMatrix::TransposeMultiply(vtkvmtkDoubleVector* x, vtkvmtkDoubleVector* y) { vtkIdType i, j, id, numberOfRows, numberOfRowElements; double xValue, yValue; yValue = 0.0; y->Fill(0.0); numberOfRows = this->GetNumberOfRows(); for (i=0; iGetRow(i)->GetNumberOfElements(); xValue = x->GetElement(i); for (j=0; jGetRow(i)->GetElementId(j); yValue = y->GetElement(id); yValue += this->GetRow(i)->GetElement(j) * xValue; y->SetElement(id,yValue); } xValue = x->GetElement(i); yValue += this->GetRow(i)->GetDiagonalElement() * xValue; if (fabs(yValue)VTK_VMTK_LARGE_DOUBLE) { yValue = VTK_VMTK_LARGE_DOUBLE; } else if (yValue<-VTK_VMTK_LARGE_DOUBLE) { yValue = -VTK_VMTK_LARGE_DOUBLE; } y->SetElement(i,yValue); } } void vtkvmtkSparseMatrix::DeepCopy(vtkvmtkSparseMatrix *src) { this->SetNumberOfRows(src->NumberOfRows); for (int i=0; iNumberOfRows; i++) { this->Array[i]->DeepCopy(src->GetRow(i)); } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataHarmonicMappingFilter.cxx0000664000175000017500000001337511757446472026771 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataHarmonicMappingFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataHarmonicMappingFilter.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkStencils.h" #include "vtkvmtkPolyDataFELaplaceAssembler.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkSparseMatrixRow.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkOpenNLLinearSystemSolver.h" #include "vtkvmtkDirichletBoundaryConditions.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataHarmonicMappingFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkPolyDataHarmonicMappingFilter); vtkvmtkPolyDataHarmonicMappingFilter::vtkvmtkPolyDataHarmonicMappingFilter() { this->BoundaryPointIds = NULL; this->BoundaryValues = NULL; this->HarmonicMappingArrayName = NULL; this->ConvergenceTolerance = 1E-6; this->SetAssemblyModeToFiniteElements(); this->QuadratureOrder = 1; } vtkvmtkPolyDataHarmonicMappingFilter::~vtkvmtkPolyDataHarmonicMappingFilter() { if (this->BoundaryPointIds) { this->BoundaryPointIds->Delete(); this->BoundaryPointIds = NULL; } if (this->BoundaryValues) { this->BoundaryValues->Delete(); this->BoundaryValues = NULL; } if (this->HarmonicMappingArrayName) { delete[] this->HarmonicMappingArrayName; this->HarmonicMappingArrayName = NULL; } } int vtkvmtkPolyDataHarmonicMappingFilter::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->BoundaryPointIds) { vtkErrorMacro(<<"BoundaryPointIds not set."); return 1; } if (!this->BoundaryValues) { vtkErrorMacro(<<"BoundaryValues not set."); return 1; } if (!this->HarmonicMappingArrayName) { vtkErrorMacro(<<"HarmonicMappingArrayName not set."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); vtkvmtkSparseMatrix* sparseMatrix = vtkvmtkSparseMatrix::New(); vtkvmtkDoubleVector* rhsVector = vtkvmtkDoubleVector::New(); rhsVector->SetNormTypeToLInf(); vtkvmtkDoubleVector* solutionVector = vtkvmtkDoubleVector::New(); solutionVector->SetNormTypeToLInf(); if (this->AssemblyMode == VTK_VMTK_ASSEMBLY_STENCILS) { vtkvmtkStencils* stencils = vtkvmtkStencils::New(); stencils->SetStencilTypeToFELaplaceBeltramiStencil(); stencils->WeightScalingOff(); stencils->NegateWeightsOn(); stencils->SetDataSet(input); stencils->Build(); sparseMatrix->CopyRowsFromStencils(stencils); rhsVector->Allocate(numberOfInputPoints); rhsVector->Fill(0.0); solutionVector->Allocate(numberOfInputPoints); solutionVector->Fill(0.0); stencils->Delete(); } else if (this->AssemblyMode == VTK_VMTK_ASSEMBLY_FINITEELEMENTS) { vtkvmtkPolyDataFELaplaceAssembler* assembler = vtkvmtkPolyDataFELaplaceAssembler::New(); assembler->SetDataSet(input); assembler->SetMatrix(sparseMatrix); assembler->SetRHSVector(rhsVector); assembler->SetSolutionVector(solutionVector); assembler->SetQuadratureOrder(this->QuadratureOrder); assembler->Build(); assembler->Delete(); } vtkvmtkLinearSystem* linearSystem = vtkvmtkLinearSystem::New(); linearSystem->SetA(sparseMatrix); linearSystem->SetB(rhsVector); linearSystem->SetX(solutionVector); //TODO: deal with NumberOfVariables > 1 vtkvmtkDirichletBoundaryConditions* dirichetBoundaryConditions = vtkvmtkDirichletBoundaryConditions::New(); dirichetBoundaryConditions->SetLinearSystem(linearSystem); dirichetBoundaryConditions->SetBoundaryNodes(this->BoundaryPointIds); dirichetBoundaryConditions->SetBoundaryValues(this->BoundaryValues); dirichetBoundaryConditions->Apply(); vtkvmtkOpenNLLinearSystemSolver* solver = vtkvmtkOpenNLLinearSystemSolver::New(); solver->SetLinearSystem(linearSystem); solver->SetConvergenceTolerance(this->ConvergenceTolerance); solver->SetMaximumNumberOfIterations(numberOfInputPoints); solver->SetSolverTypeToCG(); solver->SetPreconditionerTypeToNone(); solver->Solve(); vtkDoubleArray* harmonicMappingArray = vtkDoubleArray::New(); harmonicMappingArray->SetName(this->HarmonicMappingArrayName); harmonicMappingArray->SetNumberOfComponents(1); harmonicMappingArray->SetNumberOfTuples(numberOfInputPoints); solutionVector->CopyIntoArrayComponent(harmonicMappingArray,0); output->DeepCopy(input); output->GetPointData()->AddArray(harmonicMappingArray); solver->Delete(); harmonicMappingArray->Delete(); sparseMatrix->Delete(); rhsVector->Delete(); solutionVector->Delete(); linearSystem->Delete(); dirichetBoundaryConditions->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkNeighborhoods.h0000664000175000017500000000523611757446472023325 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNeighborhoods.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkNeighborhoods - .. // .SECTION Description // .. #ifndef __vtkvmtkNeighborhoods_h #define __vtkvmtkNeighborhoods_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkDataSetItems.h" #include "vtkvmtkNeighborhood.h" #include "vtkDataSet.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkNeighborhoods : public vtkvmtkDataSetItems { public: static vtkvmtkNeighborhoods* New(); vtkTypeRevisionMacro(vtkvmtkNeighborhoods,vtkvmtkDataSetItems); void SetNieghborhoodTypeToEmptyNeighborhood() {this->SetItemType(VTK_VMTK_EMPTY_NEIGHBORHOOD);}; void SetNeighborhoodTypeToPolyDataNeighborhood() {this->SetItemType(VTK_VMTK_POLYDATA_NEIGHBORHOOD);}; void SetNeighborhoodTypeToPolyDataManifoldNeighborhood() {this->SetItemType(VTK_VMTK_POLYDATA_MANIFOLD_NEIGHBORHOOD);}; void SetNeighborhoodTypeToPolyDataManifoldExtendedNeighborhood() {this->SetItemType(VTK_VMTK_POLYDATA_MANIFOLD_EXTENDED_NEIGHBORHOOD);}; void SetNeighborhoodTypeToUnstructuredGridNeighborhood() {this->SetItemType(VTK_VMTK_UNSTRUCTUREDGRID_NEIGHBORHOOD);}; // Description: // Get a stencil given a point id. vtkvmtkNeighborhood* GetNeighborhood(vtkIdType ptId) {return (vtkvmtkNeighborhood*)this->Array[ptId];}; void SetNumberOfNeighborhoods(vtkIdType numberOfNeighborhoods) { this->SetNumberOfItems(numberOfNeighborhoods);}; vtkIdType GetNumberOfNeighborhoods() {return this->GetNumberOfItems();}; void AllocateNeighborhood(vtkIdType i, vtkIdType neighborhoodType) {this->AllocateItem(i,neighborhoodType);}; protected: vtkvmtkNeighborhoods() {}; ~vtkvmtkNeighborhoods() {}; virtual vtkvmtkItem* InstantiateNewItem(int itemType); private: vtkvmtkNeighborhoods(const vtkvmtkNeighborhoods&); // Not implemented. void operator=(const vtkvmtkNeighborhoods&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridFEGradientAssembler.cxx0000664000175000017500000001710011757446472030143 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridFEGradientAssembler.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridFEGradientAssembler.h" #include "vtkvmtkGaussQuadrature.h" #include "vtkvmtkFEShapeFunctions.h" #include "vtkPointData.h" #include "vtkDataArray.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridFEGradientAssembler, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridFEGradientAssembler); vtkvmtkUnstructuredGridFEGradientAssembler::vtkvmtkUnstructuredGridFEGradientAssembler() { this->ScalarsArrayName = NULL; this->ScalarsComponent = 0; this->AssemblyMode = VTKVMTK_GRADIENTASSEMBLY; this->Direction = 0; } vtkvmtkUnstructuredGridFEGradientAssembler::~vtkvmtkUnstructuredGridFEGradientAssembler() { if (this->ScalarsArrayName) { delete[] this->ScalarsArrayName; this->ScalarsArrayName = NULL; } } void vtkvmtkUnstructuredGridFEGradientAssembler::Build() { switch (this->AssemblyMode) { case VTKVMTK_GRADIENTASSEMBLY: this->BuildGradient(); break; case VTKVMTK_PARTIALDERIVATIVEASSEMBLY: this->BuildPartialDerivative(); break; default: vtkErrorMacro("Unsupported AssemblyMode"); return; } } void vtkvmtkUnstructuredGridFEGradientAssembler::BuildGradient() { if (!this->ScalarsArrayName) { vtkErrorMacro("ScalarsArrayName not specified!"); return; } vtkDataArray* scalarsArray = this->DataSet->GetPointData()->GetArray(this->ScalarsArrayName); if (!scalarsArray) { vtkErrorMacro("ScalarsArray with name specified does not exist!"); return; } int numberOfVariables = 3; this->Initialize(numberOfVariables); vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New(); gaussQuadrature->SetOrder(this->QuadratureOrder); vtkvmtkFEShapeFunctions* feShapeFunctions = vtkvmtkFEShapeFunctions::New(); int dimension = 3; int numberOfCells = this->DataSet->GetNumberOfCells(); int numberOfPoints = this->DataSet->GetNumberOfPoints(); int k; for (k=0; kDataSet->GetCell(k); if (cell->GetCellDimension() != dimension) { continue; } gaussQuadrature->Initialize(cell->GetCellType()); feShapeFunctions->Initialize(cell,gaussQuadrature->GetQuadraturePoints()); int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints(); double quadraturePCoords[3]; int numberOfCellPoints = cell->GetNumberOfPoints(); int i, j; int q; for (q=0; qGetQuadraturePoint(q,quadraturePCoords); double quadratureWeight = gaussQuadrature->GetQuadratureWeight(q); double jacobian = feShapeFunctions->GetJacobian(q); double phii, phij; double dphii[3]; double gradientValue[3]; gradientValue[0] = gradientValue[1] = gradientValue[2] = 0.0; for (i=0; iGetPointId(i); feShapeFunctions->GetDPhi(q,i,dphii); double nodalValue = scalarsArray->GetComponent(iId,this->ScalarsComponent); gradientValue[0] += nodalValue * dphii[0]; gradientValue[1] += nodalValue * dphii[1]; gradientValue[2] += nodalValue * dphii[2]; } for (i=0; iGetPointId(i); phii = feShapeFunctions->GetPhi(q,i); double value0 = jacobian * quadratureWeight * gradientValue[0] * phii; double value1 = jacobian * quadratureWeight * gradientValue[1] * phii; double value2 = jacobian * quadratureWeight * gradientValue[2] * phii; this->RHSVector->AddElement(iId,value0); this->RHSVector->AddElement(iId+numberOfPoints,value1); this->RHSVector->AddElement(iId+2*numberOfPoints,value2); for (j=0; jGetPointId(j); phij = feShapeFunctions->GetPhi(q,j); double value = jacobian * quadratureWeight * phii * phij; this->Matrix->AddElement(iId,jId,value); this->Matrix->AddElement(iId+numberOfPoints,jId+numberOfPoints,value); this->Matrix->AddElement(iId+2*numberOfPoints,jId+2*numberOfPoints,value); } } } } gaussQuadrature->Delete(); feShapeFunctions->Delete(); } void vtkvmtkUnstructuredGridFEGradientAssembler::BuildPartialDerivative() { if (!this->ScalarsArrayName) { vtkErrorMacro("ScalarsArrayName not specified!"); return; } vtkDataArray* scalarsArray = this->DataSet->GetPointData()->GetArray(this->ScalarsArrayName); if (!scalarsArray) { vtkErrorMacro("ScalarsArray with name specified does not exist!"); return; } int numberOfVariables = 1; this->Initialize(numberOfVariables); vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New(); gaussQuadrature->SetOrder(this->QuadratureOrder); vtkvmtkFEShapeFunctions* feShapeFunctions = vtkvmtkFEShapeFunctions::New(); int dimension = 3; int numberOfCells = this->DataSet->GetNumberOfCells(); int k; for (k=0; kDataSet->GetCell(k); if (cell->GetCellDimension() != dimension) { continue; } gaussQuadrature->Initialize(cell->GetCellType()); feShapeFunctions->Initialize(cell,gaussQuadrature->GetQuadraturePoints()); int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints(); double quadraturePCoords[3]; int numberOfCellPoints = cell->GetNumberOfPoints(); int i, j; int q; for (q=0; qGetQuadraturePoint(q,quadraturePCoords); double quadratureWeight = gaussQuadrature->GetQuadratureWeight(q); double jacobian = feShapeFunctions->GetJacobian(q); double phii, phij; double dphii[3]; double partialDerivativeValue = 0.0; for (i=0; iGetPointId(i); feShapeFunctions->GetDPhi(q,i,dphii); double nodalValue = scalarsArray->GetComponent(iId,this->ScalarsComponent); partialDerivativeValue += nodalValue * dphii[this->Direction]; } for (i=0; iGetPointId(i); phii = feShapeFunctions->GetPhi(q,i); double value = jacobian * quadratureWeight * partialDerivativeValue * phii; this->RHSVector->AddElement(iId,value); for (j=0; jGetPointId(j); phij = feShapeFunctions->GetPhi(q,j); double value = jacobian * quadratureWeight * phii * phij; this->Matrix->AddElement(iId,jId,value); } } } } gaussQuadrature->Delete(); feShapeFunctions->Delete(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkStencil.h0000664000175000017500000000575111757446472022136 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkStencil_h #define __vtkvmtkStencil_h #include "vtkObject.h" #include "vtkvmtkNeighborhood.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkStencil : public vtkvmtkNeighborhood { public: vtkTypeRevisionMacro(vtkvmtkStencil,vtkvmtkNeighborhood); vtkSetMacro(NumberOfComponents,vtkIdType); vtkGetMacro(NumberOfComponents,vtkIdType); double GetWeight(vtkIdType i) {return this->Weights[i];}; void SetWeight(vtkIdType i, double weight) {this->Weights[i] = weight;}; double GetWeight(vtkIdType i, vtkIdType component) {return this->Weights[this->NumberOfComponents * i + component];}; void SetWeight(vtkIdType i, vtkIdType component, double weight) {this->Weights[this->NumberOfComponents * i + component] = weight;}; vtkIdType GetNumberOfWeights() {return this->NumberOfComponents * this->NPoints;}; void ScaleWeights(double factor); double GetCenterWeight() {return this->CenterWeight[0];}; void SetCenterWeight(double weight) {this->CenterWeight[0] = weight;}; const double* GetCenterWeightTuple() {return this->CenterWeight;}; double GetCenterWeight(vtkIdType component) {return this->CenterWeight[component];}; void SetCenterWeight(vtkIdType component, double weightComponent) {this->CenterWeight[component] = weightComponent;}; // vtkSetMacro(CenterWeight,double); // vtkGetMacro(CenterWeight,double); // Description: // Build the stencil. virtual void Build() = 0; // Description: // Standard DeepCopy method. virtual void DeepCopy(vtkvmtkItem *src); vtkSetMacro(WeightScaling,int) vtkGetMacro(WeightScaling,int) vtkBooleanMacro(WeightScaling,int) vtkSetMacro(NegateWeights,int) vtkGetMacro(NegateWeights,int) vtkBooleanMacro(NegateWeights,int) protected: vtkvmtkStencil(); ~vtkvmtkStencil(); void ResizePointList(vtkIdType ptId, int size); void ChangeWeightSign(); vtkIdType NumberOfComponents; double* Weights; double* CenterWeight; int WeightScaling; int NegateWeights; private: vtkvmtkStencil(const vtkvmtkStencil&); // Not implemented. void operator=(const vtkvmtkStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataManifoldStencil.cxx0000664000175000017500000000735111757446472025617 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataManifoldStencil.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataManifoldStencil, "$Revision: 1.4 $"); 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; jDataSet->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->AreaArea * 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; iNumberOfComponents*this->NPoints; i++) { this->Weights[i] = 0.0; } this->CenterWeight = new double[this->NumberOfComponents]; for (i=0; iNumberOfComponents; i++) { this->CenterWeight[i] = 0.0; } manifoldNeighborhood->Delete(); } void vtkvmtkPolyDataManifoldStencil::DeepCopy(vtkvmtkPolyDataManifoldStencil *src) { this->Superclass::DeepCopy(src); this->Area = src->Area; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDirichletBoundaryConditions.cxx0000664000175000017500000000535211757446472026552 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDirichletBoundaryConditions.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkDirichletBoundaryConditions.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkDirichletBoundaryConditions.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkDirichletBoundaryConditions, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkDirichletBoundaryConditions); void vtkvmtkDirichletBoundaryConditions::Apply() { vtkIdType i, j, k; vtkIdType systemSize; vtkIdType numberOfRowElements; vtkIdType boundaryNode, numberOfBoundaryNodes; vtkvmtkSparseMatrix* systemMatrix; vtkvmtkDoubleVector* rhsVector; vtkvmtkSparseMatrixRow* row; double boundaryValue; double element; double vectorElement; this->Superclass::Apply(); systemSize = this->LinearSystem->GetX()->GetNumberOfElements(); numberOfBoundaryNodes = this->BoundaryNodes->GetNumberOfIds(); /// FIXME: when boundary conditions apply is called, linear system hasn't checked if matrix and vectors exist systemMatrix = this->LinearSystem->GetA(); rhsVector = this->LinearSystem->GetB(); for (i=0; iBoundaryNodes->GetId(i); boundaryValue = this->BoundaryValues->GetComponent(i,0); for (j=0; jGetRow(j)->Initialize(); systemMatrix->GetRow(j)->SetDiagonalElement(1.0); rhsVector->SetElement(j,boundaryValue); //rhsVector->SetLocked(j,true); } else { row = systemMatrix->GetRow(j); numberOfRowElements = row->GetNumberOfElements(); for (k=0; kGetElementId(k) == boundaryNode) { element = row->GetElement(k); row->SetElement(k,0.0); vectorElement = rhsVector->GetElement(j); vectorElement -= element * boundaryValue; rhsVector->SetElement(j,vectorElement); } } } } } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridNeighborhood.h0000664000175000017500000000345311757446472026377 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridNeighborhood.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkUnstructuredGridNeighborhood - .. // .SECTION Description // .. #ifndef __vtkvmtkUnstructuredGridNeighborhood_h #define __vtkvmtkUnstructuredGridNeighborhood_h #include "vtkObject.h" #include "vtkvmtkConstants.h" #include "vtkvmtkNeighborhood.h" #include "vtkUnstructuredGrid.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkUnstructuredGridNeighborhood : public vtkvmtkNeighborhood { public: static vtkvmtkUnstructuredGridNeighborhood *New(); vtkTypeRevisionMacro(vtkvmtkUnstructuredGridNeighborhood,vtkvmtkNeighborhood); virtual vtkIdType GetItemType() {return VTK_VMTK_UNSTRUCTUREDGRID_NEIGHBORHOOD;}; // Description: // Build the neighborhood. virtual void Build(); protected: vtkvmtkUnstructuredGridNeighborhood() {}; ~vtkvmtkUnstructuredGridNeighborhood() {}; private: vtkvmtkUnstructuredGridNeighborhood(const vtkvmtkUnstructuredGridNeighborhood&); // Not implemented. void operator=(const vtkvmtkUnstructuredGridNeighborhood&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkFEAssembler.cxx0000664000175000017500000000542611757446472023237 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFEAssembler.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkFEAssembler, "$Revision: 1.3 $"); 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; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFEGradientAssembler.cxx0000664000175000017500000001111111757446472026337 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFEGradientAssembler.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataFEGradientAssembler.h" #include "vtkvmtkGaussQuadrature.h" #include "vtkvmtkFEShapeFunctions.h" #include "vtkPointData.h" #include "vtkDataArray.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataFEGradientAssembler, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkPolyDataFEGradientAssembler); vtkvmtkPolyDataFEGradientAssembler::vtkvmtkPolyDataFEGradientAssembler() { this->ScalarsArrayName = NULL; this->ScalarsComponent = 0; } vtkvmtkPolyDataFEGradientAssembler::~vtkvmtkPolyDataFEGradientAssembler() { if (this->ScalarsArrayName) { delete[] this->ScalarsArrayName; this->ScalarsArrayName = NULL; } } void vtkvmtkPolyDataFEGradientAssembler::Build() { if (!this->ScalarsArrayName) { vtkErrorMacro("ScalarsArrayName not specified!"); return; } vtkDataArray* scalarsArray = this->DataSet->GetPointData()->GetArray(this->ScalarsArrayName); if (!scalarsArray) { vtkErrorMacro("ScalarsArray with name specified does not exist!"); return; } int numberOfVariables = 3; this->Initialize(numberOfVariables); vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New(); gaussQuadrature->SetOrder(this->QuadratureOrder); vtkvmtkFEShapeFunctions* feShapeFunctions = vtkvmtkFEShapeFunctions::New(); int dimension = 2; int numberOfCells = this->DataSet->GetNumberOfCells(); int numberOfPoints = this->DataSet->GetNumberOfPoints(); int k; for (k=0; kDataSet->GetCell(k); if (cell->GetCellDimension() != dimension) { continue; } gaussQuadrature->Initialize(cell->GetCellType()); feShapeFunctions->Initialize(cell,gaussQuadrature->GetQuadraturePoints()); int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints(); double quadraturePCoords[3]; int numberOfCellPoints = cell->GetNumberOfPoints(); int i, j; int q; for (q=0; qGetQuadraturePoint(q,quadraturePCoords); double quadratureWeight = gaussQuadrature->GetQuadratureWeight(q); double jacobian = feShapeFunctions->GetJacobian(q); double phii, phij; double dphii[3]; double gradientValue[3]; gradientValue[0] = gradientValue[1] = gradientValue[2] = 0.0; for (i=0; iGetPointId(i); feShapeFunctions->GetDPhi(q,i,dphii); double nodalValue = scalarsArray->GetComponent(iId,this->ScalarsComponent); gradientValue[0] += nodalValue * dphii[0]; gradientValue[1] += nodalValue * dphii[1]; gradientValue[2] += nodalValue * dphii[2]; } for (i=0; iGetPointId(i); phii = feShapeFunctions->GetPhi(q,i); double value0 = jacobian * quadratureWeight * gradientValue[0] * phii; double value1 = jacobian * quadratureWeight * gradientValue[1] * phii; double value2 = jacobian * quadratureWeight * gradientValue[2] * phii; this->RHSVector->AddElement(iId,value0); this->RHSVector->AddElement(iId+numberOfPoints,value1); this->RHSVector->AddElement(iId+2*numberOfPoints,value2); for (j=0; jGetPointId(j); phij = feShapeFunctions->GetPhi(q,j); double value = jacobian * quadratureWeight * phii * phij; this->Matrix->AddElement(iId,jId,value); this->Matrix->AddElement(iId+numberOfPoints,jId+numberOfPoints,value); this->Matrix->AddElement(iId+2*numberOfPoints,jId+2*numberOfPoints,value); } } } } gaussQuadrature->Delete(); feShapeFunctions->Delete(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkLinearSystem.cxx0000664000175000017500000000363711757446472023530 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearSystem.cxx,v $ Language: C++ Date: $Date: 2006/02/23 09:31:41 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkLinearSystem, "$Revision: 1.3 $"); 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; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkEllipticProblem.cxx0000664000175000017500000000205411757446472024167 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkEllipticProblem.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkEllipticProblem.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkEllipticProblem, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkEllipticProblem); vtkvmtkEllipticProblem::vtkvmtkEllipticProblem() { } vtkvmtkEllipticProblem::~vtkvmtkEllipticProblem() { } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataLaplaceBeltramiStencil.h0000664000175000017500000000344711757446472026536 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataLaplaceBeltramiStencil.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataLaplaceBeltramiStencil - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataLaplaceBeltramiStencil_h #define __vtkvmtkPolyDataLaplaceBeltramiStencil_h #include "vtkObject.h" #include "vtkvmtkPolyDataManifoldStencil.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataLaplaceBeltramiStencil : public vtkvmtkPolyDataManifoldStencil { public: vtkTypeRevisionMacro(vtkvmtkPolyDataLaplaceBeltramiStencil,vtkvmtkPolyDataManifoldStencil); void Build(); void BuildBoundaryWeights(vtkIdType boundaryPointId, vtkIdType boundaryNeighborPointId, double &boundaryWeight, double &boundaryNeighborWeight); protected: vtkvmtkPolyDataLaplaceBeltramiStencil(); ~vtkvmtkPolyDataLaplaceBeltramiStencil() {}; private: vtkvmtkPolyDataLaplaceBeltramiStencil(const vtkvmtkPolyDataLaplaceBeltramiStencil&); // Not implemented. void operator=(const vtkvmtkPolyDataLaplaceBeltramiStencil&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFVFELaplaceBeltramiStencil.cxx0000664000175000017500000000452511757446472027556 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFVFELaplaceBeltramiStencil.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataFVFELaplaceBeltramiStencil, "$Revision: 1.4 $"); 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; jGetPoint(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); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDataSetItems.h0000664000175000017500000000353311757446472023060 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDataSetItems.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkDataSetItems - .. // .SECTION Description // .. #ifndef __vtkvmtkDataSetItems_h #define __vtkvmtkDataSetItems_h #include "vtkObject.h" #include "vtkvmtkItems.h" #include "vtkDataSet.h" //#include "vtkvmtkDifferentialGeometryWin32Header.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkDataSetItems : public vtkvmtkItems { public: vtkTypeRevisionMacro(vtkvmtkDataSetItems,vtkvmtkItems); /* vtkSetObjectMacro(DataSet,vtkDataSet); */ /* vtkGetObjectMacro(DataSet,vtkDataSet); */ void SetDataSet(vtkDataSet* dataSet) {this->DataSet = dataSet;}; vtkDataSet* GetDataSet() {return this->DataSet;}; // Description: // Build the item array. void Build(); vtkSetMacro(ReallocateOnBuild,int) vtkGetMacro(ReallocateOnBuild,int) vtkBooleanMacro(ReallocateOnBuild,int) protected: vtkvmtkDataSetItems() {} ~vtkvmtkDataSetItems() {} vtkDataSet *DataSet; int ReallocateOnBuild; private: vtkvmtkDataSetItems(const vtkvmtkDataSetItems&); // Not implemented. void operator=(const vtkvmtkDataSetItems&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataUmbrellaStencil.cxx0000664000175000017500000000252111757446472025623 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataUmbrellaStencil.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataUmbrellaStencil.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataUmbrellaStencil, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkPolyDataUmbrellaStencil); vtkvmtkPolyDataUmbrellaStencil::vtkvmtkPolyDataUmbrellaStencil() { this->UseExtendedNeighborhood = 0; } void vtkvmtkPolyDataUmbrellaStencil::Build() { this->Superclass::Build(); this->Area = 1.0; for (vtkIdType i=0; iNPoints; i++) { this->Weights[i] = 1.0/double(this->NPoints); } this->CenterWeight[0] = 1.0; this->ChangeWeightSign(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkSparseMatrixRow.cxx0000664000175000017500000001043111757446472024211 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSparseMatrixRow.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:30 $ Version: $Revision: 1.2 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkSparseMatrixRow.h" #include "vtkvmtkConstants.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkSparseMatrixRow, "$Revision: 1.2 $"); vtkStandardNewMacro(vtkvmtkSparseMatrixRow); vtkvmtkSparseMatrixRow::vtkvmtkSparseMatrixRow() { this->NElements = 0; this->ElementIds = NULL; this->Elements = NULL; this->DiagonalElement = 0.0; } vtkvmtkSparseMatrixRow::~vtkvmtkSparseMatrixRow() { if (this->ElementIds!=NULL) { delete[] this->ElementIds; this->ElementIds = NULL; } if (this->Elements!=NULL) { delete[] this->Elements; this->Elements = NULL; } } void vtkvmtkSparseMatrixRow::Initialize() { this->NElements = 0; if (this->ElementIds!=NULL) { delete[] this->ElementIds; this->ElementIds = NULL; } if (this->Elements!=NULL) { delete[] this->Elements; this->Elements = NULL; } this->DiagonalElement = 0.0; } void vtkvmtkSparseMatrixRow::SetNumberOfElements(vtkIdType numberOfElements) { vtkIdType i; this->NElements = numberOfElements; if (this->ElementIds!=NULL) { delete[] this->ElementIds; this->ElementIds = NULL; } this->ElementIds = new vtkIdType[this->NElements]; for (i=0; iNElements; i++) { this->ElementIds[i] = 0; } if (this->Elements!=NULL) { delete[] this->Elements; this->Elements = NULL; } this->Elements = new double[this->NElements]; for (i=0; iNElements; i++) { this->Elements[i] = 0.0; } this->DiagonalElement = 0.0; } vtkIdType vtkvmtkSparseMatrixRow::GetElementIndex(vtkIdType id) { vtkIdType index = -1; int j; for (j=0; jNElements; j++) { if (this->ElementIds[j] == id) { index = j; break; } } if (index == -1) { vtkErrorMacro("Error: ElementId not in sparse matrix"); return -1; } return index; } void vtkvmtkSparseMatrixRow::CopyStencil(vtkvmtkStencil* stencil) { vtkIdType i; this->NElements = stencil->GetNumberOfPoints(); if (this->ElementIds!=NULL) { delete[] this->ElementIds; this->ElementIds = NULL; } this->ElementIds = new vtkIdType[this->NElements]; for (i=0; iNElements; i++) { this->ElementIds[i] = stencil->GetPointId(i); } if (this->Elements!=NULL) { delete[] this->Elements; this->Elements = NULL; } this->Elements = new double[this->NElements]; for (i=0; iNElements; i++) { this->Elements[i] = stencil->GetWeight(i); } this->DiagonalElement = stencil->GetCenterWeight(); } void vtkvmtkSparseMatrixRow::CopyNeighborhood(vtkvmtkNeighborhood* neighborhood) { vtkIdType i; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); this->SetNumberOfElements(numberOfNeighborhoodPoints); for (i=0; iElementIds[i] = neighborhood->GetPointId(i); } } void vtkvmtkSparseMatrixRow::DeepCopy(vtkvmtkSparseMatrixRow *src) { if (this->ElementIds != NULL) { delete[] this->ElementIds; this->ElementIds = NULL; } if (this->Elements != NULL) { delete[] this->Elements; this->Elements = NULL; } this->NElements = src->NElements; if (src->NElements > 0) { this->ElementIds = new vtkIdType[src->NElements]; memcpy(this->ElementIds, src->ElementIds, this->NElements * sizeof(vtkIdType)); this->Elements = new double[src->NElements]; memcpy(this->Elements, src->Elements, this->NElements * sizeof(double)); } this->DiagonalElement = src->DiagonalElement; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkGaussQuadrature.cxx0000664000175000017500000027135011757446472024230 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkGaussQuadrature.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkGaussQuadrature.h" #include "vtkObjectFactory.h" #include "vtkCellType.h" #include "vtkLine.h" #include "vtkQuadraticEdge.h" #include "vtkQuad.h" #include "vtkQuadraticQuad.h" #include "vtkTriangle.h" #include "vtkQuadraticTriangle.h" #include "vtkHexahedron.h" #include "vtkQuadraticHexahedron.h" #include "vtkWedge.h" #include "vtkQuadraticWedge.h" #include "vtkTetra.h" #include "vtkQuadraticTetra.h" #include "vtkMath.h" vtkStandardNewMacro(vtkvmtkGaussQuadrature); vtkCxxRevisionMacro(vtkvmtkGaussQuadrature, "$Revision: 1.2 $"); vtkvmtkGaussQuadrature::vtkvmtkGaussQuadrature() { this->QuadraturePoints = NULL; this->QuadratureWeights = NULL; this->Order = 1; this->PreviousOrder = 0; this->CellType = VTK_EMPTY_CELL; } vtkvmtkGaussQuadrature::~vtkvmtkGaussQuadrature() { if (this->QuadraturePoints) { this->QuadraturePoints->Delete(); this->QuadraturePoints = NULL; } if (this->QuadratureWeights) { this->QuadratureWeights->Delete(); this->QuadratureWeights = NULL; } } void vtkvmtkGaussQuadrature::Initialize(vtkIdType cellType) { if ((cellType == this->CellType) && (this->Order == this->PreviousOrder)) { return; } this->CellType = cellType; this->PreviousOrder = this->Order; if (this->QuadraturePoints) { this->QuadraturePoints->Delete(); this->QuadraturePoints = NULL; } this->QuadraturePoints = vtkDoubleArray::New(); if (this->QuadratureWeights) { this->QuadratureWeights->Delete(); this->QuadratureWeights = NULL; } this->QuadratureWeights = vtkDoubleArray::New(); switch(cellType) { case VTK_LINE: case VTK_QUADRATIC_EDGE: { this->QuadraturePoints->SetNumberOfComponents(1); this->Initialize1DGauss(); break; } case VTK_QUAD: case VTK_QUADRATIC_QUAD: { vtkvmtkGaussQuadrature* q1D = vtkvmtkGaussQuadrature::New(); q1D->SetOrder(this->Order); q1D->Initialize1DGauss(); this->TensorProductQuad(q1D); q1D->Delete(); break; } case VTK_TRIANGLE: case VTK_QUADRATIC_TRIANGLE: { if (this->Order == 0 || this->Order ==1) { this->QuadraturePoints->SetNumberOfComponents(2); this->QuadraturePoints->SetNumberOfTuples(1); this->QuadratureWeights->SetNumberOfTuples(1); double point[2]; double weight; point[0] = 0.33333333333333333333333333333333; point[1] = 0.33333333333333333333333333333333; weight = 0.5; this->QuadraturePoints->SetTuple(0,point); this->QuadratureWeights->SetValue(0,weight); break; } vtkvmtkGaussQuadrature* gauss1D = vtkvmtkGaussQuadrature::New(); gauss1D->SetOrder(this->Order); gauss1D->Initialize1DGauss(); vtkvmtkGaussQuadrature* jacA1D = vtkvmtkGaussQuadrature::New(); jacA1D->SetOrder(this->Order); jacA1D->Initialize1DJacobi(1,0); this->TensorProductTriangle(gauss1D,jacA1D); gauss1D->Delete(); jacA1D->Delete(); break; } case VTK_HEXAHEDRON: case VTK_QUADRATIC_HEXAHEDRON: { vtkvmtkGaussQuadrature* q1D = vtkvmtkGaussQuadrature::New(); q1D->SetOrder(this->Order); q1D->Initialize1DGauss(); this->TensorProductHexahedron(q1D); q1D->Delete(); break; } case VTK_WEDGE: case VTK_QUADRATIC_WEDGE: #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case VTK_BIQUADRATIC_QUADRATIC_WEDGE: #endif { vtkvmtkGaussQuadrature* q1D = vtkvmtkGaussQuadrature::New(); q1D->SetOrder(this->Order); q1D->Initialize1DGauss(); vtkvmtkGaussQuadrature* q2D = vtkvmtkGaussQuadrature::New(); q2D->SetOrder(this->Order); q2D->Initialize(VTK_TRIANGLE); this->TensorProductWedge(q1D,q2D); q1D->Delete(); q2D->Delete(); break; } case VTK_TETRA: case VTK_QUADRATIC_TETRA: { if (this->Order == 0 || this->Order ==1) { this->QuadraturePoints->SetNumberOfComponents(3); this->QuadraturePoints->SetNumberOfTuples(1); this->QuadratureWeights->SetNumberOfTuples(1); double point[3]; double weight; point[0] = 0.25; point[1] = 0.25; point[2] = 0.25; weight = .1666666666666666666666666666666666666666666667; this->QuadraturePoints->SetTuple(0,point); this->QuadratureWeights->SetValue(0,weight); break; } vtkvmtkGaussQuadrature* gauss1D = vtkvmtkGaussQuadrature::New(); gauss1D->SetOrder(this->Order); gauss1D->Initialize1DGauss(); vtkvmtkGaussQuadrature* jacA1D = vtkvmtkGaussQuadrature::New(); jacA1D->SetOrder(this->Order); jacA1D->Initialize1DJacobi(1,0); vtkvmtkGaussQuadrature* jacB1D = vtkvmtkGaussQuadrature::New(); jacB1D->SetOrder(this->Order); jacB1D->Initialize1DJacobi(2,0); this->TensorProductTetra(gauss1D,jacA1D,jacB1D); gauss1D->Delete(); jacA1D->Delete(); jacB1D->Delete(); break; } default: { vtkErrorMacro("Unsupported element for Gauss quadrature."); return; } } } void vtkvmtkGaussQuadrature::ScaleTo01() { if (this->QuadraturePoints->GetNumberOfComponents() != 1) { vtkErrorMacro("Error: scaling assumes Dimensionality == 1."); return; } double point[1]; double weight; int numberOfQuadraturePoints = this->GetNumberOfQuadraturePoints(); int i; for (i=0; iQuadraturePoints->GetTuple(i,point); point[0] = 0.5 * (point[0] + 1.0); this->QuadraturePoints->SetTuple(i,point); weight = this->QuadratureWeights->GetValue(i); weight *= 0.5; this->QuadratureWeights->SetValue(i,weight); } } void vtkvmtkGaussQuadrature::Initialize1DGauss() { if (this->QuadraturePoints) { this->QuadraturePoints->Delete(); this->QuadraturePoints = NULL; } this->QuadraturePoints = vtkDoubleArray::New(); if (this->QuadratureWeights) { this->QuadratureWeights->Delete(); this->QuadratureWeights = NULL; } this->QuadratureWeights = vtkDoubleArray::New(); switch(this->Order) { case 0: case 1: { this->QuadraturePoints->SetNumberOfTuples (1); this->QuadratureWeights->SetNumberOfTuples(1); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.; weights[0] = 2.; break; } case 2: case 3: { this->QuadraturePoints->SetNumberOfTuples (2); this->QuadratureWeights->SetNumberOfTuples(2); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.577350269189626; // -sqrt(3)/3 points[1] = -points[0]; weights[0] = 1.; weights[1] = weights[0]; break; } case 4: case 5: { this->QuadraturePoints->SetNumberOfTuples (3); this->QuadratureWeights->SetNumberOfTuples(3); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.774596669241483377035853079956; points[1] = 0.; points[2] = -points[0]; weights[0] = 0.555555555555555555555555555556; weights[1] = 0.888888888888888888888888888889; weights[2] = weights[0]; break; } case 6: case 7: { this->QuadraturePoints->SetNumberOfTuples (4); this->QuadratureWeights->SetNumberOfTuples(4); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.861136311594052575223946488893; points[1] = -0.339981043584856264802665759103; points[2] = -points[1]; points[3] = -points[0]; weights[0] = 0.347854845137453857373063949222; weights[1] = 0.652145154862546142626936050778; weights[2] = weights[1]; weights[3] = weights[0]; break; } case 8: case 9: { this->QuadraturePoints->SetNumberOfTuples (5); this->QuadratureWeights->SetNumberOfTuples(5); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.906179845938663992797626878299; points[1] = -0.538469310105683091036314420700; points[2] = 0.; points[3] = -points[1]; points[4] = -points[0]; weights[0] = 0.236926885056189087514264040720; weights[1] = 0.478628670499366468041291514836; weights[2] = 0.568888888888888888888888888889; weights[3] = weights[1]; weights[4] = weights[0]; break; } case 10: case 11: { this->QuadraturePoints->SetNumberOfTuples (6); this->QuadratureWeights->SetNumberOfTuples(6); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.932469514203152027812301554494; points[1] = -0.661209386466264513661399595020; points[2] = -0.238619186083196908630501721681; points[3] = -points[2]; points[4] = -points[1]; points[5] = -points[0]; weights[0] = 0.171324492379170345040296142173; weights[1] = 0.360761573048138607569833513838; weights[2] = 0.467913934572691047389870343990; weights[3] = weights[2]; weights[4] = weights[1]; weights[5] = weights[0]; break; } case 12: case 13: { this->QuadraturePoints->SetNumberOfTuples (7); this->QuadratureWeights->SetNumberOfTuples(7); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.949107912342758524526189684048; points[1] = -0.741531185599394439863864773281; points[2] = -0.405845151377397166906606412077; points[3] = 0.; points[4] = -points[2]; points[5] = -points[1]; points[6] = -points[0]; weights[0] = 0.12948496616887; weights[1] = 0.27970539148928; weights[2] = 0.38183005050512; weights[3] = 0.41795918367347; weights[4] = weights[2]; weights[5] = weights[1]; weights[6] = weights[0]; break; } case 14: case 15: { this->QuadraturePoints->SetNumberOfTuples (8); this->QuadratureWeights->SetNumberOfTuples(8); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.960289856497536231683560868569; points[1] = -0.796666477413626739591553936476; points[2] = -0.525532409916328985817739049189; points[3] = -0.183434642495649804939476142360; points[4] = -points[3]; points[5] = -points[2]; points[6] = -points[1]; points[7] = -points[0]; weights[0] = 0.101228536290376259152531354310; weights[1] = 0.222381034453374470544355994426; weights[2] = 0.313706645877887287337962201987; weights[3] = 0.362683783378361982965150449277; weights[4] = weights[3]; weights[5] = weights[2]; weights[6] = weights[1]; weights[7] = weights[0]; break; } case 16: case 17: { this->QuadraturePoints->SetNumberOfTuples (9); this->QuadratureWeights->SetNumberOfTuples(9); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.968160239507626089835576202904; points[1] = -0.836031107326635794299429788070; points[2] = -0.613371432700590397308702039341; points[3] = -0.324253423403808929038538014643; points[4] = 0.0000000000000000000000000000000; points[5] = -points[3]; points[6] = -points[2]; points[7] = -points[1]; points[8] = -points[0]; weights[0] = 0.0812743883615744119718921581105; weights[1] = 0.180648160694857404058472031243; weights[2] = 0.260610696402935462318742869419; weights[3] = 0.312347077040002840068630406584; weights[4] = 0.330239355001259763164525069287; weights[5] = weights[3]; weights[6] = weights[2]; weights[7] = weights[1]; weights[8] = weights[0]; break; } case 18: case 19: { this->QuadraturePoints->SetNumberOfTuples (10); this->QuadratureWeights->SetNumberOfTuples(10); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.973906528517171720077964012084; points[1] = -0.865063366688984510732096688423; points[2] = -0.679409568299024406234327365115; points[3] = -0.433395394129247190799265943166; points[4] = -0.148874338981631210864826001130; points[5] = -points[4]; points[6] = -points[3]; points[7] = -points[2]; points[8] = -points[1]; points[9] = -points[0]; weights[0] = 0.0666713443086881375935688098933; weights[1] = 0.149451349150580593145776339658; weights[2] = 0.219086362515982043995534934228; weights[3] = 0.269266719309996355091226921569; weights[4] = 0.295524224714752870173892994651; weights[5] = weights[4]; weights[6] = weights[3]; weights[7] = weights[2]; weights[8] = weights[1]; weights[9] = weights[0]; break; } case 20: case 21: { this->QuadraturePoints->SetNumberOfTuples (11); this->QuadratureWeights->SetNumberOfTuples(11); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.97822865814606; points[1] = -0.88706259976810; points[2] = -0.73015200557405; points[3] = -0.51909612920681; points[4] = -0.26954315595235; points[5] = 0.; points[6] = -points[4]; points[7] = -points[3]; points[8] = -points[2]; points[9] = -points[1]; points[10] = -points[0]; weights[0] = 0.05566856711617; weights[1] = 0.12558036946490; weights[2] = 0.18629021092773; weights[3] = 0.23319376459199; weights[4] = 0.26280454451025; weights[5] = 0.27292508677790; weights[6] = weights[4]; weights[7] = weights[3]; weights[8] = weights[2]; weights[9] = weights[1]; weights[10] = weights[0]; break; } case 22: case 23: { this->QuadraturePoints->SetNumberOfTuples (12); this->QuadratureWeights->SetNumberOfTuples(12); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.981560634246719250690549090149; points[1] = -0.904117256370474856678465866119; points[2] = -0.769902674194304687036893833213; points[3] = -0.587317954286617447296702418941; points[4] = -0.367831498998180193752691536644; points[5] = -0.125233408511468915472441369464; points[6] = -points[5]; points[7] = -points[4]; points[8] = -points[3]; points[9] = -points[2]; points[10] = -points[1]; points[11] = -points[0]; weights[0] = 0.0471753363865118271946159614850; weights[1] = 0.106939325995318430960254718194; weights[2] = 0.160078328543346226334652529543; weights[3] = 0.203167426723065921749064455810; weights[4] = 0.233492536538354808760849898925; weights[5] = 0.249147045813402785000562436043; weights[6] = weights[5]; weights[7] = weights[4]; weights[8] = weights[3]; weights[9] = weights[2]; weights[10] = weights[1]; weights[11] = weights[0]; break; } case 24: case 25: { this->QuadraturePoints->SetNumberOfTuples (13); this->QuadratureWeights->SetNumberOfTuples(13); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.98418305471859; points[1] = -0.91759839922298; points[2] = -0.80157809073331; points[3] = -0.64234933944034; points[4] = -0.44849275103645; points[5] = -0.23045831595513; points[6] = 0.; points[7] = -points[5]; points[8] = -points[4]; points[9] = -points[3]; points[10] = -points[2]; points[11] = -points[1]; points[12] = -points[0]; weights[0] = 0.04048400476532; weights[1] = 0.09212149983773; weights[2] = 0.13887351021979; weights[3] = 0.17814598076195; weights[4] = 0.20781604753689; weights[5] = 0.22628318026290; weights[6] = 0.23255155323087; weights[7] = weights[5]; weights[8] = weights[4]; weights[9] = weights[3]; weights[10] = weights[2]; weights[11] = weights[1]; weights[12] = weights[0]; break; } case 26: case 27: { this->QuadraturePoints->SetNumberOfTuples (14); this->QuadratureWeights->SetNumberOfTuples(14); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.98628380869681; points[1] = -0.92843488366357; points[2] = -0.82720131506977; points[3] = -0.68729290481169; points[4] = -0.51524863635815; points[5] = -0.31911236892789; points[6] = -0.10805494870734; points[7] = -points[6]; points[8] = -points[5]; points[9] = -points[4]; points[10] = -points[3]; points[11] = -points[2]; points[12] = -points[1]; points[13] = -points[0]; weights[0] = 0.03511946033175; weights[1] = 0.08015808715976; weights[2] = 0.12151857068790; weights[3] = 0.15720316715819; weights[4] = 0.18553839747794; weights[5] = 0.20519846372130; weights[6] = 0.21526385346316; weights[7] = weights[6]; weights[8] = weights[5]; weights[9] = weights[4]; weights[10] = weights[3]; weights[11] = weights[2]; weights[12] = weights[1]; weights[13] = weights[0]; break; } case 28: case 29: { this->QuadraturePoints->SetNumberOfTuples (15); this->QuadratureWeights->SetNumberOfTuples(15); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.98799251802049; points[1] = -0.93727339240071; points[2] = -0.84820658341043; points[3] = -0.72441773136017; points[4] = -0.57097217260854; points[5] = -0.39415134707756; points[6] = -0.20119409399743; points[7] = -0.00000000000000; points[8] = -points[6]; points[9] = -points[5]; points[10] = -points[4]; points[11] = -points[3]; points[12] = -points[2]; points[13] = -points[1]; points[14] = -points[0]; weights[0] = 0.03075324199612; weights[1] = 0.07036604748811; weights[2] = 0.10715922046717; weights[3] = 0.13957067792615; weights[4] = 0.16626920581699; weights[5] = 0.18616100001556; weights[6] = 0.19843148532711; weights[7] = 0.20257824192556; weights[8] = weights[6]; weights[9] = weights[5]; weights[10] = weights[4]; weights[11] = weights[3]; weights[12] = weights[2]; weights[13] = weights[1]; weights[14] = weights[0]; break; } case 30: case 31: { this->QuadraturePoints->SetNumberOfTuples (16); this->QuadratureWeights->SetNumberOfTuples(16); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.98940093499165; points[1] = -0.94457502307323; points[2] = -0.86563120238783; points[3] = -0.75540440835500; points[4] = -0.61787624440264; points[5] = -0.45801677765723; points[6] = -0.28160355077926; points[7] = -0.09501250983764; points[8] = -points[7]; points[9] = -points[6]; points[10] = -points[5]; points[11] = -points[4]; points[12] = -points[3]; points[13] = -points[2]; points[14] = -points[1]; points[15] = -points[0]; weights[0] = 0.02715245941175; weights[1] = 0.06225352393865; weights[2] = 0.09515851168249; weights[3] = 0.12462897125553; weights[4] = 0.14959598881658; weights[5] = 0.16915651939500; weights[6] = 0.18260341504492; weights[7] = 0.18945061045507; weights[8] = weights[7]; weights[9] = weights[6]; weights[10] = weights[5]; weights[11] = weights[4]; weights[12] = weights[3]; weights[13] = weights[2]; weights[14] = weights[1]; weights[15] = weights[0]; break; } case 32: case 33: { this->QuadraturePoints->SetNumberOfTuples (17); this->QuadratureWeights->SetNumberOfTuples(17); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.99057547531442; points[1] = -0.95067552176877; points[2] = -0.88023915372699; points[3] = -0.78151400389680; points[4] = -0.65767115921669; points[5] = -0.51269053708648; points[6] = -0.35123176345388; points[7] = -0.17848418149585; points[8] = 0.; points[9] = -points[7]; points[10] = -points[6]; points[11] = -points[5]; points[12] = -points[4]; points[13] = -points[3]; points[14] = -points[2]; points[15] = -points[1]; points[16] = -points[0]; weights[0] = 0.02414830286855; weights[1] = 0.05545952937399; weights[2] = 0.08503614831718; weights[3] = 0.11188384719340; weights[4] = 0.13513636846853; weights[5] = 0.15404576107681; weights[6] = 0.16800410215645; weights[7] = 0.17656270536699; weights[8] = 0.17944647035621; weights[9] = weights[7]; weights[10] = weights[6]; weights[11] = weights[5]; weights[12] = weights[4]; weights[13] = weights[3]; weights[14] = weights[2]; weights[15] = weights[1]; weights[16] = weights[0]; break; } case 34: case 35: { this->QuadraturePoints->SetNumberOfTuples (18); this->QuadratureWeights->SetNumberOfTuples(18); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.99156516842093; points[1] = -0.95582394957140; points[2] = -0.89260246649756; points[3] = -0.80370495897252; points[4] = -0.69168704306035; points[5] = -0.55977083107395; points[6] = -0.41175116146284; points[7] = -0.25188622569151; points[8] = -0.08477501304173; points[9] = -points[8]; points[10] = -points[7]; points[11] = -points[6]; points[12] = -points[5]; points[13] = -points[4]; points[14] = -points[3]; points[15] = -points[2]; points[16] = -points[1]; points[17] = -points[0]; weights[0] = 0.02161601352648; weights[1] = 0.04971454889497; weights[2] = 0.07642573025489; weights[3] = 0.10094204410629; weights[4] = 0.12255520671148; weights[5] = 0.14064291467065; weights[6] = 0.15468467512627; weights[7] = 0.16427648374583; weights[8] = 0.16914238296314; weights[9] = weights[8]; weights[10] = weights[7]; weights[11] = weights[6]; weights[12] = weights[5]; weights[13] = weights[4]; weights[14] = weights[3]; weights[15] = weights[2]; weights[16] = weights[1]; weights[17] = weights[0]; break; } case 36: case 37: { this->QuadraturePoints->SetNumberOfTuples (19); this->QuadratureWeights->SetNumberOfTuples(19); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.99240684384358; points[1] = -0.96020815213483; points[2] = -0.90315590361482; points[3] = -0.82271465653714; points[4] = -0.72096617733523; points[5] = -0.60054530466168; points[6] = -0.46457074137596; points[7] = -0.31656409996363; points[8] = -0.16035864564023; points[9] = 0.; points[10] = -points[8]; points[11] = -points[7]; points[12] = -points[6]; points[13] = -points[5]; points[14] = -points[4]; points[15] = -points[3]; points[16] = -points[2]; points[17] = -points[1]; points[18] = -points[0]; weights[0] = 0.01946178822973; weights[1] = 0.04481422676570; weights[2] = 0.06904454273764; weights[3] = 0.09149002162245; weights[4] = 0.11156664554733; weights[5] = 0.12875396253934; weights[6] = 0.14260670217361; weights[7] = 0.15276604206586; weights[8] = 0.15896884339395; weights[9] = 0.16105444984878; weights[10] = weights[8]; weights[11] = weights[7]; weights[12] = weights[6]; weights[13] = weights[5]; weights[14] = weights[4]; weights[15] = weights[3]; weights[16] = weights[2]; weights[17] = weights[1]; weights[18] = weights[0]; break; } case 38: case 39: { this->QuadraturePoints->SetNumberOfTuples (20); this->QuadratureWeights->SetNumberOfTuples(20); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.99312859918510; points[1] = -0.96397192727791; points[2] = -0.91223442825133; points[3] = -0.83911697182222; points[4] = -0.74633190646015; points[5] = -0.63605368072652; points[6] = -0.51086700195083; points[7] = -0.37370608871542; points[8] = -0.22778585114164; points[9] = -0.07652652113350; points[10] = -points[9]; points[11] = -points[8]; points[12] = -points[7]; points[13] = -points[6]; points[14] = -points[5]; points[15] = -points[4]; points[16] = -points[3]; points[17] = -points[2]; points[18] = -points[1]; points[19] = -points[0]; weights[0] = 0.01761400713915; weights[1] = 0.04060142980039; weights[2] = 0.06267204833411; weights[3] = 0.08327674157670; weights[4] = 0.10193011981724; weights[5] = 0.11819453196152; weights[6] = 0.13168863844918; weights[7] = 0.14209610931838; weights[8] = 0.14917298647260; weights[9] = 0.15275338713073; weights[10] = weights[9]; weights[11] = weights[8]; weights[12] = weights[7]; weights[13] = weights[6]; weights[14] = weights[5]; weights[15] = weights[4]; weights[16] = weights[3]; weights[17] = weights[2]; weights[18] = weights[1]; weights[19] = weights[0]; break; } case 40: case 41: { this->QuadraturePoints->SetNumberOfTuples (21); this->QuadratureWeights->SetNumberOfTuples(21); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.99375217062039; points[1] = -0.96722683856631; points[2] = -0.92009933415040; points[3] = -0.85336336458332; points[4] = -0.76843996347568; points[5] = -0.66713880419741; points[6] = -0.55161883588722; points[7] = -0.42434212020744; points[8] = -0.28802131680240; points[9] = -0.14556185416090; points[10] = 0.; points[11] = -points[9]; points[12] = -points[8]; points[13] = -points[7]; points[14] = -points[6]; points[15] = -points[5]; points[16] = -points[4]; points[17] = -points[3]; points[18] = -points[2]; points[19] = -points[1]; points[20] = -points[0]; weights[0] = 0.01601722825777; weights[1] = 0.03695378977085; weights[2] = 0.05713442542686; weights[3] = 0.07610011362838; weights[4] = 0.09344442345603; weights[5] = 0.10879729916715; weights[6] = 0.12183141605373; weights[7] = 0.13226893863334; weights[8] = 0.13988739479107; weights[9] = 0.14452440398997; weights[10] = 0.14608113364969; weights[11] = weights[9]; weights[12] = weights[8]; weights[13] = weights[7]; weights[14] = weights[6]; weights[15] = weights[5]; weights[16] = weights[4]; weights[17] = weights[3]; weights[18] = weights[2]; weights[19] = weights[1]; weights[20] = weights[0]; break; } case 42: case 43: { this->QuadraturePoints->SetNumberOfTuples (22); this->QuadratureWeights->SetNumberOfTuples(22); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = -0.99429458548240; points[1] = -0.97006049783543; points[2] = -0.92695677218717; points[3] = -0.86581257772030; points[4] = -0.78781680597921; points[5] = -0.69448726318668; points[6] = -0.58764040350691; points[7] = -0.46935583798676; points[8] = -0.34193582089208; points[9] = -0.20786042668822; points[10] = -0.06973927331972; points[11] = -points[10]; points[12] = -points[9]; points[13] = -points[8]; points[14] = -points[7]; points[15] = -points[6]; points[16] = -points[5]; points[17] = -points[4]; points[18] = -points[3]; points[19] = -points[2]; points[20] = -points[1]; points[21] = -points[0]; weights[0] = 0.01462799529827; weights[1] = 0.03377490158481; weights[2] = 0.05229333515268; weights[3] = 0.06979646842452; weights[4] = 0.08594160621707; weights[5] = 0.10041414444288; weights[6] = 0.11293229608054; weights[7] = 0.12325237681051; weights[8] = 0.13117350478706; weights[9] = 0.13654149834602; weights[10] = 0.13925187285563; weights[11] = weights[10]; weights[12] = weights[9]; weights[13] = weights[8]; weights[14] = weights[7]; weights[15] = weights[6]; weights[16] = weights[5]; weights[17] = weights[4]; weights[18] = weights[3]; weights[19] = weights[2]; weights[20] = weights[1]; weights[21] = weights[0]; break; } default: { vtkErrorMacro("Quadrature rule not supported."); return; } } this->ScaleTo01(); } void vtkvmtkGaussQuadrature::Initialize1DJacobi(int alpha, int beta) { if (this->QuadraturePoints) { this->QuadraturePoints->Delete(); this->QuadraturePoints = NULL; } this->QuadraturePoints = vtkDoubleArray::New(); if (this->QuadratureWeights) { this->QuadratureWeights->Delete(); this->QuadratureWeights = NULL; } this->QuadratureWeights = vtkDoubleArray::New(); if ((alpha == 1) && (beta == 0)) { switch (this->Order) { case 0: case 1: { this->QuadraturePoints->SetNumberOfTuples (1); this->QuadratureWeights->SetNumberOfTuples(1); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.33333333333333; weights[0] = 0.50000000000000; break; } case 2: case 3: { this->QuadraturePoints->SetNumberOfTuples (2); this->QuadratureWeights->SetNumberOfTuples(2); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.15505102572168; points[1] = 0.64494897427832; weights[0] = 0.31804138174398; weights[1] = 0.18195861825602; break; } case 4: case 5: { this->QuadraturePoints->SetNumberOfTuples (3); this->QuadratureWeights->SetNumberOfTuples(3); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.08858795951270; points[1] = 0.40946686444073; points[2] = 0.78765946176085; weights[0] = 0.20093191373896; weights[1] = 0.22924110635959; weights[2] = 0.06982697990145; break; } case 6: case 7: { this->QuadraturePoints->SetNumberOfTuples (4); this->QuadratureWeights->SetNumberOfTuples(4); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.05710419611452; points[1] = 0.27684301363812; points[2] = 0.58359043236892; points[3] = 0.86024013565622; weights[0] = 0.13550691343149; weights[1] = 0.20346456801027; weights[2] = 0.12984754760823; weights[3] = 0.03118097095001; break; } case 8: case 9: { this->QuadraturePoints->SetNumberOfTuples (5); this->QuadratureWeights->SetNumberOfTuples(5); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.03980985705147; points[1] = 0.19801341787361; points[2] = 0.43797481024739; points[3] = 0.69546427335364; points[4] = 0.90146491420117; weights[0] = 0.09678159022665; weights[1] = 0.16717463809437; weights[2] = 0.14638698708467; weights[3] = 0.07390887007262; weights[4] = 0.01574791452169; break; } case 10: case 11: { this->QuadraturePoints->SetNumberOfTuples (6); this->QuadratureWeights->SetNumberOfTuples(6); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.02931642715979; points[1] = 0.14807859966848; points[2] = 0.33698469028115; points[3] = 0.55867151877155; points[4] = 0.76923386203005; points[5] = 0.92694567131974; weights[0] = 0.07231033072551; weights[1] = 0.13554249723152; weights[2] = 0.14079255378820; weights[3] = 0.09866115089066; weights[4] = 0.04395516555051; weights[5] = 0.00873830181361; break; } case 12: case 13: { this->QuadraturePoints->SetNumberOfTuples (7); this->QuadratureWeights->SetNumberOfTuples(7); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.02247938643871; points[1] = 0.11467905316090; points[2] = 0.26578982278459; points[3] = 0.45284637366944; points[4] = 0.64737528288683; points[5] = 0.81975930826311; points[6] = 0.94373743946308; weights[0] = 0.05596736342349; weights[1] = 0.11050925819087; weights[2] = 0.12739089729959; weights[3] = 0.10712506569587; weights[4] = 0.06638469646549; weights[5] = 0.02740835672187; weights[6] = 0.00521436220281; break; } case 14: case 15: { this->QuadraturePoints->SetNumberOfTuples (8); this->QuadratureWeights->SetNumberOfTuples(8); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01777991514737; points[1] = 0.09132360789979; points[2] = 0.21430847939563; points[3] = 0.37193216458327; points[4] = 0.54518668480343; points[5] = 0.71317524285557; points[6] = 0.85563374295785; points[7] = 0.95536604471003; weights[0] = 0.04455080436154; weights[1] = 0.09111902363638; weights[2] = 0.11250579947089; weights[3] = 0.10604735943593; weights[4] = 0.07919959949232; weights[5] = 0.04543931950470; weights[6] = 0.01784290265599; weights[7] = 0.00329519144225; break; } case 16: case 17: { this->QuadraturePoints->SetNumberOfTuples (9); this->QuadratureWeights->SetNumberOfTuples(9); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01441240964887; points[1] = 0.07438738970920; points[2] = 0.17611665616299; points[3] = 0.30966757992764; points[4] = 0.46197040108101; points[5] = 0.61811723469529; points[6] = 0.76282301518504; points[7] = 0.88192102121000; points[8] = 0.96374218711679; weights[0] = 0.03627800352333; weights[1] = 0.07607425510930; weights[2] = 0.09853374217235; weights[3] = 0.10030880919337; weights[4] = 0.08435832184492; weights[5] = 0.05840119529517; weights[6] = 0.03180482149105; weights[7] = 0.01206000428479; weights[8] = 0.00218084708577; break; } case 18: case 19: { this->QuadraturePoints->SetNumberOfTuples (10); this->QuadratureWeights->SetNumberOfTuples(10); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01191761343242; points[1] = 0.06173207187714; points[2] = 0.14711144964308; points[3] = 0.26115967600846; points[4] = 0.39463984688579; points[5] = 0.53673876571566; points[6] = 0.67594446167666; points[7] = 0.80097892103690; points[8] = 0.90171098779015; points[9] = 0.96997096783851; weights[0] = 0.03009950802395; weights[1] = 0.06428715450909; weights[2] = 0.08621130028917; weights[3] = 0.09269689367772; weights[4] = 0.08455710969083; weights[5] = 0.06605307556335; weights[6] = 0.04340190640715; weights[7] = 0.02277459145326; weights[8] = 0.00841931978298; weights[9] = 0.00149914060241; break; } case 20: case 21: { this->QuadraturePoints->SetNumberOfTuples (11); this->QuadratureWeights->SetNumberOfTuples(11); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01001828046168; points[1] = 0.05203545112718; points[2] = 0.12461922514445; points[3] = 0.22284060704384; points[4] = 0.34000815791467; points[5] = 0.46813761308958; points[6] = 0.59849727976714; points[7] = 0.72220328489097; points[8] = 0.83082489962282; points[9] = 0.91695838655260; points[10] = 0.97472637960248; weights[0] = 0.02536734068817; weights[1] = 0.05493809113287; weights[2] = 0.07562004805718; weights[3] = 0.08465942288402; weights[4] = 0.08187910298806; weights[5] = 0.06953187515818; weights[6] = 0.05159136067230; weights[7] = 0.03264154671383; weights[8] = 0.01666362345168; weights[9] = 0.00604392096048; weights[10] = 0.00106366729324; break; } case 22: case 23: { this->QuadraturePoints->SetNumberOfTuples (12); this->QuadratureWeights->SetNumberOfTuples(12); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00853905498844; points[1] = 0.04444646315539; points[2] = 0.10685449088348; points[3] = 0.19215105452985; points[4] = 0.29538088426258; points[5] = 0.41054508120146; points[6] = 0.53095084931282; points[7] = 0.64960065027725; points[8] = 0.75959888952523; points[9] = 0.85455254376493; points[10] = 0.92894210126442; points[11] = 0.97843793683415; weights[0] = 0.02166486088692; weights[1] = 0.04742785198044; weights[2] = 0.06660675062670; weights[3] = 0.07689660268004; weights[4] = 0.07769631681553; weights[5] = 0.07010933999763; weights[6] = 0.05661384371367; weights[7] = 0.04045165370691; weights[8] = 0.02487678040927; weights[9] = 0.01243600916642; weights[10] = 0.00444480779567; weights[11] = 0.00077518222094; break; } case 24: case 25: { this->QuadraturePoints->SetNumberOfTuples (13); this->QuadratureWeights->SetNumberOfTuples(13); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00736465102609; points[1] = 0.03839813873968; points[2] = 0.09259522469900; points[3] = 0.16725101139156; points[4] = 0.25862354070576; points[5] = 0.36213139728224; points[6] = 0.47258438600412; points[7] = 0.58444396402134; points[8] = 0.69210100171960; points[9] = 0.79015702827344; points[10] = 0.87369482130669; points[11] = 0.93852445910073; points[12] = 0.98138963498901; weights[0] = 0.01871473158558; weights[1] = 0.04132028941977; weights[2] = 0.05895393795654; weights[3] = 0.06971346828202; weights[4] = 0.07284969651569; weights[5] = 0.06881552948745; weights[6] = 0.05912048131399; weights[7] = 0.04599578067597; weights[8] = 0.03193678716215; weights[9] = 0.01921395716469; weights[10] = 0.00944892447958; weights[11] = 0.00333835925077; weights[12] = 0.00057805670494; break; } case 26: case 27: { this->QuadraturePoints->SetNumberOfTuples (14); this->QuadratureWeights->SetNumberOfTuples(14); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00641676079282; points[1] = 0.03350140453201; points[2] = 0.08098549968196; points[3] = 0.14680486768121; points[4] = 0.22808427064926; points[5] = 0.32127174398894; points[6] = 0.42229465730757; points[7] = 0.52673786133987; points[8] = 0.63003668837040; points[9] = 0.72767645288926; points[10] = 0.81538973944347; points[11] = 0.88934280881952; points[12] = 0.94630270006028; points[13] = 0.98377523409860; weights[0] = 0.01632675432256; weights[1] = 0.03629607805537; weights[2] = 0.05244595350181; weights[3] = 0.06321302557420; weights[4] = 0.06783165960405; weights[5] = 0.06639235062595; weights[6] = 0.05978555902241; weights[7] = 0.04951945452310; weights[8] = 0.03744309645891; weights[9] = 0.02542346540710; weights[10] = 0.01503230374390; weights[11] = 0.00729648413320; weights[12] = 0.00255410131768; weights[13] = 0.00043971370875; break; } case 28: case 29: { this->QuadraturePoints->SetNumberOfTuples (15); this->QuadratureWeights->SetNumberOfTuples(15); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00564068897251; points[1] = 0.02948229864794; points[2] = 0.07141295311516; points[3] = 0.12983102555359; points[4] = 0.20249275505010; points[5] = 0.28660608625753; points[6] = 0.37893868864698; points[7] = 0.47594230846323; points[8] = 0.57388916090669; points[9] = 0.66901519502996; points[10] = 0.75766473903134; points[11] = 0.83643096060561; points[12] = 0.90228670067938; points[13] = 0.95270040990583; points[14] = 0.98573054526317; weights[0] = 0.01436706962168; weights[1] = 0.03211904487489; weights[2] = 0.04689163994396; weights[3] = 0.05739882550681; weights[4] = 0.06291810664846; weights[5] = 0.06334395516137; weights[6] = 0.05917419205958; weights[7] = 0.05141236231177; weights[8] = 0.04140073518433; weights[9] = 0.03060976958640; weights[10] = 0.02041630927257; weights[11] = 0.01190419035507; weights[12] = 0.00571722239471; weights[13] = 0.00198623469314; weights[14] = 0.00034034238414; break; } case 30: case 31: { this->QuadraturePoints->SetNumberOfTuples (16); this->QuadratureWeights->SetNumberOfTuples(16); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00499729966377; points[1] = 0.02614351368139; points[2] = 0.06343094558384; points[3] = 0.11559843757982; points[4] = 0.18087055965788; points[5] = 0.25702480784517; points[6] = 0.34146792754782; points[7] = 0.43132434359563; points[8] = 0.52353411602517; points[9] = 0.61495715187649; points[10] = 0.70248013792504; points[11] = 0.78312255396487; points[12] = 0.85413814777521; points[13] = 0.91310837653714; points[14] = 0.95802441769048; points[15] = 0.98735302062604; weights[0] = 0.01273931065730; weights[1] = 0.02861245259007; weights[2] = 0.04212943115733; weights[3] = 0.05222859440383; weights[4] = 0.05825424020971; weights[5] = 0.06000085488797; weights[6] = 0.05771887960913; weights[7] = 0.05206413784368; weights[8] = 0.04399738218914; weights[9] = 0.03464781657920; weights[10] = 0.02515923310641; weights[11] = 0.01653958435560; weights[12] = 0.00953416788464; weights[13] = 0.00453923238613; weights[14] = 0.00156718847359; weights[15] = 0.00026749366505; break; } case 32: case 33: { this->QuadraturePoints->SetNumberOfTuples (17); this->QuadratureWeights->SetNumberOfTuples(17); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00445799356779; points[1] = 0.02334009412377; points[2] = 0.05670796876908; points[3] = 0.10355543293520; points[4] = 0.16246000342814; points[5] = 0.23163212577717; points[6] = 0.30897011775220; points[7] = 0.39212413472210; points[8] = 0.47856759685308; points[9] = 0.56567396688663; points[10] = 0.65079655845338; points[11] = 0.73134895273405; points[12] = 0.80488357852497; points[13] = 0.86916605956741; points[14] = 0.92224303459230; points[15] = 0.96250119782335; points[16] = 0.98871404063224; weights[0] = 0.01137270311317; weights[1] = 0.02564242792014; weights[2] = 0.03802572882564; weights[3] = 0.04764186937449; weights[4] = 0.05390793166739; weights[5] = 0.05657361138232; weights[6] = 0.05573491792341; weights[7] = 0.05180974192916; weights[8] = 0.04547779039902; weights[9] = 0.03759232548701; weights[10] = 0.02907452408763; weights[11] = 0.02080327801024; weights[12] = 0.01351369745227; weights[13] = 0.00771642221479; weights[14] = 0.00364723048341; weights[15] = 0.00125268343939; weights[16] = 0.00021311628921; break; } case 34: case 35: { this->QuadraturePoints->SetNumberOfTuples (18); this->QuadratureWeights->SetNumberOfTuples(18); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00400147938387; points[1] = 0.02096364839377; points[2] = 0.05099404158789; points[3] = 0.09328039592854; points[4] = 0.14667010367762; points[5] = 0.20970703958884; points[6] = 0.28067179006017; points[7] = 0.35762864997663; points[8] = 0.43847844922414; points[9] = 0.52101582087078; points[10] = 0.60298936055983; points[11] = 0.68216303911365; points[12] = 0.75637719340615; points[13] = 0.82360742977487; points[14] = 0.88201982536208; points[15] = 0.93002088969969; points[16] = 0.96630075194563; points[17] = 0.98986684820260; weights[0] = 0.01021433943501; weights[1] = 0.02310635016331; weights[2] = 0.03447111892183; weights[3] = 0.04357390707452; weights[4] = 0.04990222691756; weights[5] = 0.05319233463169; weights[6] = 0.05344528780267; weights[7] = 0.05091692885623; weights[8] = 0.04608240099011; weights[9] = 0.03957916228850; weights[10] = 0.03213480612754; weights[11] = 0.02448759000122; weights[12] = 0.01730830048085; weights[13] = 0.01113187009738; weights[14] = 0.00630603888236; weights[15] = 0.00296244306442; weights[16] = 0.00101302517930; weights[17] = 0.00017186908410; break; } case 36: case 37: { this->QuadraturePoints->SetNumberOfTuples (19); this->QuadratureWeights->SetNumberOfTuples(19); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00361164281856; points[1] = 0.01893183703159; points[2] = 0.04609793304843; points[3] = 0.08444722278421; points[4] = 0.13303618855810; points[5] = 0.19066859490476; points[6] = 0.25592540348210; points[7] = 0.32719980076381; points[8] = 0.40273678616508; points[9] = 0.48067639357855; points[10] = 0.55909949264903; points[11] = 0.63607504487927; points[12] = 0.70970765165390; points[13] = 0.77818422297676; points[14] = 0.83981861570871; points[15] = 0.89309313498184; points[16] = 0.93669584807437; points[17] = 0.96955263708022; points[18] = 0.99085180527096; weights[0] = 0.00922403772500; weights[1] = 0.02092465175192; weights[2] = 0.03137627528564; weights[3] = 0.03996237004887; weights[4] = 0.04623492816844; weights[5] = 0.04993413824027; weights[6] = 0.05100418662657; weights[7] = 0.04959104646856; weights[8] = 0.04602198571600; weights[9] = 0.04076887087172; weights[10] = 0.03439895795181; weights[11] = 0.02751805814427; weights[12] = 0.02071167256270; weights[13] = 0.01448984711207; weights[14] = 0.00924109192929; weights[15] = 0.00519978132826; weights[16] = 0.00243009171203; weights[17] = 0.00082788076092; weights[18] = 0.00014012759418; break; } case 38: case 39: { this->QuadraturePoints->SetNumberOfTuples (20); this->QuadratureWeights->SetNumberOfTuples(20); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00327610666905; points[1] = 0.01718121814526; points[2] = 0.04187143111777; points[3] = 0.07680083708962; points[4] = 0.12118986732368; points[5] = 0.17404711263554; points[6] = 0.23419188631359; points[7] = 0.30028067683595; points[8] = 0.37083718058440; points[9] = 0.44428528696301; points[10] = 0.51898428870357; points[11] = 0.59326553348351; points[12] = 0.66546969890551; points[13] = 0.73398385823566; points[14] = 0.79727750833659; points[15] = 0.85393675303589; points[16] = 0.90269587179345; points[17] = 0.94246554236319; points[18] = 0.97235694664744; points[19] = 0.99169995579293; weights[0] = 0.00837084417624; weights[1] = 0.01903496946364; weights[2] = 0.02866823737904; weights[3] = 0.03675023983654; weights[4] = 0.04289029583785; weights[5] = 0.04684169186242; weights[6] = 0.04851610505971; weights[7] = 0.04798546160980; weights[8] = 0.04547058894121; weights[9] = 0.04131770681654; weights[10] = 0.03596491915375; weights[11] = 0.02990174184254; weights[12] = 0.02362529617348; weights[13] = 0.01759706687915; weights[14] = 0.01220404612664; weights[15] = 0.00772766793003; weights[16] = 0.00432321911268; weights[17] = 0.00201145761396; weights[18] = 0.00068306227608; weights[19] = 0.00011538190718; break; } case 40: case 41: { this->QuadraturePoints->SetNumberOfTuples (21); this->QuadratureWeights->SetNumberOfTuples(21); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00298523728321; points[1] = 0.01566228055757; points[2] = 0.03819828824507; points[3] = 0.07013961906233; points[4] = 0.11083667332036; points[5] = 0.15946112944407; points[6] = 0.21502318535802; points[7] = 0.27639177909378; points[8] = 0.34231763295873; points[9] = 0.41145869156191; points[10] = 0.48240744461244; points[11] = 0.55371958072829; points[12] = 0.62394338972128; points[13] = 0.69164931501296; points[14] = 0.75545905444969; points[15] = 0.81407361651270; points[16] = 0.86629975897096; points[17] = 0.91107426580262; points[18] = 0.94748554440640; points[19] = 0.97479197566037; points[10] = 0.99243549072562; weights[0] = 0.00763060590649; weights[1] = 0.01738792607614; weights[2] = 0.02628726008312; weights[3] = 0.03388679034430; weights[4] = 0.03984597757127; weights[5] = 0.04393557063501; weights[6] = 0.04605027072311; weights[7] = 0.04621255261088; weights[8] = 0.04456687468601; weights[9] = 0.04136476039687; weights[10] = 0.03694201264838; weights[11] = 0.03168995305003; weights[12] = 0.02602304679581; weights[13] = 0.02034554938976; weights[14] = 0.01501987261315; weights[15] = 0.01033920975794; weights[16] = 0.00650659742363; weights[17] = 0.00362205286973; weights[18] = 0.00167875602156; weights[19] = 0.00056849852670; weights[20] = 0.00009586186853; break; } case 42: case 43: { this->QuadraturePoints->SetNumberOfTuples (22); this->QuadratureWeights->SetNumberOfTuples(22); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00273144600888; points[1] = 0.01433593348370; points[2] = 0.03498632835122; points[3] = 0.06430264113216; points[4] = 0.10173934345216; points[5] = 0.14659920015767; points[6] = 0.19804660411818; points[7] = 0.25512320697169; points[8] = 0.31676578871045; points[9] = 0.38182606925675; points[10] = 0.44909210098682; points[11] = 0.51731084595099; points[12] = 0.58521151795130; points[13] = 0.65152925489581; points[14] = 0.71502868047476; points[15] = 0.77452691606482; points[16] = 0.82891561362173; points[17] = 0.87718159746542; points[18] = 0.91842572498985; points[19] = 0.95187959322972; points[20] = 0.97691966323713; points[21] = 0.99307748504435; weights[0] = 0.00698425611365; weights[1] = 0.01594405345473; weights[2] = 0.02418423667181; weights[3] = 0.03132759699927; weights[4] = 0.03707705409308; weights[5] = 0.04122240490628; weights[6] = 0.04365120378616; weights[7] = 0.04435337090028; weights[8] = 0.04341875014528; weights[9] = 0.04102779578181; weights[10] = 0.03743611646681; weights[11] = 0.03295405878528; weights[12] = 0.02792287082335; weights[13] = 0.02268922859809; weights[14] = 0.01758001756010; weights[15] = 0.01287923028132; weights[16] = 0.00880867244008; weights[17] = 0.00551387510211; weights[18] = 0.00305621411314; weights[19] = 0.00141176685313; weights[20] = 0.00047692790566; weights[21] = 0.00008029821694; break; } default: { vtkErrorMacro("Error: quadrature rule not supported."); return; } } } else if ((alpha == 2) && (beta == 0)) { switch(this->Order) { case 0: case 1: { this->QuadraturePoints->SetNumberOfTuples (1); this->QuadratureWeights->SetNumberOfTuples(1); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.25000000000000; weights[0] = 0.33333333333333; break; } case 2: case 3: { this->QuadraturePoints->SetNumberOfTuples (2); this->QuadratureWeights->SetNumberOfTuples(2); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.12251482265544; points[1] = 0.54415184401123; weights[0] = 0.23254745125351; weights[1] = 0.10078588207983; break; } case 4: case 5: { this->QuadraturePoints->SetNumberOfTuples (3); this->QuadratureWeights->SetNumberOfTuples(3); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.07299402407315; points[1] = 0.34700376603835; points[2] = 0.70500220988850; weights[0] = 0.15713636106489; weights[1] = 0.14624626925987; weights[2] = 0.02995070300858; break; } case 6: case 7: { this->QuadraturePoints->SetNumberOfTuples (4); this->QuadratureWeights->SetNumberOfTuples(4); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.04850054944700; points[1] = 0.23860073755186; points[2] = 0.51704729510437; points[3] = 0.79585141789677; weights[0] = 0.11088841561128; weights[1] = 0.14345878979921; weights[2] = 0.06863388717292; weights[3] = 0.01035224074992; break; } case 8: case 9: { this->QuadraturePoints->SetNumberOfTuples (5); this->QuadratureWeights->SetNumberOfTuples(5); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.03457893991821; points[1] = 0.17348032077170; points[2] = 0.38988638706552; points[3] = 0.63433347263089; points[4] = 0.85105421294702; weights[0] = 0.08176478428577; weights[1] = 0.12619896189991; weights[2] = 0.08920016122159; weights[3] = 0.03205560072296; weights[4] = 0.00411382520310; break; } case 10: case 11: { this->QuadraturePoints->SetNumberOfTuples (6); this->QuadratureWeights->SetNumberOfTuples(6); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.02590455509367; points[1] = 0.13156394165798; points[2] = 0.30243691802289; points[3] = 0.50903641316475; points[4] = 0.71568112731171; points[5] = 0.88680561617756; weights[0] = 0.06253870272658; weights[1] = 0.10737649973678; weights[2] = 0.09457718674854; weights[3] = 0.05128957112962; weights[4] = 0.01572029718495; weights[5] = 0.00183107580687; break; } case 12: case 13: { this->QuadraturePoints->SetNumberOfTuples (7); this->QuadratureWeights->SetNumberOfTuples(7); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.02013277377340; points[1] = 0.10308902914805; points[2] = 0.24055412604806; points[3] = 0.41400214459706; points[4] = 0.60002151327899; points[5] = 0.77351724659144; points[6] = 0.91118316656300; weights[0] = 0.04927650177644; weights[1] = 0.09069882461269; weights[2] = 0.09173380327980; weights[3] = 0.06314637870889; weights[4] = 0.02942221128953; weights[5] = 0.00816292563230; weights[6] = 0.00089268803369; break; } case 14: case 15: { this->QuadraturePoints->SetNumberOfTuples (8); this->QuadratureWeights->SetNumberOfTuples(8); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01609775955192; points[1] = 0.08290061748565; points[2] = 0.19547516848874; points[3] = 0.34165199147720; points[4] = 0.50559707818449; points[5] = 0.66955227182436; points[6] = 0.81577170358328; points[7] = 0.92850896495991; weights[0] = 0.03977895780670; weights[1] = 0.07681809326722; weights[2] = 0.08528476917194; weights[3] = 0.06844718342165; weights[4] = 0.04081442638854; weights[5] = 0.01724686378023; weights[6] = 0.00447452171301; weights[7] = 0.00046851778403; break; } case 16: case 17: { this->QuadraturePoints->SetNumberOfTuples (9); this->QuadratureWeights->SetNumberOfTuples(9); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01316588559711; points[1] = 0.06808452959377; points[2] = 0.16175951676407; points[3] = 0.28589108833922; points[4] = 0.42945364538781; points[5] = 0.57969405635116; points[6] = 0.72326857174034; points[7] = 0.84743684201324; points[8] = 0.94124586421327; weights[0] = 0.03276014511105; weights[1] = 0.06548953703338; weights[2] = 0.07767356916056; weights[3] = 0.06928439568980; weights[4] = 0.04854062786451; weights[5] = 0.02634328090255; weights[6] = 0.01040611657935; weights[7] = 0.00257439864561; weights[8] = 0.00026126234652; break; } case 18: case 19: { this->QuadraturePoints->SetNumberOfTuples (10); this->QuadratureWeights->SetNumberOfTuples(10); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.01096845245617; points[1] = 0.05689815053366; points[2] = 0.13595023405023; points[3] = 0.24228119613252; points[4] = 0.36800785044934; points[5] = 0.50380712641487; points[6] = 0.63960948865471; points[7] = 0.76534767954811; points[8] = 0.87171007457441; points[9] = 0.95087429264052; weights[0] = 0.02743408871016; weights[1] = 0.05627293640278; weights[2] = 0.07006950770867; weights[3] = 0.06745221938144; weights[4] = 0.05288378876696; weights[5] = 0.03385456501681; weights[6] = 0.01719757504655; weights[7] = 0.00646988906856; weights[8] = 0.00154552319474; weights[9] = 0.00015324003670; break; } case 20: case 21: { this->QuadraturePoints->SetNumberOfTuples (11); this->QuadratureWeights->SetNumberOfTuples(11); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00927897383134; points[1] = 0.04824969209430; points[2] = 0.11578862662939; points[3] = 0.20766834159706; points[4] = 0.31811795190623; points[5] = 0.44019839985886; points[6] = 0.56623983915457; points[7] = 0.68832423986296; points[8] = 0.79878435859091; points[9] = 0.89069109935439; points[10] = 0.95832514378665; weights[0] = 0.02330085005155; weights[1] = 0.04874586103051; weights[2] = 0.06297954300041; weights[3] = 0.06418355934975; weights[4] = 0.05463222232105; weights[5] = 0.03929021779844; weights[6] = 0.02358966353881; weights[7] = 0.01141459091810; weights[8] = 0.00414000426322; weights[9] = 0.00096302057554; weights[10] = 0.00009380048601; break; } case 22: case 23: { this->QuadraturePoints->SetNumberOfTuples (12); this->QuadratureWeights->SetNumberOfTuples(12); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00795204570266; points[1] = 0.04142781045426; points[2] = 0.09975762554264; points[3] = 0.17981078905241; points[4] = 0.27727345779932; points[5] = 0.38689200999769; points[6] = 0.50275736044903; points[7] = 0.61862386345846; points[8] = 0.72824645295307; points[9] = 0.82571851421479; points[10] = 0.90579507354454; points[11] = 0.96420653529267; weights[0] = 0.02003111258445; weights[1] = 0.04255661536742; weights[2] = 0.05658418474943; weights[3] = 0.06025060748762; weights[4] = 0.05457394116423; weights[5] = 0.04276476357019; weights[6] = 0.02890805183873; weights[7] = 0.01654734364461; weights[8] = 0.00771636702389; weights[9] = 0.00272084214410; weights[10] = 0.00061995339854; weights[11] = 0.00005955035981; break; } case 24: case 25: { this->QuadraturePoints->SetNumberOfTuples (13); this->QuadratureWeights->SetNumberOfTuples(13); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00689083130996; points[1] = 0.03595336270017; points[2] = 0.08681178015759; points[3] = 0.15709997419651; points[4] = 0.24353289958713; points[5] = 0.34206951264608; points[6] = 0.44810263890571; points[7] = 0.55667462262945; points[8] = 0.66270931356039; points[9] = 0.76124976630828; points[10] = 0.84769104394723; points[11] = 0.91799964553721; points[12] = 0.96892889422859; weights[0] = 0.01740122861003; weights[1] = 0.03742670816877; weights[2] = 0.05090983071260; weights[3] = 0.05611153713072; weights[4] = 0.05334002160577; weights[5] = 0.04462460075553; weights[6] = 0.03294045167837; weights[7] = 0.02125499671472; weights[8] = 0.01172825959308; weights[9] = 0.00531356933882; weights[10] = 0.00183239113924; weights[11] = 0.00041072089179; weights[12] = 0.00003901699326; break; } case 26: case 27: { this->QuadraturePoints->SetNumberOfTuples (14); this->QuadratureWeights->SetNumberOfTuples(14); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00602880887107; points[1] = 0.03149425981866; points[2] = 0.07621362247485; points[3] = 0.13836652595947; points[4] = 0.21540975706890; points[5] = 0.30418952814166; points[6] = 0.40107137869715; points[7] = 0.50208913974998; points[8] = 0.60310739672760; points[9] = 0.69999091716991; points[10] = 0.78877423843456; points[11] = 0.86582490073160; points[12] = 0.92799573874675; points[13] = 0.97277712074118; weights[0] = 0.01525520611942; weights[1] = 0.03313959546989; weights[2] = 0.04591477211457; weights[3] = 0.05202586541059; weights[4] = 0.05138992403936; weights[5] = 0.04525343225437; weights[6] = 0.03573901029244; weights[7] = 0.02521618353679; weights[8] = 0.01569433228504; weights[9] = 0.00841297673712; weights[10] = 0.00372487567527; weights[11] = 0.00126178389515; weights[12] = 0.00027909934095; weights[13] = 0.00002627616167; break; } case 28: case 29: { this->QuadraturePoints->SetNumberOfTuples (15); this->QuadratureWeights->SetNumberOfTuples(15); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00531905200284; points[1] = 0.02781456191826; points[2] = 0.06743186583900; points[3] = 0.12274828621550; points[4] = 0.19176570627765; points[5] = 0.27198996592949; points[6] = 0.36052169358706; points[7] = 0.45416123575448; points[8] = 0.54952435559355; points[9] = 0.64316460176878; points[10] = 0.73169797305252; points[11] = 0.81192547727501; points[12] = 0.88094952871531; points[13] = 0.93628182173552; points[14] = 0.97595387433502; weights[0] = 0.01348166272510; weights[1] = 0.02952765075673; weights[2] = 0.04153130765151; weights[3] = 0.04813205766842; weights[4] = 0.04904126789430; weights[5] = 0.04499155582051; weights[6] = 0.03747387579201; weights[7] = 0.02832655317418; weights[8] = 0.01929341658523; weights[9] = 0.01166858248475; weights[10] = 0.00611105011019; weights[11] = 0.00265566298577; weights[12] = 0.00088657363523; weights[13] = 0.00019398726306; weights[14] = 0.00001812878557; break; } case 30: case 31: { this->QuadraturePoints->SetNumberOfTuples (16); this->QuadratureWeights->SetNumberOfTuples(16); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00472768712293; points[1] = 0.02474296761943; points[2] = 0.06007643771664; points[3] = 0.10960060925877; points[4] = 0.17172475948300; points[5] = 0.24445243174451; points[6] = 0.32544621002413; points[7] = 0.41210296411686; points[8] = 0.50163755615319; points[9] = 0.59117238531650; points[10] = 0.67782991741456; points[11] = 0.75882525794914; points[12] = 0.83155588302646; points[13] = 0.89368597454880; points[14] = 0.94322428571225; points[15] = 0.97860643749870; weights[0] = 0.01199940562466; weights[1] = 0.02646084251727; weights[2] = 0.03768582468182; weights[3] = 0.04449657347243; weights[4] = 0.04650623939725; weights[5] = 0.04411265767579; weights[6] = 0.03834804695109; weights[7] = 0.03061203791776; weights[8] = 0.02235718564947; weights[9] = 0.01480377665771; weights[10] = 0.00874754549559; weights[11] = 0.00449484885147; weights[12] = 0.00192353192606; weights[13] = 0.00063445999957; weights[14] = 0.00013757810398; weights[15] = 0.00001277841057; break; } case 32: case 33: { this->QuadraturePoints->SetNumberOfTuples (17); this->QuadratureWeights->SetNumberOfTuples(17); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00422976548649; points[1] = 0.02215270531183; points[2] = 0.05385601482718; points[3] = 0.09843493683054; points[4] = 0.15460792826589; points[5] = 0.22075922519215; points[6] = 0.29498586629802; points[7] = 0.37515254164082; points[8] = 0.45895305335302; points[9] = 0.54397667809048; points[10] = 0.62777753854681; points[11] = 0.70794500138509; points[12] = 0.78217310308122; points[13] = 0.84832708570995; points[14] = 0.90450542331433; points[15] = 0.94909701659654; points[16] = 0.98084389384741; weights[0] = 0.01074815103074; weights[1] = 0.02383776201864; weights[2] = 0.03430788979558; weights[3] = 0.04114397584696; weights[4] = 0.04392261877247; weights[5] = 0.04282540392782; weights[6] = 0.03855524194700; weights[7] = 0.03216357011229; weights[8] = 0.02482925611191; weights[9] = 0.01763878933100; weights[10] = 0.01141364223861; weights[11] = 0.00661641976034; weights[12] = 0.00334651729181; weights[13] = 0.00141388375895; weights[14] = 0.00046167405878; weights[15] = 0.00009935652534; weights[16] = 0.00000918080420; break; } case 34: case 35: { this->QuadraturePoints->SetNumberOfTuples (18); this->QuadratureWeights->SetNumberOfTuples(18); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00380658224750; points[1] = 0.01994835104734; points[2] = 0.04854964530422; points[3] = 0.08887625911650; points[4] = 0.13988457083517; points[5] = 0.20025369592363; points[6] = 0.26842018278660; points[7] = 0.34261859780201; points[8] = 0.42092727587032; points[9] = 0.50131810275027; points[10] = 0.58170905267092; points[11] = 0.66001812722532; points[12] = 0.73421730813501; points[13] = 0.80238514983642; points[14] = 0.86275672070006; points[15] = 0.91376986411079; points[16] = 0.95410789551732; points[17] = 0.98274840759429; weights[0] = 0.00968239880373; weights[1] = 0.02157877267913; weights[2] = 0.03133390767164; weights[3] = 0.03807513425334; weights[4] = 0.04137718228740; weights[5] = 0.04128366580984; weights[6] = 0.03826279467224; weights[7] = 0.03309597620198; weights[8] = 0.02672342436888; weights[9] = 0.02007864169631; weights[10] = 0.01394389765361; weights[11] = 0.00885227822507; weights[12] = 0.00505024878834; weights[13] = 0.00252072163843; weights[14] = 0.00105355028395; weights[15] = 0.00034109120369; weights[16] = 0.00007293700866; weights[17] = 0.00000671008612; break; } case 36: case 37: { this->QuadraturePoints->SetNumberOfTuples (19); this->QuadratureWeights->SetNumberOfTuples(19); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00344389040386; points[1] = 0.01805697833790; points[2] = 0.04398739509084; points[3] = 0.08063327636666; points[4] = 0.12713640986156; points[5] = 0.18240698366909; points[6] = 0.24514956909517; points[7] = 0.31389356741822; points[8] = 0.38702770276933; points[9] = 0.46283779855202; points[10] = 0.53954696279209; points[11] = 0.61535724480455; points[12] = 0.68849179091409; points[13] = 0.75723651917330; points[14] = 0.81998035706324; points[15] = 0.87525316298383; points[16] = 0.92176068172914; points[17] = 0.95841690242341; points[18] = 0.98438280655170; weights[0] = 0.00876729705685; weights[1] = 0.01962085634017; weights[2] = 0.02870814977862; weights[3] = 0.03527811719937; weights[4] = 0.03892238622215; weights[5] = 0.03959824821476; weights[6] = 0.03760750052024; weights[7] = 0.03352506807051; weights[8] = 0.02809160793602; weights[9] = 0.02209056314976; weights[10] = 0.01623181532195; weights[11] = 0.01106144062900; weights[12] = 0.00691081107791; weights[13] = 0.00388978481254; weights[14] = 0.00191978847269; weights[15] = 0.00079504432545; weights[16] = 0.00025553085889; weights[17] = 0.00005434264313; weights[18] = 0.00000498070233; break; } case 38: case 39: { this->QuadraturePoints->SetNumberOfTuples (20); this->QuadratureWeights->SetNumberOfTuples(20); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00313068374074; points[1] = 0.01642208813399; points[2] = 0.04003690046191; points[3] = 0.07347719178529; points[4] = 0.11603090765549; points[5] = 0.16679125348101; points[6] = 0.22467641938431; points[7] = 0.28845271218127; points[8] = 0.35676087010245; points[9] = 0.42814504093326; points[10] = 0.50108381548285; points[11] = 0.57402265818283; points[12] = 0.64540704577737; points[13] = 0.71371561101529; points[14] = 0.77749259203549; points[15] = 0.83537891463156; points[16] = 0.88614130291455; points[17] = 0.92869901491875; points[18] = 0.96214871215050; points[19] = 0.98579578884064; weights[0] = 0.00797579273624; weights[1] = 0.01791375232568; weights[2] = 0.02638256442904; weights[3] = 0.03273464431747; weights[4] = 0.03658791655311; weights[5] = 0.03784739037681; weights[6] = 0.03669742047191; weights[7] = 0.03355643145337; weights[8] = 0.02900240474550; weights[9] = 0.02368229041417; weights[10] = 0.01822050341821; weights[11] = 0.01314091925662; weights[12] = 0.00881355607822; weights[13] = 0.00543209080611; weights[14] = 0.00302248917090; weights[15] = 0.00147744444197; weights[16] = 0.00060704570427; weights[17] = 0.00019388830962; weights[18] = 0.00004103910209; weights[19] = 0.00000374922099; break; } case 40: case 41: { this->QuadraturePoints->SetNumberOfTuples (21); this->QuadratureWeights->SetNumberOfTuples(21); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00285835060009; points[1] = 0.01499936497208; points[2] = 0.03659386328114; points[3] = 0.06722644166794; points[4] = 0.10630147973769; points[5] = 0.15305857495572; points[6] = 0.20658770608253; points[7] = 0.26584701401082; points[8] = 0.32968309899010; points[9] = 0.39685347698562; points[10] = 0.46605076663517; points[11] = 0.53592813869303; points[12] = 0.60512553397610; points[13] = 0.67229614098693; points[14] = 0.73613262059729; points[15] = 0.79539257374613; points[16] = 0.84892277353769; points[17] = 0.89568174292547; points[18] = 0.93476043640123; points[19] = 0.96540160736574; points[20] = 0.98702556657876; weights[0] = 0.00728663173133; weights[1] = 0.01641706114419; weights[2] = 0.02431607495623; weights[3] = 0.03042385465478; weights[4] = 0.03438855355052; weights[5] = 0.03608527738478; weights[6] = 0.03561594477458; weights[7] = 0.03328104676273; weights[8] = 0.02952807270199; weights[9] = 0.02488508387518; weights[10] = 0.01988978006629; weights[11] = 0.01502452804187; weights[12] = 0.01066627036547; weights[13] = 0.00705732097434; weights[14] = 0.00429931006420; weights[15] = 0.00236862153460; weights[16] = 0.00114824142071; weights[17] = 0.00046857361253; weights[18] = 0.00014884999899; weights[19] = 0.00003137723340; weights[20] = 0.00000285848355; break; } case 42: case 43: { this->QuadraturePoints->SetNumberOfTuples (22); this->QuadratureWeights->SetNumberOfTuples(22); double* points = this->QuadraturePoints->GetPointer(0); double* weights = this->QuadratureWeights->GetPointer(0); points[0] = 0.00262007472037; points[1] = 0.01375365798739; points[2] = 0.03357522684803; points[3] = 0.06173556162307; points[4] = 0.09773269667537; points[5] = 0.14092439775695; points[6] = 0.19053995518422; points[7] = 0.24569399962450; points[8] = 0.30540231844260; points[9] = 0.36859942495594; points[10] = 0.43415757484016; points[11] = 0.50090689264794; points[12] = 0.56765625027261; points[13] = 0.63321452557266; points[14] = 0.69641186298595; points[15] = 0.75612055917893; points[16] = 0.81127520683922; points[17] = 0.86089175276287; points[18] = 0.90408517849775; points[19] = 0.94008566921082; points[20] = 0.96825388381656; points[21] = 0.98810245999088; weights[0] = 0.00668293152387; weights[1] = 0.01509806242157; weights[2] = 0.02247371373445; weights[3] = 0.02832445802520; weights[4] = 0.03232947395276; weights[5] = 0.03434859966431; weights[6] = 0.03442630982802; weights[7] = 0.03277458690039; weights[8] = 0.02973733662833; weights[9] = 0.02574182123471; weights[10] = 0.02124416781346; weights[11] = 0.01667648237965; weights[12] = 0.01240245351092; weights[13] = 0.00868669847385; weights[14] = 0.00568076838491; weights[15] = 0.00342606852096; weights[16] = 0.00187138795325; weights[17] = 0.00090066625279; weights[18] = 0.00036536328467; weights[19] = 0.00011551470918; weights[20] = 0.00002426317792; weights[21] = 0.00000220495706; break; } default: { vtkErrorMacro("Quadrature rule not supported."); return; } } } else { vtkErrorMacro("Unsupported combination of Alpha and Beta."); return; } } void vtkvmtkGaussQuadrature::TensorProductQuad(vtkvmtkGaussQuadrature* q1D) { int numberOf1DQuadraturePoints = q1D->GetNumberOfQuadraturePoints(); this->QuadraturePoints->SetNumberOfComponents(2); this->QuadraturePoints->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); this->QuadratureWeights->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); double point[3]; double weight; int id; int i, j; for (j=0; jGetQuadraturePoint(i)[0]; point[1] = q1D->GetQuadraturePoint(j)[0]; point[2] = 0.0; weight = q1D->GetQuadratureWeight(i) * q1D->GetQuadratureWeight(j); this->QuadraturePoints->SetTuple(id,point); this->QuadratureWeights->SetValue(id,weight); } } } void vtkvmtkGaussQuadrature::TensorProductTriangle(vtkvmtkGaussQuadrature* gauss1D, vtkvmtkGaussQuadrature* jacA1D) { if (gauss1D->GetNumberOfQuadraturePoints() != jacA1D->GetNumberOfQuadraturePoints()) { vtkErrorMacro("Error: cannot build tensor product rule if rules have different order."); } int numberOf1DQuadraturePoints = gauss1D->GetNumberOfQuadraturePoints(); this->QuadraturePoints->SetNumberOfComponents(2); this->QuadraturePoints->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); this->QuadratureWeights->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); double point[2]; double weight; int id; int i, j; for (j=0; jGetQuadraturePoint(j)[0]; point[1] = gauss1D->GetQuadraturePoint(i)[0] * (1.0 - jacA1D->GetQuadraturePoint(j)[0]); weight = gauss1D->GetQuadratureWeight(i) * jacA1D->GetQuadratureWeight(j); this->QuadraturePoints->SetTuple(id,point); this->QuadratureWeights->SetValue(id,weight); } } } void vtkvmtkGaussQuadrature::TensorProductHexahedron(vtkvmtkGaussQuadrature* q1D) { int numberOf1DQuadraturePoints = q1D->GetNumberOfQuadraturePoints(); this->QuadraturePoints->SetNumberOfComponents(3); this->QuadraturePoints->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); this->QuadratureWeights->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); double point[3]; double weight; int id; int i, j, k; for (k=0; kGetQuadraturePoint(i)[0]; point[1] = q1D->GetQuadraturePoint(j)[0]; point[2] = q1D->GetQuadraturePoint(k)[0]; weight = q1D->GetQuadratureWeight(i) * q1D->GetQuadratureWeight(j) * q1D->GetQuadratureWeight(k); this->QuadraturePoints->SetTuple(id,point); this->QuadratureWeights->SetValue(id,weight); } } } } void vtkvmtkGaussQuadrature::TensorProductWedge(vtkvmtkGaussQuadrature* q1D, vtkvmtkGaussQuadrature* q2D) { int numberOf1DQuadraturePoints = q1D->GetNumberOfQuadraturePoints(); int numberOf2DQuadraturePoints = q2D->GetNumberOfQuadraturePoints(); this->QuadraturePoints->SetNumberOfComponents(3); this->QuadraturePoints->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf2DQuadraturePoints); this->QuadratureWeights->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf2DQuadraturePoints); double point[3]; double weight; int id; int i, j; for (j=0; jGetQuadraturePoint(i)[0]; point[1] = q2D->GetQuadraturePoint(i)[1]; point[2] = q1D->GetQuadraturePoint(j)[0]; weight = q2D->GetQuadratureWeight(i) * q1D->GetQuadratureWeight(j); this->QuadraturePoints->SetTuple(id,point); this->QuadratureWeights->SetValue(id,weight); } } } void vtkvmtkGaussQuadrature::TensorProductTetra(vtkvmtkGaussQuadrature* gauss1D, vtkvmtkGaussQuadrature* jacA1D, vtkvmtkGaussQuadrature* jacB1D) { if (gauss1D->GetNumberOfQuadraturePoints() != jacA1D->GetNumberOfQuadraturePoints()) { vtkErrorMacro("Error: cannot build tensor product rule if rules have different order."); } if (jacA1D->GetNumberOfQuadraturePoints() != jacB1D->GetNumberOfQuadraturePoints()) { vtkErrorMacro("Error: cannot build tensor product rule if rules have different order."); } int numberOf1DQuadraturePoints = gauss1D->GetNumberOfQuadraturePoints(); this->QuadraturePoints->SetNumberOfComponents(3); this->QuadraturePoints->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); this->QuadratureWeights->SetNumberOfTuples(numberOf1DQuadraturePoints * numberOf1DQuadraturePoints * numberOf1DQuadraturePoints); double point[3]; double weight; int id; int i, j, k; for (k=0; kGetQuadraturePoint(k)[0]; point[1] = jacA1D->GetQuadraturePoint(j)[0] * (1.0 - jacB1D->GetQuadraturePoint(k)[0]); point[2] = gauss1D->GetQuadraturePoint(i)[0] * (1.0 - jacA1D->GetQuadraturePoint(j)[0]) * (1.0 - jacB1D->GetQuadraturePoint(k)[0]); weight = gauss1D->GetQuadratureWeight(i) * jacA1D->GetQuadratureWeight(j) * jacB1D->GetQuadratureWeight(k); this->QuadraturePoints->SetTuple(id,point); this->QuadratureWeights->SetValue(id,weight); } } } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataCylinderHarmonicMappingFilter.h0000664000175000017500000000345611757446472030107 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCylinderHarmonicMappingFilter.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataCylinderHarmonicMappingFilter - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataCylinderHarmonicMappingFilter_h #define __vtkvmtkPolyDataCylinderHarmonicMappingFilter_h #include "vtkvmtkPolyDataHarmonicMappingFilter.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataCylinderHarmonicMappingFilter : public vtkvmtkPolyDataHarmonicMappingFilter { public: static vtkvmtkPolyDataCylinderHarmonicMappingFilter* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataCylinderHarmonicMappingFilter,vtkvmtkPolyDataHarmonicMappingFilter); protected: vtkvmtkPolyDataCylinderHarmonicMappingFilter(); ~vtkvmtkPolyDataCylinderHarmonicMappingFilter(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); private: vtkvmtkPolyDataCylinderHarmonicMappingFilter(const vtkvmtkPolyDataCylinderHarmonicMappingFilter&); // Not implemented. void operator=(const vtkvmtkPolyDataCylinderHarmonicMappingFilter&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataCylinderHarmonicMappingFilter.cxx0000664000175000017500000000605611757446472030461 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataCylinderHarmonicMappingFilter.cxx,v $ Language: C++ Date: $Date: 2005/03/31 15:07:53 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkPolyDataCylinderHarmonicMappingFilter, "$Revision: 1.5 $"); 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(); boundaryExtractor->SetInput(input); 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; iGetCell(i); for (int j=0; jGetNumberOfPoints(); j++) { this->BoundaryPointIds->InsertNextId(static_cast(boundaries->GetPointData()->GetScalars()->GetTuple1(boundaryCell->GetPointId(j)))); this->BoundaryValues->InsertNextTuple1(static_cast(i)); } } Superclass::RequestData(request,inputVector,outputVector); this->BoundaryPointIds->Delete(); this->BoundaryPointIds = NULL; this->BoundaryValues->Delete(); this->BoundaryValues = NULL; return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridFELaplaceAssembler.cxx0000664000175000017500000000605111757446472027752 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridFELaplaceAssembler.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridFELaplaceAssembler.h" #include "vtkvmtkGaussQuadrature.h" #include "vtkvmtkFEShapeFunctions.h" #include "vtkCell.h" #include "vtkMath.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridFELaplaceAssembler, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridFELaplaceAssembler); vtkvmtkUnstructuredGridFELaplaceAssembler::vtkvmtkUnstructuredGridFELaplaceAssembler() { } vtkvmtkUnstructuredGridFELaplaceAssembler::~vtkvmtkUnstructuredGridFELaplaceAssembler() { } void vtkvmtkUnstructuredGridFELaplaceAssembler::Build() { int numberOfVariables = 1; this->Initialize(numberOfVariables); vtkvmtkGaussQuadrature* gaussQuadrature = vtkvmtkGaussQuadrature::New(); gaussQuadrature->SetOrder(this->QuadratureOrder); vtkvmtkFEShapeFunctions* feShapeFunctions = vtkvmtkFEShapeFunctions::New(); int dimension = 3; int numberOfCells = this->DataSet->GetNumberOfCells(); int k; for (k=0; kDataSet->GetCell(k); if (cell->GetCellDimension() != dimension) { continue; } gaussQuadrature->Initialize(cell->GetCellType()); feShapeFunctions->Initialize(cell,gaussQuadrature->GetQuadraturePoints()); int numberOfQuadraturePoints = gaussQuadrature->GetNumberOfQuadraturePoints(); double quadraturePCoords[3]; int numberOfCellPoints = cell->GetNumberOfPoints(); int i, j; int q; for (q=0; qGetQuadraturePoint(q,quadraturePCoords); double quadratureWeight = gaussQuadrature->GetQuadratureWeight(q); double jacobian = feShapeFunctions->GetJacobian(q); double dphii[3], dphij[3]; for (i=0; iGetPointId(i); feShapeFunctions->GetDPhi(q,i,dphii); for (j=0; jGetPointId(j); feShapeFunctions->GetDPhi(q,j,dphij); double gradphii_gradphij = vtkMath::Dot(dphii,dphij); double value = jacobian * quadratureWeight * gradphii_gradphij; this->Matrix->AddElement(iId,jId,value); } } } } gaussQuadrature->Delete(); feShapeFunctions->Delete(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkLinearSystemSolver.cxx0000664000175000017500000000315711757446472024720 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearSystemSolver.cxx,v $ Language: C++ Date: $Date: 2005/03/04 11:07:29 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkLinearSystemSolver.h" #include "vtkvmtkConstants.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkLinearSystemSolver, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkLinearSystemSolver); vtkvmtkLinearSystemSolver::vtkvmtkLinearSystemSolver() { this->LinearSystem = NULL; this->MaximumNumberOfIterations = VTK_VMTK_LARGE_INTEGER; this->ConvergenceTolerance = 1E-4; this->NumberOfIterations = 0; this->Residual = VTK_VMTK_LARGE_DOUBLE; } vtkvmtkLinearSystemSolver::~vtkvmtkLinearSystemSolver() { if (this->LinearSystem) { this->LinearSystem->Delete(); this->LinearSystem = NULL; } } int vtkvmtkLinearSystemSolver::Solve() { if (this->LinearSystem==NULL) { vtkErrorMacro(<< "Linear system not set!"); return -1; } if (this->LinearSystem->CheckSystem()==-1) { return -1; } return 0; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataSurfaceRemeshing.h0000664000175000017500000001361611757446472025424 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataSurfaceRemeshing.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataSurfaceRemeshing - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataSurfaceRemeshing_h #define __vtkvmtkPolyDataSurfaceRemeshing_h #include "vtkObject.h" #include "vtkPolyDataAlgorithm.h" #include "vtkvmtkWin32Header.h" #include "vtkIdList.h" class vtkCellLocator; class vtkIntArray; class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataSurfaceRemeshing : public vtkPolyDataAlgorithm { public: static vtkvmtkPolyDataSurfaceRemeshing *New(); vtkTypeRevisionMacro(vtkvmtkPolyDataSurfaceRemeshing,vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent); vtkSetMacro(AspectRatioThreshold,double); vtkGetMacro(AspectRatioThreshold,double); vtkSetMacro(InternalAngleTolerance,double); vtkGetMacro(InternalAngleTolerance,double); vtkSetMacro(NormalAngleTolerance,double); vtkGetMacro(NormalAngleTolerance,double); vtkSetMacro(CollapseAngleThreshold,double); vtkGetMacro(CollapseAngleThreshold,double); vtkSetMacro(Relaxation,double); vtkGetMacro(Relaxation,double); vtkSetMacro(TargetArea,double); vtkGetMacro(TargetArea,double); vtkSetMacro(TargetAreaFactor,double); vtkGetMacro(TargetAreaFactor,double); vtkSetMacro(MinAreaFactor,double); vtkGetMacro(MinAreaFactor,double); vtkSetMacro(MaxArea,double); vtkGetMacro(MaxArea,double); vtkSetMacro(MinArea,double); vtkGetMacro(MinArea,double); vtkSetMacro(NumberOfIterations,int); vtkGetMacro(NumberOfIterations,int); vtkSetMacro(NumberOfConnectivityOptimizationIterations,int); vtkGetMacro(NumberOfConnectivityOptimizationIterations,int); vtkSetStringMacro(TargetAreaArrayName); vtkGetStringMacro(TargetAreaArrayName); vtkSetMacro(ElementSizeMode,int); vtkGetMacro(ElementSizeMode,int); void SetElementSizeModeToTargetArea() { this->SetElementSizeMode(TARGET_AREA); } void SetElementSizeModeToTargetAreaArray() { this->SetElementSizeMode(TARGET_AREA_ARRAY); } vtkSetMacro(PreserveBoundaryEdges,int); vtkGetMacro(PreserveBoundaryEdges,int); vtkBooleanMacro(PreserveBoundaryEdges,int); vtkSetStringMacro(CellEntityIdsArrayName); vtkGetStringMacro(CellEntityIdsArrayName); vtkSetObjectMacro(ExcludedEntityIds,vtkIdList); vtkGetObjectMacro(ExcludedEntityIds,vtkIdList); //BTX enum { SUCCESS = 0, EDGE_ON_BOUNDARY, EDGE_BETWEEN_ENTITIES, EDGE_LOCKED, NOT_EDGE, NON_MANIFOLD, NOT_TRIANGLES, DEGENERATE_TRIANGLES, TRIANGLE_LOCKED }; enum { DO_CHANGE, DO_NOTHING }; enum { TARGET_AREA, TARGET_AREA_ARRAY }; enum { RELOCATE_SUCCESS, RELOCATE_FAILURE }; enum { INTERNAL_POINT, POINT_ON_BOUNDARY, NO_NEIGHBORS }; //ETX protected: vtkvmtkPolyDataSurfaceRemeshing(); ~vtkvmtkPolyDataSurfaceRemeshing(); virtual int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); void BuildEntityBoundary(vtkPolyData* input, vtkPolyData* entityBoundary); int EdgeFlipConnectivityOptimizationIteration(); int EdgeFlipIteration(); int EdgeCollapseIteration(); int EdgeSplitIteration(); int PointRelocationIteration(bool projectToSurface=true); int TestFlipEdgeValidity(vtkIdType pt1, vtkIdType pt2, vtkIdType cell1, vtkIdType cell2, vtkIdType pt3, vtkIdType pt4); int TestConnectivityFlipEdge(vtkIdType pt1, vtkIdType pt2); int TestDelaunayFlipEdge(vtkIdType pt1, vtkIdType pt2); int TestAspectRatioCollapseEdge(vtkIdType cellId, vtkIdType& pt1, vtkIdType& pt2); int TestAreaSplitEdge(vtkIdType cellId, vtkIdType& pt1, vtkIdType& pt2); int IsElementExcluded(vtkIdType cellId); int GetEdgeCellsAndOppositeEdge(vtkIdType pt1, vtkIdType pt2, vtkIdType& cell1, vtkIdType& cell2, vtkIdType& pt3, vtkIdType& pt4); int SplitEdge(vtkIdType pt1, vtkIdType pt2); int CollapseEdge(vtkIdType pt1, vtkIdType pt2); int FlipEdge(vtkIdType pt1, vtkIdType pt2); int SplitTriangle(vtkIdType cellId); int CollapseTriangle(vtkIdType cellId); int RelocatePoint(vtkIdType pointId, bool projectToSurface); int IsPointOnBoundary(vtkIdType pointId); int IsPointOnEntityBoundary(vtkIdType pointId); int GetNumberOfBoundaryEdges(vtkIdType cellId); double ComputeTriangleTargetArea(vtkIdType cellId); int FindOneRingNeighbors(vtkIdType pointId, vtkIdList* neighborIds); vtkPolyData* Mesh; vtkPolyData* InputBoundary; vtkPolyData* InputEntityBoundary; vtkCellLocator* Locator; vtkCellLocator* BoundaryLocator; vtkCellLocator* EntityBoundaryLocator; vtkIntArray* CellEntityIdsArray; vtkDataArray* TargetAreaArray; vtkIdList* ExcludedEntityIds; double AspectRatioThreshold; double InternalAngleTolerance; double NormalAngleTolerance; double CollapseAngleThreshold; double Relaxation; int NumberOfConnectivityOptimizationIterations; int NumberOfIterations; int PreserveBoundaryEdges; int ElementSizeMode; double TargetArea; double TargetAreaFactor; double MaxArea; double MinArea; double MinAreaFactor; char* TargetAreaArrayName; char* CellEntityIdsArrayName; private: vtkvmtkPolyDataSurfaceRemeshing(const vtkvmtkPolyDataSurfaceRemeshing&); // Not implemented. void operator=(const vtkvmtkPolyDataSurfaceRemeshing&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkDoubleVector.cxx0000664000175000017500000001433511757446472023503 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkDoubleVector.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkDoubleVector.h" #include "vtkvmtkConstants.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkDoubleVector, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkDoubleVector); vtkvmtkDoubleVector::vtkvmtkDoubleVector() { this->NormType = VTK_VMTK_L2_NORM; this->NumberOfElements = 0; this->NumberOfElementsPerVariable = 0; this->NumberOfVariables = 0; this->Array = NULL; //this->Locked = NULL; } vtkvmtkDoubleVector::~vtkvmtkDoubleVector() { if (this->Array != NULL) { delete [] this->Array; this->Array = NULL; } //if (this->Locked != NULL) // { // delete [] this->Locked; // this->Locked = NULL; // } } void vtkvmtkDoubleVector::Allocate(vtkIdType numberOfElementsPerVariable, vtkIdType numberOfVariables) { if ( this->Array != NULL ) { delete [] this->Array; this->Array = NULL; } this->NumberOfElements = numberOfElementsPerVariable * numberOfVariables; this->NumberOfElementsPerVariable = numberOfElementsPerVariable; this->NumberOfVariables = numberOfVariables; this->Array = new double[this->NumberOfElements]; //this->Locked = new bool[this->NumberOfElements]; } void vtkvmtkDoubleVector::Fill(double value) { for (vtkIdType i=0; iNumberOfElements; i++) { this->Array[i] = value; } } //void vtkvmtkDoubleVector::UnlockAll() //{ // for (vtkIdType i=0; iNumberOfElements; i++) // { // this->Locked[i] = false; // } //} void vtkvmtkDoubleVector::Assign(vtkvmtkDoubleVector *src) { if (this->NumberOfElements != src->NumberOfElements) { vtkErrorMacro(<< "Vectors have different number of elements."); } this->NumberOfElements = src->NumberOfElements; memcpy(this->Array, src->Array, src->NumberOfElements * sizeof(double)); } void vtkvmtkDoubleVector::Assign(vtkIdType numberOfElements, const double *array) { this->NumberOfElements = numberOfElements; memcpy(this->Array, array, numberOfElements * sizeof(double)); } double vtkvmtkDoubleVector::ComputeNorm() { vtkIdType i; double norm = 0.0; double value; if (this->NormType==VTK_VMTK_L2_NORM) { norm = 0.0; for (i=0; iNumberOfElements; i++) { value = this->Array[i]; norm += value * value; } norm = sqrt(norm); } else if (this->NormType==VTK_VMTK_LINF_NORM) { norm = -VTK_VMTK_LARGE_DOUBLE; for (i=0; iNumberOfElements; i++) { value = this->Array[i]; if (value>norm) { norm = value; } } } return norm; } void vtkvmtkDoubleVector::Add(vtkvmtkDoubleVector* vectorToAdd) { if (this->NumberOfElements != vectorToAdd->NumberOfElements) { vtkErrorMacro(<< "Vector to add does not have the same number of elements."); return; } for (int i=0; iNumberOfElements; i++) { this->Array[i] += vectorToAdd->GetElement(i); } } void vtkvmtkDoubleVector::Subtract(vtkvmtkDoubleVector* vectorToSubtract) { if (this->NumberOfElements != vectorToSubtract->NumberOfElements) { vtkErrorMacro(<< "Vector to add does not have the same number of elements."); return; } for (int i=0; iNumberOfElements; i++) { this->Array[i] -= vectorToSubtract->GetElement(i); } } void vtkvmtkDoubleVector::MultiplyBy(double scalar) { for (int i=0; iNumberOfElements; i++) { this->Array[i] *= scalar; } } double vtkvmtkDoubleVector::Dot(vtkvmtkDoubleVector* vectorToDotWith) { double dot; if (this->NumberOfElements != vectorToDotWith->NumberOfElements) { vtkErrorMacro(<< "Vector to add does not have the same number of elements."); return 0.0; } dot = 0.0; for (int i=0; iNumberOfElements; i++) { dot += this->Array[i] * vectorToDotWith->Array[i]; } return dot; } void vtkvmtkDoubleVector::CopyIntoArrayComponent(vtkDataArray *array, int component) { vtkIdType i; if (array==NULL) { vtkErrorMacro(<<"NULL vtkDoubleArray provided!"); return; } if (component > array->GetNumberOfComponents()-1) { array->SetNumberOfComponents(component+1); } if (this->NumberOfElements>array->GetNumberOfTuples()) { array->SetNumberOfTuples(this->NumberOfElements); } for (i=0; iNumberOfElements; i++) { array->SetComponent(i,component,this->Array[i]); } } void vtkvmtkDoubleVector::CopyVariableIntoArrayComponent(vtkDataArray *array, int variable, int component) { vtkIdType i; if (array==NULL) { vtkErrorMacro(<<"NULL vtkDoubleArray provided!"); return; } if (component > array->GetNumberOfComponents()-1) { array->SetNumberOfComponents(component+1); } if (this->NumberOfElementsPerVariable > array->GetNumberOfTuples()) { array->SetNumberOfTuples(this->NumberOfElementsPerVariable); } for (i=0; iNumberOfElementsPerVariable; i++) { array->SetComponent(i,component,this->Array[i+variable*this->NumberOfElementsPerVariable]); } } void vtkvmtkDoubleVector::DeepCopy(vtkvmtkDoubleVector *src) { this->NumberOfElements = src->NumberOfElements; this->NumberOfElementsPerVariable = src->NumberOfElementsPerVariable; this->NumberOfVariables = src->NumberOfVariables; if (this->Array != NULL) { delete [] this->Array; this->Array = NULL; } this->Array = new double[src->NumberOfElements]; memcpy(this->Array, src->Array, src->NumberOfElements * sizeof(double)); // memcpy(this->Locked, src->Locked, src->NumberOfElements * sizeof(bool)); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridHarmonicMappingFilter.cxx0000664000175000017500000001216611757446472030566 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridHarmonicMappingFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridHarmonicMappingFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkUnstructuredGridFELaplaceAssembler.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkOpenNLLinearSystemSolver.h" #include "vtkvmtkDirichletBoundaryConditions.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridHarmonicMappingFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridHarmonicMappingFilter); vtkvmtkUnstructuredGridHarmonicMappingFilter::vtkvmtkUnstructuredGridHarmonicMappingFilter() { this->BoundaryPointIds = NULL; this->BoundaryValues = NULL; this->HarmonicMappingArrayName = NULL; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; } vtkvmtkUnstructuredGridHarmonicMappingFilter::~vtkvmtkUnstructuredGridHarmonicMappingFilter() { if (this->BoundaryPointIds) { this->BoundaryPointIds->Delete(); this->BoundaryPointIds = NULL; } if (this->BoundaryValues) { this->BoundaryValues->Delete(); this->BoundaryValues = NULL; } if (this->HarmonicMappingArrayName) { delete[] this->HarmonicMappingArrayName; this->HarmonicMappingArrayName = NULL; } } int vtkvmtkUnstructuredGridHarmonicMappingFilter::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())); if (!this->BoundaryPointIds) { vtkErrorMacro(<<"BoundaryPointIds not set."); return 1; } if (!this->BoundaryValues) { vtkErrorMacro(<<"BoundaryValues not set."); return 1; } if (!this->HarmonicMappingArrayName) { vtkErrorMacro(<<"HarmonicMappingArrayName not set."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); vtkvmtkSparseMatrix* sparseMatrix = vtkvmtkSparseMatrix::New(); vtkvmtkDoubleVector* rhsVector = vtkvmtkDoubleVector::New(); rhsVector->SetNormTypeToLInf(); vtkvmtkDoubleVector* solutionVector = vtkvmtkDoubleVector::New(); solutionVector->SetNormTypeToLInf(); vtkvmtkUnstructuredGridFELaplaceAssembler* assembler = vtkvmtkUnstructuredGridFELaplaceAssembler::New(); assembler->SetDataSet(input); assembler->SetMatrix(sparseMatrix); assembler->SetRHSVector(rhsVector); assembler->SetSolutionVector(solutionVector); assembler->SetQuadratureOrder(this->QuadratureOrder); assembler->Build(); vtkvmtkLinearSystem* linearSystem = vtkvmtkLinearSystem::New(); linearSystem->SetA(sparseMatrix); linearSystem->SetB(rhsVector); linearSystem->SetX(solutionVector); vtkvmtkDirichletBoundaryConditions* dirichetBoundaryConditions = vtkvmtkDirichletBoundaryConditions::New(); dirichetBoundaryConditions->SetLinearSystem(linearSystem); dirichetBoundaryConditions->SetBoundaryNodes(this->BoundaryPointIds); dirichetBoundaryConditions->SetBoundaryValues(this->BoundaryValues); dirichetBoundaryConditions->Apply(); vtkvmtkOpenNLLinearSystemSolver* solver = vtkvmtkOpenNLLinearSystemSolver::New(); solver->SetLinearSystem(linearSystem); solver->SetConvergenceTolerance(this->ConvergenceTolerance); solver->SetMaximumNumberOfIterations(numberOfInputPoints); solver->SetSolverTypeToCG(); solver->SetPreconditionerTypeToNone(); solver->Solve(); vtkDoubleArray* harmonicMappingArray = vtkDoubleArray::New(); harmonicMappingArray->SetName(this->HarmonicMappingArrayName); harmonicMappingArray->SetNumberOfComponents(1); harmonicMappingArray->SetNumberOfTuples(numberOfInputPoints); solutionVector->CopyIntoArrayComponent(harmonicMappingArray,0); output->DeepCopy(input); output->GetPointData()->AddArray(harmonicMappingArray); assembler->Delete(); solver->Delete(); harmonicMappingArray->Delete(); sparseMatrix->Delete(); rhsVector->Delete(); solutionVector->Delete(); linearSystem->Delete(); dirichetBoundaryConditions->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkNeighborhoods.cxx0000664000175000017500000000416411757446472023677 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkNeighborhoods.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkNeighborhoods.h" #include "vtkObjectFactory.h" #include "vtkIdList.h" #include "vtkCell.h" #include "vtkvmtkEmptyNeighborhood.h" #include "vtkvmtkPolyDataNeighborhood.h" #include "vtkvmtkPolyDataManifoldNeighborhood.h" #include "vtkvmtkPolyDataManifoldExtendedNeighborhood.h" #include "vtkvmtkUnstructuredGridNeighborhood.h" vtkCxxRevisionMacro(vtkvmtkNeighborhoods, "$Revision: 1.3 $"); vtkStandardNewMacro(vtkvmtkNeighborhoods); vtkvmtkItem* vtkvmtkNeighborhoods::InstantiateNewItem(int itemType) { vtkvmtkNeighborhood* newItem; switch(itemType) { case VTK_VMTK_EMPTY_NEIGHBORHOOD: newItem = vtkvmtkEmptyNeighborhood::New(); break; case VTK_VMTK_POLYDATA_NEIGHBORHOOD: newItem = vtkvmtkPolyDataNeighborhood::New(); break; case VTK_VMTK_POLYDATA_MANIFOLD_NEIGHBORHOOD: newItem = vtkvmtkPolyDataManifoldNeighborhood::New(); break; case VTK_VMTK_POLYDATA_MANIFOLD_EXTENDED_NEIGHBORHOOD: newItem = vtkvmtkPolyDataManifoldExtendedNeighborhood::New(); break; case VTK_VMTK_UNSTRUCTUREDGRID_NEIGHBORHOOD: newItem = vtkvmtkUnstructuredGridNeighborhood::New(); break; default: vtkErrorMacro(<<"Invalid neighborhood type"); return NULL; } newItem->SetReallocateOnBuild(this->ReallocateOnBuild); newItem->Register(this); newItem->Delete(); return newItem; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataDiscreteElasticaFilter.cxx0000664000175000017500000004367611757446472027134 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataDiscreteElasticaFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.5 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataDiscreteElasticaFilter.h" #include "vtkvmtkPolyDataManifoldNeighborhood.h" #include "vtkPolyDataNormals.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkMath.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataDiscreteElasticaFilter, "$Revision: 1.5 $"); vtkStandardNewMacro(vtkvmtkPolyDataDiscreteElasticaFilter); vtkvmtkPolyDataDiscreteElasticaFilter::vtkvmtkPolyDataDiscreteElasticaFilter() { } vtkvmtkPolyDataDiscreteElasticaFilter::~vtkvmtkPolyDataDiscreteElasticaFilter() { } #define CURVATURES #ifdef CURVATURES #include "vtkCurvatures.h" #if 0 int vtkvmtkPolyDataDiscreteElasticaFilter::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())); vtkPolyData* surface = vtkPolyData::New(); surface->DeepCopy(input); vtkPolyDataNormals* normalsFilter = vtkPolyDataNormals::New(); normalsFilter->SetInput(surface); normalsFilter->FlipNormalsOff(); normalsFilter->ConsistencyOn(); normalsFilter->ComputePointNormalsOn(); normalsFilter->ComputeCellNormalsOn(); vtkCurvatures* curvaturesFilter = vtkCurvatures::New(); curvaturesFilter->SetInput(surface); // curvaturesFilter->InvertMeanCurvatureOn(); vtkvmtkPolyDataManifoldNeighborhood* neighborhood = vtkvmtkPolyDataManifoldNeighborhood::New(); neighborhood->SetDataSet(surface); int numberOfPoints = surface->GetNumberOfPoints(); vtkPoints* newPoints = vtkPoints::New(); newPoints->SetNumberOfPoints(numberOfPoints); vtkDoubleArray* meanCurvatureArray = vtkDoubleArray::New(); vtkDoubleArray* gaussianCurvatureArray = vtkDoubleArray::New(); double deltaT = 1.0; int numberOfIterations = 1000; for (int n=0; nModified(); curvaturesFilter->SetCurvatureTypeToMean(); curvaturesFilter->Update(); meanCurvatureArray->DeepCopy(curvaturesFilter->GetOutput()->GetPointData()->GetScalars()); curvaturesFilter->SetCurvatureTypeToGaussian(); curvaturesFilter->Update(); gaussianCurvatureArray->DeepCopy(curvaturesFilter->GetOutput()->GetPointData()->GetScalars()); normalsFilter->Update(); vtkDataArray* normals = normalsFilter->GetOutput()->GetPointData()->GetNormals(); newPoints->DeepCopy(surface->GetPoints()); double minTriangleArea = 1E8; for (int i=0; iSetDataSetPointId(i); neighborhood->Build(); if (neighborhood->GetIsBoundary()) { continue; } double point[3]; surface->GetPoint(i,point); if (surface->GetPointData()->GetArray("Clamp")->GetTuple1(i) > 0.5) { newPoints->SetPoint(i,point); continue; } double meanCurvature = meanCurvatureArray->GetTuple1(i); double gaussianCurvature = gaussianCurvatureArray->GetTuple1(i); double laplaceBeltramiH = 0.0; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); double weight = 1.0 / double(numberOfNeighborhoodPoints); for (int j=0; jGetTuple1(neighborhood->GetPointId(j)); laplaceBeltramiH += weight * (neighborMeanCurvature - meanCurvature); } double point1[3], point2[3]; double area = 0.0; double triangleArea; for (int j=0; jGetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); triangleArea = vtkvmtkMath::TriangleArea(point,point1,point2); area += triangleArea; if (triangleArea < minTriangleArea) { minTriangleArea = triangleArea; } } double normal[3]; normals->GetTuple(i,normal); double newPoint[3]; newPoint[0] = point[0]; newPoint[1] = point[1]; newPoint[2] = point[2]; double f = laplaceBeltramiH - 2.0 * meanCurvature * (meanCurvature*meanCurvature - gaussianCurvature); if (meanCurvature*meanCurvature - gaussianCurvature < 0.0) { f = laplaceBeltramiH; } // f = laplaceBeltramiH; // cout<SetPoint(i,newPoint); } cout<GetPoints()->DeepCopy(newPoints); } output->DeepCopy(surface); curvaturesFilter->Delete(); normalsFilter->Delete(); neighborhood->Delete(); meanCurvatureArray->Delete(); gaussianCurvatureArray->Delete(); surface->Delete(); newPoints->Delete(); return 1; } #endif int vtkvmtkPolyDataDiscreteElasticaFilter::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())); vtkPolyData* surface = vtkPolyData::New(); surface->DeepCopy(input); vtkPolyDataNormals* normalsFilter = vtkPolyDataNormals::New(); normalsFilter->SetInput(surface); normalsFilter->FlipNormalsOff(); normalsFilter->ConsistencyOn(); normalsFilter->ComputePointNormalsOn(); normalsFilter->ComputeCellNormalsOn(); vtkCurvatures* curvaturesFilter = vtkCurvatures::New(); curvaturesFilter->SetInput(surface); // curvaturesFilter->InvertMeanCurvatureOn(); vtkvmtkPolyDataManifoldNeighborhood* neighborhood = vtkvmtkPolyDataManifoldNeighborhood::New(); neighborhood->SetDataSet(surface); int numberOfPoints = surface->GetNumberOfPoints(); vtkPoints* newPoints = vtkPoints::New(); newPoints->SetNumberOfPoints(numberOfPoints); vtkDoubleArray* meanCurvatureArray = vtkDoubleArray::New(); double deltaT = 1.0; int numberOfIterations = 100; for (int n=0; nModified(); curvaturesFilter->SetCurvatureTypeToMean(); curvaturesFilter->Update(); meanCurvatureArray->DeepCopy(curvaturesFilter->GetOutput()->GetPointData()->GetScalars()); normalsFilter->Update(); vtkDataArray* normals = normalsFilter->GetOutput()->GetPointData()->GetNormals(); newPoints->DeepCopy(surface->GetPoints()); double minTriangleArea = 1E8; for (int i=0; iSetDataSetPointId(i); neighborhood->Build(); if (neighborhood->GetIsBoundary()) { continue; } double point[3]; surface->GetPoint(i,point); if (surface->GetPointData()->GetArray("Clamp")->GetTuple1(i) > 0.5) { newPoints->SetPoint(i,point); continue; } double meanCurvature = meanCurvatureArray->GetTuple1(i); double laplaceH = 0.0; double neighborPoint[3]; double laplace[3]; laplace[0] = laplace[1] = laplace[2] = 0.0; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); double weight = 1.0 / double(numberOfNeighborhoodPoints); for (int j=0; jGetTuple1(neighborhood->GetPointId(j)); laplaceH += weight * (neighborMeanCurvature - meanCurvature); surface->GetPoint(neighborhood->GetPointId(j),neighborPoint); laplace[0] += weight * (neighborPoint[0] - point[0]); laplace[1] += weight * (neighborPoint[1] - point[1]); laplace[2] += weight * (neighborPoint[2] - point[2]); } double point1[3], point2[3]; double area = 0.0; double triangleArea; for (int j=0; jGetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); triangleArea = vtkvmtkMath::TriangleArea(point,point1,point2); area += triangleArea; if (triangleArea < minTriangleArea) { minTriangleArea = triangleArea; } } double normal[3]; normals->GetTuple(i,normal); double newPoint[3]; newPoint[0] = point[0]; newPoint[1] = point[1]; newPoint[2] = point[2]; deltaT = minTriangleArea / 10.0; // newPoint[0] += deltaT * laplaceH * normal[0]; // newPoint[1] += deltaT * laplaceH * normal[1]; // newPoint[2] += deltaT * laplaceH * normal[2]; // deltaT = 1E0; double alpha = 1.0; double beta = 0.0; newPoint[0] += deltaT * (alpha * laplaceH * normal[0] + beta * laplace[0]); newPoint[1] += deltaT * (alpha * laplaceH * normal[1] + beta * laplace[1]); newPoint[2] += deltaT * (alpha * laplaceH * normal[2] + beta * laplace[2]); newPoints->SetPoint(i,newPoint); } cout<GetPoints()->DeepCopy(newPoints); } output->DeepCopy(surface); curvaturesFilter->Delete(); normalsFilter->Delete(); neighborhood->Delete(); meanCurvatureArray->Delete(); surface->Delete(); newPoints->Delete(); return 1; } #else int vtkvmtkPolyDataDiscreteElasticaFilter::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())); vtkPolyData* surface = vtkPolyData::New(); surface->DeepCopy(input); vtkPolyDataNormals* normalsFilter = vtkPolyDataNormals::New(); normalsFilter->SetInput(surface); normalsFilter->FlipNormalsOff(); normalsFilter->ConsistencyOn(); normalsFilter->ComputePointNormalsOn(); normalsFilter->ComputeCellNormalsOn(); vtkvmtkPolyDataManifoldNeighborhood* neighborhood = vtkvmtkPolyDataManifoldNeighborhood::New(); neighborhood->SetDataSet(surface); // Explicit filtering (not Gauss-Seidel) // For each iteration // 1. Compute normals // 2. Compute mean curvature (using laplace beltrami) and store it in an array // 3. Compute F by computing laplace beltrami of mean curvature, mean curvature and Gauss curvature // P_i^{k+1} = P_i^k + \tau^k * F_i^k * N_i^k // F = - \Delta_B H - 2 H (H^2 - K) // H = 0.5 * N * \Delta_B P // K = 3 / A * (2\pi - \sum_i \phi_i) // \tau_k = A_k^2 / 150 // A_k: minimal triangle area int numberOfPoints = surface->GetNumberOfPoints(); vtkPoints* newPoints = vtkPoints::New(); newPoints->SetNumberOfPoints(numberOfPoints); vtkDoubleArray* meanCurvatureArray = vtkDoubleArray::New(); meanCurvatureArray->SetNumberOfTuples(numberOfPoints); double deltaT = 1.0; int numberOfIterations = 300; for (int n=0; nModified(); normalsFilter->Update(); vtkDataArray* normals = normalsFilter->GetOutput()->GetPointData()->GetNormals(); newPoints->DeepCopy(surface->GetPoints()); double minTriangleArea = 1E8; for (int i=0; iSetDataSetPointId(i); neighborhood->Build(); if (neighborhood->GetIsBoundary()) { continue; } double normal[3]; normals->GetTuple(i,normal); double point[3]; surface->GetPoint(i,point); double laplaceBeltrami[3]; laplaceBeltrami[0] = 0.0; laplaceBeltrami[1] = 0.0; laplaceBeltrami[2] = 0.0; double point0[3], point1[3], point2[3]; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); for (int j=0; jGetPoint(neighborhood->GetPointId((j-1+numberOfNeighborhoodPoints)%numberOfNeighborhoodPoints),point0); surface->GetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); double weight = vtkvmtkMath::Cotangent(point,point0,point1) + vtkvmtkMath::Cotangent(point,point2,point1); laplaceBeltrami[0] += weight * (point1[0] - point[0]); laplaceBeltrami[1] += weight * (point1[1] - point[1]); laplaceBeltrami[2] += weight * (point1[2] - point[2]); } double area = 0.0; double triangleArea; for (int j=0; jGetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); triangleArea = vtkvmtkMath::TriangleArea(point,point1,point2); area += triangleArea; if (triangleArea < minTriangleArea) { minTriangleArea = triangleArea; } } laplaceBeltrami[0] *= 3.0 / area; laplaceBeltrami[1] *= 3.0 / area; laplaceBeltrami[2] *= 3.0 / area; double meanCurvature = 0.5 * vtkMath::Dot(normal,laplaceBeltrami); meanCurvatureArray->SetTuple1(i,meanCurvature); } for (int i=0; iSetDataSetPointId(i); neighborhood->Build(); if (neighborhood->GetIsBoundary()) { continue; } double normal[3]; normals->GetTuple(i,normal); double point[3]; surface->GetPoint(i,point); double meanCurvature = meanCurvatureArray->GetTuple1(i); double laplaceBeltramiH = 0.0; double point0[3], point1[3], point2[3]; int numberOfNeighborhoodPoints = neighborhood->GetNumberOfPoints(); for (int j=0; jGetPoint(neighborhood->GetPointId((j-1+numberOfNeighborhoodPoints)%numberOfNeighborhoodPoints),point0); surface->GetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); double weight = vtkvmtkMath::Cotangent(point,point0,point1) + vtkvmtkMath::Cotangent(point,point2,point1); double neighborMeanCurvature = meanCurvatureArray->GetTuple1(neighborhood->GetPointId(j)); laplaceBeltramiH += weight * (neighborMeanCurvature - meanCurvature); } double area = 0.0; for (int j=0; jGetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); area += vtkvmtkMath::TriangleArea(point,point1,point2); } laplaceBeltramiH *= 3.0 / area; double newPoint[3]; newPoint[0] = point[0]; newPoint[1] = point[1]; newPoint[2] = point[2]; double normal1[3], normal2[3]; double angleSum = 0.0; for (int j=0; jGetPoint(neighborhood->GetPointId(j),point1); surface->GetPoint(neighborhood->GetPointId((j+1)%numberOfNeighborhoodPoints),point2); normal1[0] = point1[0] - point[0]; normal1[1] = point1[1] - point[1]; normal1[2] = point1[2] - point[2]; vtkMath::Normalize(normal1); normal2[0] = point2[0] - point[0]; normal2[1] = point2[1] - point[1]; normal2[2] = point2[2] - point[2]; vtkMath::Normalize(normal2); angleSum += vtkvmtkMath::AngleBetweenNormals(normal1,normal2); } double gaussianCurvature = 3.0 / area * (2.0 * vtkMath::Pi() - angleSum); double f = - laplaceBeltramiH - 2.0 * meanCurvature * (meanCurvature*meanCurvature - gaussianCurvature); if (meanCurvature*meanCurvature - gaussianCurvature < 0.0) { f = - laplaceBeltramiH; } // f = - meanCurvature; // cout<SetPoint(i,newPoint); } cout<GetPoints()->DeepCopy(newPoints); } output->DeepCopy(surface); normalsFilter->Delete(); neighborhood->Delete(); meanCurvatureArray->Delete(); surface->Delete(); newPoints->Delete(); return 1; } #endif void vtkvmtkPolyDataDiscreteElasticaFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkFEAssembler.h0000664000175000017500000000432011757446472022654 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkFEAssembler.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkFEAssembler - .. // .SECTION Description // .. #ifndef __vtkvmtkFEAssembler_h #define __vtkvmtkFEAssembler_h #include "vtkObject.h" #include "vtkPolyData.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkFEAssembler : public vtkObject { public: vtkTypeRevisionMacro(vtkvmtkFEAssembler,vtkObject); vtkSetObjectMacro(DataSet,vtkDataSet); vtkGetObjectMacro(DataSet,vtkDataSet); vtkSetObjectMacro(Matrix,vtkvmtkSparseMatrix); vtkGetObjectMacro(Matrix,vtkvmtkSparseMatrix); vtkSetObjectMacro(RHSVector,vtkvmtkDoubleVector); vtkGetObjectMacro(RHSVector,vtkvmtkDoubleVector); vtkSetObjectMacro(SolutionVector,vtkvmtkDoubleVector); vtkGetObjectMacro(SolutionVector,vtkvmtkDoubleVector); vtkGetMacro(NumberOfVariables,int); vtkSetMacro(QuadratureOrder,int); vtkGetMacro(QuadratureOrder,int); virtual void Build() = 0; void DeepCopy(vtkvmtkFEAssembler *src); void ShallowCopy(vtkvmtkFEAssembler *src); protected: vtkvmtkFEAssembler(); ~vtkvmtkFEAssembler(); void Initialize(int numberOfVariables); vtkDataSet* DataSet; vtkvmtkSparseMatrix* Matrix; vtkvmtkDoubleVector* RHSVector; vtkvmtkDoubleVector* SolutionVector; int NumberOfVariables; int QuadratureOrder; private: vtkvmtkFEAssembler(const vtkvmtkFEAssembler&); // Not implemented. void operator=(const vtkvmtkFEAssembler&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkLinearSystemSolver.h0000664000175000017500000000361511757446472024344 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkLinearSystemSolver.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:43 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkLinearSystemSolver - .. // .SECTION Description // .. #ifndef __vtkvmtkLinearSystemSolver_h #define __vtkvmtkLinearSystemSolver_h #include "vtkObject.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkLinearSystemSolver : public vtkObject { public: static vtkvmtkLinearSystemSolver* New(); vtkTypeRevisionMacro(vtkvmtkLinearSystemSolver,vtkObject); vtkSetObjectMacro(LinearSystem,vtkvmtkLinearSystem); vtkGetObjectMacro(LinearSystem,vtkvmtkLinearSystem); vtkSetMacro(MaximumNumberOfIterations,int); vtkGetMacro(MaximumNumberOfIterations,int); vtkSetMacro(ConvergenceTolerance,double); vtkGetMacro(ConvergenceTolerance,double); virtual int Solve(); protected: vtkvmtkLinearSystemSolver(); ~vtkvmtkLinearSystemSolver(); vtkvmtkLinearSystem* LinearSystem; int MaximumNumberOfIterations; double ConvergenceTolerance; int NumberOfIterations; double Residual; private: vtkvmtkLinearSystemSolver(const vtkvmtkLinearSystemSolver&); // Not implemented. void operator=(const vtkvmtkLinearSystemSolver&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataGradientStencil.cxx0000664000175000017500000000754711757446472025632 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataGradientStencil.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataGradientStencil.h" #include "vtkPolyData.h" #include "vtkvmtkMath.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkvmtkConstants.h" vtkCxxRevisionMacro(vtkvmtkPolyDataGradientStencil, "$Revision: 1.4 $"); vtkStandardNewMacro(vtkvmtkPolyDataGradientStencil); vtkvmtkPolyDataGradientStencil::vtkvmtkPolyDataGradientStencil() { this->Area = 0.0; this->NumberOfComponents = 3; } void vtkvmtkPolyDataGradientStencil::ScaleWithArea() { this->ScaleWithAreaFactor(1.0); } void vtkvmtkPolyDataGradientStencil::Gamma(double p0[3], double p1[3], double p2[3], double gamma[3]) { double p01[3], p12[3], p20[3]; p01[0] = p0[0] - p1[0]; p01[1] = p0[1] - p1[1]; p01[2] = p0[2] - p1[2]; p12[0] = p1[0] - p2[0]; p12[1] = p1[1] - p2[1]; p12[2] = p1[2] - p2[2]; p20[0] = p2[0] - p0[0]; p20[1] = p2[1] - p0[1]; p20[2] = p2[2] - p0[2]; double dot = vtkMath::Dot(p01,p12); gamma[0] = dot * p20[0]; gamma[1] = dot * p20[1]; gamma[2] = dot * p20[2]; } void vtkvmtkPolyDataGradientStencil::Build() { double point[3], point1[3], point2[3]; vtkIdType j, firstId, lastId; this->Superclass::Build(); vtkPolyData* pdata = vtkPolyData::SafeDownCast(this->DataSet); if (!this->IsBoundary) { firstId = 0; lastId = this->NPoints-1; } else { firstId = 0; lastId = this->NPoints-2; } pdata->GetPoint(this->DataSetPointId,point); for (j=0; j<3*this->NPoints; j++) this->Weights[j] = 0.0; this->CenterWeight[0] = 0.0; this->CenterWeight[1] = 0.0; this->CenterWeight[2] = 0.0; double gamma[3]; for (j=firstId; j<=lastId; j++) { pdata->GetPoint(this->PointIds[j],point1); int jplus = (j+1) % this->NPoints; pdata->GetPoint(this->PointIds[jplus],point2); double areaWeight = 1.0 / (4.0 * vtkvmtkMath::TriangleArea(point,point1,point2)); this->Gamma(point,point1,point2,gamma); this->CenterWeight[0] += gamma[0] * areaWeight; this->CenterWeight[1] += gamma[1] * areaWeight; this->CenterWeight[2] += gamma[2] * areaWeight; this->Gamma(point,point2,point1,gamma); this->CenterWeight[0] += gamma[0] * areaWeight; this->CenterWeight[1] += gamma[1] * areaWeight; this->CenterWeight[2] += gamma[2] * areaWeight; this->Gamma(point1,point,point2,gamma); this->Weights[3*j+0] += gamma[0] * areaWeight; this->Weights[3*j+1] += gamma[1] * areaWeight; this->Weights[3*j+2] += gamma[2] * areaWeight; this->Gamma(point1,point2,point,gamma); this->Weights[3*j+0] += gamma[0] * areaWeight; this->Weights[3*j+1] += gamma[1] * areaWeight; this->Weights[3*j+2] += gamma[2] * areaWeight; this->Gamma(point2,point1,point,gamma); this->Weights[3*jplus+0] += gamma[0] * areaWeight; this->Weights[3*jplus+1] += gamma[1] * areaWeight; this->Weights[3*jplus+2] += gamma[2] * areaWeight; this->Gamma(point2,point,point1,gamma); this->Weights[3*jplus+0] += gamma[0] * areaWeight; this->Weights[3*jplus+1] += gamma[1] * areaWeight; this->Weights[3*jplus+2] += gamma[2] * areaWeight; } this->ComputeArea(); this->ScaleWithArea(); } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkUnstructuredGridGradientFilter.cxx0000664000175000017500000001553411757446472027251 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkUnstructuredGridGradientFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkUnstructuredGridGradientFilter.h" #include "vtkUnstructuredGrid.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkUnstructuredGridFEGradientAssembler.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkOpenNLLinearSystemSolver.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkUnstructuredGridGradientFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkUnstructuredGridGradientFilter); vtkvmtkUnstructuredGridGradientFilter::vtkvmtkUnstructuredGridGradientFilter() { this->InputArrayName = NULL; this->GradientArrayName = NULL; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; this->ComputeIndividualPartialDerivatives = 0; } vtkvmtkUnstructuredGridGradientFilter::~vtkvmtkUnstructuredGridGradientFilter() { if (this->InputArrayName) { delete[] this->InputArrayName; this->InputArrayName = NULL; } if (this->GradientArrayName) { delete[] this->GradientArrayName; this->GradientArrayName = NULL; } } int vtkvmtkUnstructuredGridGradientFilter::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())); if (!this->InputArrayName) { vtkErrorMacro(<<"InputArrayName not set."); return 1; } if (!this->GradientArrayName) { vtkErrorMacro(<<"GradientArrayName not set."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); vtkDataArray* inputArray = input->GetPointData()->GetArray(this->InputArrayName); if (!inputArray) { vtkErrorMacro("InputArray with name specified doesn not exist!"); return 0; } int numberOfInputComponents = inputArray->GetNumberOfComponents(); vtkDoubleArray* gradientArray = vtkDoubleArray::New(); gradientArray->SetName(this->GradientArrayName); gradientArray->SetNumberOfComponents(3*numberOfInputComponents); gradientArray->SetNumberOfTuples(numberOfInputPoints); int i; for (i=0; iSetNormTypeToLInf(); vtkvmtkDoubleVector* solutionVector = vtkvmtkDoubleVector::New(); solutionVector->SetNormTypeToLInf(); if (!this->ComputeIndividualPartialDerivatives) { vtkvmtkUnstructuredGridFEGradientAssembler* assembler = vtkvmtkUnstructuredGridFEGradientAssembler::New(); assembler->SetDataSet(input); assembler->SetScalarsArrayName(this->InputArrayName); assembler->SetScalarsComponent(i); assembler->SetMatrix(sparseMatrix); assembler->SetRHSVector(rhsVector); assembler->SetSolutionVector(solutionVector); assembler->SetQuadratureOrder(this->QuadratureOrder); assembler->SetAssemblyModeToGradient(); cout<<"Assembling system"<Build(); cout<<"Done"<SetA(sparseMatrix); linearSystem->SetB(rhsVector); linearSystem->SetX(solutionVector); vtkvmtkOpenNLLinearSystemSolver* solver = vtkvmtkOpenNLLinearSystemSolver::New(); solver->SetLinearSystem(linearSystem); solver->SetConvergenceTolerance(this->ConvergenceTolerance); solver->SetMaximumNumberOfIterations(numberOfInputPoints); solver->SetSolverTypeToCG(); solver->SetPreconditionerTypeToJacobi(); cout<<"Solving system"<Solve(); cout<<"Done"<CopyVariableIntoArrayComponent(gradientArray,0,3*i+0); solutionVector->CopyVariableIntoArrayComponent(gradientArray,1,3*i+1); solutionVector->CopyVariableIntoArrayComponent(gradientArray,2,3*i+2); assembler->Delete(); linearSystem->Delete(); solver->Delete(); } else { int j; for (j=0; j<3; j++) { vtkvmtkUnstructuredGridFEGradientAssembler* assembler = vtkvmtkUnstructuredGridFEGradientAssembler::New(); assembler->SetDataSet(input); assembler->SetScalarsArrayName(this->InputArrayName); assembler->SetScalarsComponent(i); assembler->SetMatrix(sparseMatrix); assembler->SetRHSVector(rhsVector); assembler->SetSolutionVector(solutionVector); assembler->SetQuadratureOrder(this->QuadratureOrder); assembler->SetAssemblyModeToPartialDerivative(); assembler->SetDirection(j); cout<<"Assembling system"<Build(); cout<<"Done"<SetA(sparseMatrix); linearSystem->SetB(rhsVector); linearSystem->SetX(solutionVector); vtkvmtkOpenNLLinearSystemSolver* solver = vtkvmtkOpenNLLinearSystemSolver::New(); solver->SetLinearSystem(linearSystem); solver->SetConvergenceTolerance(this->ConvergenceTolerance); solver->SetMaximumNumberOfIterations(numberOfInputPoints); solver->SetSolverTypeToCG(); solver->SetPreconditionerTypeToJacobi(); cout<<"Solving system"<Solve(); cout<<"Done"<CopyIntoArrayComponent(gradientArray,3*i+j); assembler->Delete(); linearSystem->Delete(); solver->Delete(); } } solutionVector->Delete(); rhsVector->Delete(); sparseMatrix->Delete(); } output->DeepCopy(input); output->GetPointData()->AddArray(gradientArray); gradientArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkSparseMatrixRow.h0000664000175000017500000000460111757446472023640 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkSparseMatrixRow.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.3 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 - .. // .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(); vtkTypeRevisionMacro(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 vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataFEGradientAssembler.h0000664000175000017500000000340711757446472025775 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataFEGradientAssembler.h,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 vtkvmtkPolyDataFEGradientAssembler - .. // .SECTION Description // .. #ifndef __vtkvmtkPolyDataFEGradientAssembler_h #define __vtkvmtkPolyDataFEGradientAssembler_h #include "vtkvmtkFEAssembler.h" #include "vtkvmtkWin32Header.h" class VTK_VMTK_DIFFERENTIAL_GEOMETRY_EXPORT vtkvmtkPolyDataFEGradientAssembler : public vtkvmtkFEAssembler { public: static vtkvmtkPolyDataFEGradientAssembler* New(); vtkTypeRevisionMacro(vtkvmtkPolyDataFEGradientAssembler,vtkvmtkFEAssembler); virtual void Build(); vtkSetStringMacro(ScalarsArrayName); vtkGetStringMacro(ScalarsArrayName); vtkSetMacro(ScalarsComponent,int); vtkGetMacro(ScalarsComponent,int); protected: vtkvmtkPolyDataFEGradientAssembler(); ~vtkvmtkPolyDataFEGradientAssembler(); char* ScalarsArrayName; int ScalarsComponent; private: vtkvmtkPolyDataFEGradientAssembler(const vtkvmtkPolyDataFEGradientAssembler&); // Not implemented. void operator=(const vtkvmtkPolyDataFEGradientAssembler&); // Not implemented. }; #endif vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkEmptyStencil.cxx0000664000175000017500000000254311757446472023524 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkEmptyStencil.cxx,v $ Language: C++ Date: $Date: 2005/11/15 17:39:25 $ Version: $Revision: 1.4 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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" vtkCxxRevisionMacro(vtkvmtkEmptyStencil, "$Revision: 1.4 $"); 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; } } vmtk-1.0.1/vtkVmtk/DifferentialGeometry/vtkvmtkPolyDataGradientFilter.cxx0000664000175000017500000001151511757446472025444 0ustar lucaluca/*========================================================================= Program: VMTK Module: $RCSfile: vtkvmtkPolyDataGradientFilter.cxx,v $ Language: C++ Date: $Date: 2006/04/06 16:46:44 $ Version: $Revision: 1.7 $ Copyright (c) Luca Antiga, David Steinman. All rights reserved. See LICENCE 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 "vtkvmtkPolyDataGradientFilter.h" #include "vtkPolyData.h" #include "vtkPointData.h" #include "vtkDoubleArray.h" #include "vtkvmtkDoubleVector.h" #include "vtkvmtkPolyDataFEGradientAssembler.h" #include "vtkvmtkSparseMatrix.h" #include "vtkvmtkLinearSystem.h" #include "vtkvmtkOpenNLLinearSystemSolver.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" vtkCxxRevisionMacro(vtkvmtkPolyDataGradientFilter, "$Revision: 1.7 $"); vtkStandardNewMacro(vtkvmtkPolyDataGradientFilter); vtkvmtkPolyDataGradientFilter::vtkvmtkPolyDataGradientFilter() { this->InputArrayName = NULL; this->GradientArrayName = NULL; this->ConvergenceTolerance = 1E-6; this->QuadratureOrder = 3; } vtkvmtkPolyDataGradientFilter::~vtkvmtkPolyDataGradientFilter() { if (this->InputArrayName) { delete[] this->InputArrayName; this->InputArrayName = NULL; } if (this->GradientArrayName) { delete[] this->GradientArrayName; this->GradientArrayName = NULL; } } int vtkvmtkPolyDataGradientFilter::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->InputArrayName) { vtkErrorMacro(<<"InputArrayName not set."); return 1; } if (!this->GradientArrayName) { vtkErrorMacro(<<"GradientArrayName not set."); return 1; } int numberOfInputPoints = input->GetNumberOfPoints(); vtkDataArray* inputArray = input->GetPointData()->GetArray(this->InputArrayName); if (!inputArray) { vtkErrorMacro("InputArray with name specified doesn not exist!"); return 0; } int numberOfInputComponents = inputArray->GetNumberOfComponents(); vtkDoubleArray* gradientArray = vtkDoubleArray::New(); gradientArray->SetName(this->GradientArrayName); gradientArray->SetNumberOfComponents(3*numberOfInputComponents); gradientArray->SetNumberOfTuples(numberOfInputPoints); int i; for (i=0; iSetNormTypeToLInf(); vtkvmtkDoubleVector* solutionVector = vtkvmtkDoubleVector::New(); solutionVector->SetNormTypeToLInf(); vtkvmtkPolyDataFEGradientAssembler* assembler = vtkvmtkPolyDataFEGradientAssembler::New(); assembler->SetDataSet(input); assembler->SetScalarsArrayName(this->InputArrayName); assembler->SetScalarsComponent(i); assembler->SetMatrix(sparseMatrix); assembler->SetRHSVector(rhsVector); assembler->SetSolutionVector(solutionVector); assembler->SetQuadratureOrder(this->QuadratureOrder); assembler->Build(); assembler->Delete(); vtkvmtkLinearSystem* linearSystem = vtkvmtkLinearSystem::New(); linearSystem->SetA(sparseMatrix); linearSystem->SetB(rhsVector); linearSystem->SetX(solutionVector); vtkvmtkOpenNLLinearSystemSolver* solver = vtkvmtkOpenNLLinearSystemSolver::New(); solver->SetLinearSystem(linearSystem); solver->SetConvergenceTolerance(this->ConvergenceTolerance); solver->SetMaximumNumberOfIterations(numberOfInputPoints); solver->SetSolverTypeToCG(); solver->SetPreconditionerTypeToJacobi(); solver->Solve(); solutionVector->CopyVariableIntoArrayComponent(gradientArray,0,3*i+0); solutionVector->CopyVariableIntoArrayComponent(gradientArray,1,3*i+1); solutionVector->CopyVariableIntoArrayComponent(gradientArray,2,3*i+2); sparseMatrix->Delete(); rhsVector->Delete(); linearSystem->Delete(); solver->Delete(); solutionVector->Delete(); } output->DeepCopy(input); output->GetPointData()->AddArray(gradientArray); gradientArray->Delete(); return 1; } vmtk-1.0.1/vtkVmtk/CMakeOptions.cmake0000664000175000017500000001132711757446472016157 0ustar lucaluca# # 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) #this is a hack to make DICOMParser be included correctly - VTK source # INCLUDE_DIRECTORIES(BEFORE ${VTK_SOURCE_DIR}/Utilities/DICOMParser) 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) #ELSE (EXISTS ${VTK_DIR}/bin) #this is a hack to make DICOMParser be included correctly - VTK install # INCLUDE_DIRECTORIES(BEFORE ${VTK_INCLUDE_DIRS}) 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). # # # Tcl # IF (VTK_WRAP_TCL) OPTION(VTK_VMTK_WRAP_TCL "Wrap classes into the TCL interpreted language." ON) IF(VTK_VMTK_WRAP_TCL) SET(VTK_WRAP_TCL3_INIT_DIR "${VTK_VMTK_SOURCE_DIR}/Wrapping") INCLUDE(${VTK_CMAKE_DIR}/vtkWrapTcl.cmake) ENDIF(VTK_VMTK_WRAP_TCL) ELSE (VTK_WRAP_TCL) IF (VTK_VMTK_WRAP_TCL) MESSAGE("Warning. VTK_VMTK_WRAP_TCL is ON but the VTK version you have " "chosen has not support for Tcl (VTK_WRAP_TCL is OFF). " "Please set VTK_VMTK_WRAP_TCL to OFF.") SET (VTK_VMTK_WRAP_TCL OFF) ENDIF (VTK_VMTK_WRAP_TCL) ENDIF (VTK_WRAP_TCL) # # 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) vmtk-1.0.1/LICENSE0000664000175000017500000000022111757446472012147 0ustar lucalucaLICENSE ------- VMTK, the Vascular Modeling Toolkit. Copyright (C) 2004-2012, Luca Antiga, David Steinman See Copyright.txt file for Details. vmtk-1.0.1/Copyright.txt0000664000175000017500000012637511757446472013676 0ustar lucalucaCOPYRIGHT --------- Copyright (C) 2004-2012, Luca Antiga, David Steinman APPLICABLE LICENSES ------------------- * vmtk is licensed under the BSD license. * ITK is licensed under the Apache 2.0 license. * VTK is licensed under the Visualization Toolkit (VTK) license. * OpenNL is license under a modified BSD license. * Tetgen is licensed under a modified MIT license. Tetgen is not a required dependency. * Stellar and Starbase are licensed under the BSD license. COMPLETE LICENSE FOR VMTK ------------------------- Copyright (c) 2004-2011, Luca Antiga, David Steinman All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of Orobix Srl, the Mario Negri Institute, of the University of Toronto, 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. THE INSIGHT TOOLKIT (ITK) LICENSE --------------------------------- Starting with its version ITK 3.6, The Insight Toolkit is distributed under the new and simplified BSD license approved by the Open Source Initiative (OSI) [http://www.opensource.org/licenses/bsd-license.php]. Copyright (c) 1999-2009 Insight Software Consortium 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 Insight Software Consortium 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. Starting with its version ITK 4, The Insight Toolkit is distributed under the Apache 2.0 License Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. THE VISUALIZATION TOOLKIT (VTK) LICENSE --------------------------------------- Copyright (c) 1993-2009 Ken Martin, Will Schroeder, Bill Lorensen 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 name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names of any 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 AUTHORS 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. TETGEN LICENSE -------------- The software (TetGen) is licensed under the terms of the MIT license with the following exceptions: Distribution of modified versions of this code is permissible UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE SAME SOURCE FILES tetgen.h AND tetgen.cxx REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code for any commercial purpose is permissible ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER. The full license text is reproduced below. This means that TetGen is no free software, but for private, research, and educational purposes it can be used at absolutely no cost and without further arrangements. For details, see http://tetgen.berlios.de ======================================================================= TetGen A Quality Tetrahedral Mesh Generator and 3D Delaunay Triangulator Version 1.4 (Released on January 14, 2006). Copyright 2002, 2004, 2005, 2006 Hang Si Rathausstr. 9, 10178 Berlin, Germany si@wias-berlin.de Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Distribution of modified versions of this code is permissible UNDER THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE SAME SOURCE FILES tetgen.h AND tetgen.cxx REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code for any commercial purpose is permissible ONLY BY DIRECT ARRANGEMENT WITH THE COPYRIGHT OWNER. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ====================================================================== OPENNL LICENSE -------------- Copyright (c) 2004-2010, Bruno Levy 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: Bruno Levy levy@loria.fr ALICE Project LORIA, INRIA Lorraine, Campus Scientifique, BP 239 54506 VANDOEUVRE LES NANCY CEDEX FRANCE STELLAR AND STARBASE LICENSE ---------------------------- /* */ /* ,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 */ /* Jonathan Richard Shewchuk */ /* 965 Sutter Street #815 */ /* San Francisco, California 94109-6082 */ /* jrs@cs.berkeley.edu */ /* */ /* 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 Jonathan Shewchuk 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 Daniel K. Blandford, Guy E. Blelloch, David E. */ /* Cardoze, and Clemens Kadow, "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 Jonathan Richard Shewchuk, "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 Jonathan Richard Shewchuk, "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 */ /* Douglas M. Priest, "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 Steven Fortune */ /* and Christopher J. Van Wyk, "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. */ /* */ /*****************************************************************************/ PYTHON LICENSE ______________ A. HISTORY OF THE SOFTWARE ========================== Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others. In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) in Reston, Virginia where he released several versions of the software. In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation, see http://www.zope.com). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF. All Python releases are Open Source (see http://www.opensource.org for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases. Release Derived Year Owner GPL- from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes 1.6 1.5.2 2000 CNRI no 2.0 1.6 2000 BeOpen.com no 1.6.1 1.6 2001 CNRI yes (2) 2.1 2.0+1.6.1 2001 PSF no 2.0.1 2.0+1.6.1 2001 PSF yes 2.1.1 2.1+2.0.1 2001 PSF yes 2.2 2.1.1 2001 PSF yes 2.1.2 2.1.1 2002 PSF yes 2.1.3 2.1.2 2002 PSF yes 2.2.1 2.2 2002 PSF yes 2.2.2 2.2.1 2002 PSF yes 2.2.3 2.2.2 2003 PSF yes 2.3 2.2.2 2002-2003 PSF yes 2.3.1 2.3 2002-2003 PSF yes 2.3.2 2.3.1 2002-2003 PSF yes 2.3.3 2.3.2 2002-2003 PSF yes 2.3.4 2.3.3 2004 PSF yes 2.3.5 2.3.4 2005 PSF yes 2.4 2.3 2004 PSF yes 2.4.1 2.4 2005 PSF yes 2.4.2 2.4.1 2005 PSF yes 2.4.3 2.4.2 2006 PSF yes 2.4.4 2.4.3 2006 PSF yes 2.5 2.4 2006 PSF yes 2.5.1 2.5 2007 PSF yes 2.5.2 2.5.1 2008 PSF yes 2.5.3 2.5.2 2008 PSF yes 2.6 2.5 2008 PSF yes 2.6.1 2.6 2008 PSF yes 2.6.2 2.6.1 2009 PSF yes 2.6.3 2.6.2 2009 PSF yes 2.6.4 2.6.3 2009 PSF yes 2.6.5 2.6.4 2010 PSF yes 2.7 2.6 2010 PSF yes Footnotes: (1) GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't. (2) According to Richard Stallman, 1.6.1 is not GPL-compatible, because its license has a choice of law clause. According to CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 is "not incompatible" with the GPL. Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible. B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. vmtk-1.0.1/vmtk.py0000775000175000017500000001033711757446472012511 0ustar lucaluca#!/usr/bin/env python import sys import os if __name__ == '__main__': if sys.platform == 'darwin': ldEnvironmentVariable = "DYLD_LIBRARY_PATH" elif sys.platform == 'win32': ldEnvironmentVariable = "PATH" else: ldEnvironmentVariable = "LD_LIBRARY_PATH" currentEnviron = dict() currentEnviron[ldEnvironmentVariable] = "" currentEnviron["PYTHONPATH"] = "" if os.environ.has_key(ldEnvironmentVariable): currentEnviron[ldEnvironmentVariable] = os.environ[ldEnvironmentVariable] if os.environ.has_key("PYTHONPATH"): currentEnviron["PYTHONPATH"] = os.environ["PYTHONPATH"] newEnviron = {} vmtkhome = os.path.dirname(os.path.abspath(__file__)) if vmtkhome.endswith('bin'): vmtkhome = os.path.join(os.path.dirname(os.path.abspath(__file__)),"..") else: vmtkhome = os.path.join(os.path.dirname(os.path.abspath(__file__)),"..","..","..") vtkdir = [el for el in os.listdir(os.path.join(vmtkhome,"lib")) if el.startswith('vtk')][0] newEnviron[ldEnvironmentVariable] = os.path.join(vmtkhome,"bin") + os.path.pathsep + \ os.path.join(vmtkhome,"lib",vtkdir) + os.path.pathsep + \ os.path.join(vmtkhome,"lib","vmtk") + os.path.pathsep + \ os.path.join(vmtkhome,"lib","InsightToolkit") os.environ[ldEnvironmentVariable] = newEnviron[ldEnvironmentVariable] + os.path.pathsep + currentEnviron[ldEnvironmentVariable] sys.path.append(os.path.join(vmtkhome,"bin","Python")) sys.path.append(os.path.join(vmtkhome,"lib",vtkdir)) sys.path.append(os.path.join(vmtkhome,"lib","vmtk")) from vmtk import pypes vmtkOptions = ['--help', '--ui', '--file'] if len(sys.argv) > 1 and sys.argv[1] not in vmtkOptions: arguments = sys.argv[1:] print "Executing", ' '.join(arguments) pipe = pypes.Pype() pipe.ExitOnError = 0 pipe.Arguments = arguments pipe.ParseArguments() pipe.Execute() sys.exit(0) elif len(sys.argv) > 1 and '--file' in sys.argv: fileindex = sys.argv.index('--file')+1 if fileindex < len(sys.argv): inputfile = open(sys.argv[fileindex],'r') physicalLines = [line for line in inputfile.readlines() if line and line.strip() and line.strip()[0]!='#'] lines = [] for line in physicalLines: if lines and lines[-1].endswith('\\\n'): lines[-1] = lines[-1][:-2] + line else: lines.append(line) for line in lines: pipe = pypes.Pype() pipe.ExitOnError = 0 pipe.Arguments = line.split() pipe.ParseArguments() pipe.Execute() elif '--help' in sys.argv: print 'Usage: \tvmtk [--ui pad|console]\t\tStart in interactive mode\n\tvmtk [PYPE]\t\t\tExecute the pype [PYPE]\n\tvmtk --file [FILE]\t\tExecute the content of file [FILE]' sys.exit(0) else: ui = 'pad' if '--ui' in sys.argv and sys.argv.index('--ui') != len(sys.argv)-1: ui = sys.argv[sys.argv.index('--ui')+1] if ui == 'pad': try: from vmtk import pypepad except ImportError: ui = 'console' else: pypepad.RunPypeTkPad() if ui == 'console': try: import readline except ImportError: pass else: readline.parse_and_bind("tab: complete") while 1: try: inputString = raw_input("vmtk> ") except EOFError: sys.stdout.write('\n') sys.exit(0) if not inputString: continue print "Executing", inputString splitString = inputString.split() pipe = pypes.Pype() pipe.ExitOnError = 0 pipe.Arguments = inputString.split() pipe.ParseArguments() try: pipe.Execute() except Exception: continue vmtk-1.0.1/vmtkScripts/0000775000175000017500000000000011757446472013500 5ustar lucalucavmtk-1.0.1/vmtkScripts/vmtksurfaceremeshing.py0000664000175000017500000001502411757446472020310 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceremeshing.py,v $ ## Language: Python ## Date: $Date: 2006/02/23 09:27:52 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfaceremeshing = 'vmtkSurfaceRemeshing' class vmtkSurfaceRemeshing(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.TargetArea = 1.0 self.TargetEdgeLength = 1.0 self.TargetAreaFactor = 1.0 self.TargetEdgeLengthFactor = 1.0 self.MaxArea = 1E16 self.MinArea = 0.0 self.MaxEdgeLength = 1E16 self.MinEdgeLength = 0.0 self.NumberOfIterations = 10 self.NumberOfConnectivityOptimizationIterations = 20 self.CellEntityIdsArrayName = None self.TargetAreaArrayName = 'TargetArea' self.TargetEdgeLengthArrayName = '' self.ElementSizeMode = 'area' self.MinAreaFactor = 0.5 self.AspectRatioThreshold = 1.2 self.InternalAngleTolerance = 0.0 self.NormalAngleTolerance = 0.2 self.CollapseAngleThreshold = 0.2 self.Relaxation = 0.5 self.PreserveBoundaryEdges = 0 self.ExcludeEntityIds = [] self.SetScriptName('vmtksurfaceremeshing') self.SetScriptDoc('remesh a surface using quality triangles') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ElementSizeMode','elementsizemode','str',1,'["area","edgelength","areaarray","edgelengtharray"]'], ['TargetArea','area','float',1,'(0.0,)'], ['TargetAreaArrayName','areaarray','str',1], ['TargetEdgeLength','edgelength','float',1,'(0.0,)'], ['TargetEdgeLengthArrayName','edgelengtharray','str',1], ['TargetAreaFactor','areafactor','float',1,'(0.0,)'], ['TargetEdgeLengthFactor','edgelengthfactor','float',1,'(0.0,)'], ['MaxArea','maxarea','float',1,'(0.0,)'], ['MinArea','minarea','float',1,'(0.0,)'], ['NumberOfIterations','iterations','int',1,'(0,)'], ['NumberOfConnectivityOptimizationIterations','connectivityiterations','int',1,'(0,)'], ['CellEntityIdsArrayName','entityidsarray','str',1], ['AspectRatioThreshold','aspectratio','float',1,'(0.0,)'], ['MinAreaFactor','minareafactor','float',1,'(0.0,)'], ['InternalAngleTolerance','internalangletolerance','float',1,'(0.0,)'], ['NormalAngleTolerance','normalangletolerance','float',1,'(0.0,)'], ['CollapseAngleThreshold','collapseangle','float',1,'(0.0,)'], ['Relaxation','relaxation','float',1,'(0.5,)'], ['ExcludeEntityIds','exclude','int',-1,''], ['PreserveBoundaryEdges','preserveboundary','bool',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(self.Surface) cleaner.Update() triangleFilter = vtk.vtkTriangleFilter() triangleFilter.SetInput(cleaner.GetOutput()) triangleFilter.Update() self.Surface = triangleFilter.GetOutput() if self.ElementSizeMode == 'edgelength': self.TargetArea = 0.25 * 3.0**0.5 * self.TargetEdgeLength**2 elif self.ElementSizeMode == 'edgelengtharray': calculator = vtk.vtkArrayCalculator() calculator.SetInput(self.Surface) calculator.AddScalarArrayName(self.TargetEdgeLengthArrayName,0) calculator.SetFunction("%f^2 * 0.25 * sqrt(3) * %s^2" % (self.TargetEdgeLengthFactor,self.TargetEdgeLengthArrayName)) calculator.SetResultArrayName(self.TargetAreaArrayName) calculator.Update() self.MaxArea = 0.25 * 3.0**0.5 * self.MaxEdgeLength**2 self.MinArea = 0.25 * 3.0**0.5 * self.MinEdgeLength**2 self.Surface = calculator.GetOutput() excludedIds = vtk.vtkIdList() if self.ExcludeEntityIds: for excludedId in self.ExcludeEntityIds: excludedIds.InsertNextId(excludedId) surfaceRemeshing = vtkvmtk.vtkvmtkPolyDataSurfaceRemeshing() surfaceRemeshing.SetInput(self.Surface) if self.CellEntityIdsArrayName: surfaceRemeshing.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) if self.ElementSizeMode in ['area','edgelength']: surfaceRemeshing.SetElementSizeModeToTargetArea() elif self.ElementSizeMode in ['areaarray','edgelengtharray']: surfaceRemeshing.SetElementSizeModeToTargetAreaArray() surfaceRemeshing.SetTargetAreaArrayName(self.TargetAreaArrayName) else: self.PrintError('Error: unsupported ElementSizeMode.') surfaceRemeshing.SetTargetArea(self.TargetArea) surfaceRemeshing.SetTargetAreaFactor(self.TargetAreaFactor) surfaceRemeshing.SetMaxArea(self.MaxArea) surfaceRemeshing.SetMinArea(self.MinArea) surfaceRemeshing.SetNumberOfIterations(self.NumberOfIterations) surfaceRemeshing.SetNumberOfConnectivityOptimizationIterations(self.NumberOfConnectivityOptimizationIterations) surfaceRemeshing.SetRelaxation(self.Relaxation) surfaceRemeshing.SetMinAreaFactor(self.MinAreaFactor) surfaceRemeshing.SetAspectRatioThreshold(self.AspectRatioThreshold) surfaceRemeshing.SetInternalAngleTolerance(self.InternalAngleTolerance) surfaceRemeshing.SetNormalAngleTolerance(self.NormalAngleTolerance) surfaceRemeshing.SetCollapseAngleThreshold(self.CollapseAngleThreshold) surfaceRemeshing.SetPreserveBoundaryEdges(self.PreserveBoundaryEdges) surfaceRemeshing.SetExcludedEntityIds(excludedIds) surfaceRemeshing.Update() self.Surface = surfaceRemeshing.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshwallshearrate.py0000664000175000017500000000473711757446472020502 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshwallshearrate.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtkvmtk import vtk import sys import pypes vmtkmeshwallshearrate = 'vmtkMeshWallShearRate' class vmtkMeshWallShearRate(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.Surface = None self.VelocityArrayName = None self.WallShearRateArrayName = 'WallShearRate' self.ConvergenceTolerance = 1E-6 self.QuadratureOrder = 3 self.SetScriptName('vmtkmeshwallshearrate') self.SetScriptDoc('compute wall shear rate from a velocity field, producing a surface in output') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['VelocityArrayName','velocityarray','str',1,'',''], ['WallShearRateArrayName','wsrarray','str',1,'',''], ['ConvergenceTolerance','tolerance','float',1,'',''], ['QuadratureOrder','quadratureorder','int',1,'',''] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') wallShearRateFilter = vtkvmtk.vtkvmtkMeshWallShearRate() wallShearRateFilter.SetInput(self.Mesh) wallShearRateFilter.SetVelocityArrayName(self.VelocityArrayName) wallShearRateFilter.SetWallShearRateArrayName(self.WallShearRateArrayName) wallShearRateFilter.SetConvergenceTolerance(self.ConvergenceTolerance) wallShearRateFilter.SetQuadratureOrder(self.QuadratureOrder) wallShearRateFilter.ComputeIndividualPartialDerivativesOn() wallShearRateFilter.Update() self.Surface = wallShearRateFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagefeaturecorrection.py0000664000175000017500000000542011757446472021503 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagefeaturecorrection.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkimagefeaturecorrection = 'vmtkImageFeatureCorrection' class vmtkImageFeatureCorrection(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.LevelSets = None self.Sigma = 1.0 self.ScaleValue = 0.02 self.NegateLevelSets = False self.ComputeScaleValueFromInput = True self.SetScriptName('vmtkimagefeaturecorrection') self.SetScriptDoc('correct a feature image (e.g. remove influence of bone and/or air from CT-based feature images)') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input feature image','vmtkimagereader'], ['LevelSets','levelsets','vtkImageData',1,'','the input level sets','vmtkimagereader'], ['Sigma','sigma','float',1,'(0.0,)'], ['ScaleValue','scale','float',1,'(0.0,)'], ['ComputeScaleValueFromInput','scalefrominput','bool',1,''], ['NegateLevelSets','negate','bool',1,''] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.LevelSets == None: self.PrintError('Error: No input level sets.') if self.NegateLevelSets: negateFilter = vtk.vtkImageMathematics() negateFilter.SetInput(self.LevelSets) negateFilter.SetOperationToMultiplyByK() negateFilter.SetConstantK(-1.0) negateFilter.Update() self.LevelSets = negateFilter.GetOutput() sigmoid = vtkvmtk.vtkvmtkLevelSetSigmoidFilter() sigmoid.SetInput(self.Image) sigmoid.SetLevelSetsImage(self.LevelSets) sigmoid.SetSigma(self.Sigma) sigmoid.SetScaleValue(self.ScaleValue) if self.ComputeScaleValueFromInput: sigmoid.ComputeScaleValueFromInputOn() else: sigmoid.ComputeScaleValueFromInputOff() sigmoid.Update() self.Image = sigmoid.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlines.py0000664000175000017500000006360711757446472017303 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlines.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:52:56 $ ## Version: $Revision: 1.20 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkcenterlines = 'vmtkCenterlines' ## TODO: make SeedSelector a separate pype script to be used in other contexts class vmtkSeedSelector(object): def __init__(self): self._Surface = None self._SeedIds = None self._SourceSeedIds = vtk.vtkIdList() self._TargetSeedIds = vtk.vtkIdList() self.PrintError = None self.PrintLog = None self.InputText = None self.OutputText = None self.InputInfo = None def SetSurface(self,surface): self._Surface = surface def GetSurface(self): return self._Surface def GetSourceSeedIds(self): return self._SourceSeedIds def GetTargetSeedIds(self): return self._TargetSeedIds def Execute(self): pass class vmtkIdListSeedSelector(vmtkSeedSelector): def __init__(self): vmtkSeedSelector.__init__(self) self.SourceIds = None self.TargetIds = None def Execute(self): if not self._Surface: self.PrintError('vmtkIdListSeedSelector Error: Surface not set.') return if not self.SourceIds: self.PrintError('vmtkIdListSeedSelector Error: SourceIds not set.') return if not self.TargetIds: self.PrintError('vmtkIdListSeedSelector Error: TargetIds not set.') return self._SourceSeedIds.Initialize() self._TargetSeedIds.Initialize() maxId = self._Surface.GetNumberOfPoints()-1 for id in self.SourceIds: if id >= maxId: self.PrintError('vmtkIdListSeedSelector Error: invalid SourceId.') self._SourceSeedIds.InsertNextId(id) for id in self.TargetIds: if id >= maxId: self.PrintError('vmtkIdListSeedSelector Error: invalid TargetId.') self._TargetSeedIds.InsertNextId(id) class vmtkPointListSeedSelector(vmtkSeedSelector): def __init__(self): vmtkSeedSelector.__init__(self) self.SourcePoints = None self.TargetPoints = None def Execute(self): if not self._Surface: self.PrintError('vmtkPointListSeedSelector Error: Surface not set.') return if not self.SourcePoints: self.PrintError('vmtkPointListSeedSelector Error: SourcePoints not set.') return if not self.TargetPoints: self.PrintError('vmtkPointListSeedSelector Error: TargetPoints not set.') return self._SourceSeedIds.Initialize() self._TargetSeedIds.Initialize() if len(self.SourcePoints) % 3 != 0: self.PrintError('vmtkPointListSeedSelector Error: SourcePoints not made up of triplets.') return if len(self.TargetPoints) % 3 != 0: self.PrintError('vmtkPointListSeedSelector Error: TargetPoints not made up of triplets.') return pointLocator = vtk.vtkPointLocator() pointLocator.SetDataSet(self._Surface) pointLocator.BuildLocator() for i in range(len(self.SourcePoints)/3): point = [self.SourcePoints[3*i+0],self.SourcePoints[3*i+1],self.SourcePoints[3*i+2]] id = pointLocator.FindClosestPoint(point) self._SourceSeedIds.InsertNextId(id) for i in range(len(self.TargetPoints)/3): point = [self.TargetPoints[3*i+0],self.TargetPoints[3*i+1],self.TargetPoints[3*i+2]] id = pointLocator.FindClosestPoint(point) self._TargetSeedIds.InsertNextId(id) class vmtkPickPointSeedSelector(vmtkSeedSelector): def __init__(self): vmtkSeedSelector.__init__(self) self.PickedSeedIds = vtk.vtkIdList() self.PickedSeeds = vtk.vtkPolyData() self.vmtkRenderer = None self.OwnRenderer = 0 self.Script = None def UndoCallback(self, obj): self.InitializeSeeds() self.PickedSeeds.Modified() self.vmtkRenderer.RenderWindow.Render() def PickCallback(self, obj): picker = vtk.vtkCellPicker() picker.SetTolerance(1E-4 * self._Surface.GetLength()) eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: return pickPosition = picker.GetPickPosition() pickedCellPointIds = self._Surface.GetCell(picker.GetCellId()).GetPointIds() minDistance = 1E10 pickedSeedId = -1 for i in range(pickedCellPointIds.GetNumberOfIds()): distance = vtk.vtkMath.Distance2BetweenPoints(pickPosition,self._Surface.GetPoint(pickedCellPointIds.GetId(i))) if distance < minDistance: minDistance = distance pickedSeedId = pickedCellPointIds.GetId(i) if pickedSeedId == -1: pickedSeedId = pickedCellPointIds.GetId(0) self.PickedSeedIds.InsertNextId(pickedSeedId) point = self._Surface.GetPoint(pickedSeedId) self.PickedSeeds.GetPoints().InsertNextPoint(point) self.PickedSeeds.Modified() self.vmtkRenderer.RenderWindow.Render() def InitializeSeeds(self): self.PickedSeedIds.Initialize() self.PickedSeeds.Initialize() seedPoints = vtk.vtkPoints() self.PickedSeeds.SetPoints(seedPoints) def Execute(self): if (self._Surface == None): self.PrintError('vmtkPickPointSeedSelector Error: Surface not set.') return self._SourceSeedIds.Initialize() self._TargetSeedIds.Initialize() if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self.Script) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphs.SetInput(self.PickedSeeds) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToDataScalingOff() glyphs.SetScaleFactor(self._Surface.GetLength()*0.01) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) self.SeedActor = vtk.vtkActor() self.SeedActor.SetMapper(glyphMapper) self.SeedActor.GetProperty().SetColor(1.0,0.0,0.0) self.SeedActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.SeedActor) ##self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.vmtkRenderer.AddKeyBinding('u','Undo.',self.UndoCallback) self.vmtkRenderer.AddKeyBinding('space','Add points.',self.PickCallback) surfaceMapper = vtk.vtkPolyDataMapper() surfaceMapper.SetInput(self._Surface) surfaceMapper.ScalarVisibilityOff() surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(surfaceMapper) surfaceActor.GetProperty().SetOpacity(1.0) self.vmtkRenderer.Renderer.AddActor(surfaceActor) self.InputInfo('Please position the mouse and press space to add source points, \'u\' to undo\n') any = 0 while any == 0: self.InitializeSeeds() self.vmtkRenderer.Render() any = self.PickedSeedIds.GetNumberOfIds() self._SourceSeedIds.DeepCopy(self.PickedSeedIds) self.InputInfo('Please position the mouse and press space to add target points, \'u\' to undo\n') any = 0 while any == 0: self.InitializeSeeds() self.vmtkRenderer.Render() any = self.PickedSeedIds.GetNumberOfIds() self._TargetSeedIds.DeepCopy(self.PickedSeedIds) if self.OwnRenderer: self.vmtkRenderer.Deallocate() class vmtkOpenProfilesSeedSelector(vmtkSeedSelector): def __init__(self): vmtkSeedSelector.__init__(self) self.vmtkRenderer = None self.OwnRenderer = 0 self.Script = None def SetSeedIds(self,seedIds): self._SeedIds = seedIds def GetSeedIds(self): return self._SeedIds def Execute(self): if (self._Surface == None): self.PrintError('vmtkOpenProfilesSeedSelector Error: Surface not set.') return if (self._SeedIds == None): self.PrintError('vmtkOpenProfilesSeedSelector Error: SeedIds not set.') return self._SourceSeedIds.Initialize() self._TargetSeedIds.Initialize() if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self.Script) seedPoints = vtk.vtkPoints() for i in range(self._SeedIds.GetNumberOfIds()): seedPoints.InsertNextPoint(self._Surface.GetPoint(self._SeedIds.GetId(i))) seedPolyData = vtk.vtkPolyData() seedPolyData.SetPoints(seedPoints) seedPolyData.Update() labelsMapper = vtk.vtkLabeledDataMapper(); labelsMapper.SetInput(seedPolyData) labelsMapper.SetLabelModeToLabelIds() labelsActor = vtk.vtkActor2D() labelsActor.SetMapper(labelsMapper) self.vmtkRenderer.Renderer.AddActor(labelsActor) surfaceMapper = vtk.vtkPolyDataMapper() surfaceMapper.SetInput(self._Surface) surfaceMapper.ScalarVisibilityOff() surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(surfaceMapper) surfaceActor.GetProperty().SetOpacity(0.25) self.vmtkRenderer.Renderer.AddActor(surfaceActor) self.vmtkRenderer.Render() seedIdString = self.InputText("Please input list of inlet profile ids: ") separator = ' ' if seedIdString.find(',') != -1: separator = ',' seedIdList = seedIdString.split(separator) for seedIdString in seedIdList: self._SourceSeedIds.InsertNextId(int(seedIdString.strip())) seedIdString = self.InputText("Please input list of outlet profile ids (leave empty for all available profiles): ") if seedIdString.strip() == '': self.InputInfo("Selected outlets: ") for i in range(seedPoints.GetNumberOfPoints()): if self._SourceSeedIds.IsId(i) == -1: self._TargetSeedIds.InsertNextId(i) self.InputInfo("%d " % i) self.InputInfo("\n") else: seedIdList = seedIdString.split(separator) for seedIdString in seedIdList: self._TargetSeedIds.InsertNextId(int(seedIdString.strip())) if self.OwnRenderer: self.vmtkRenderer.Deallocate() class vmtkCarotidProfilesSeedSelector(vmtkSeedSelector): def SetSeedIds(self,seedIds): self._SeedIds = seedIds def GetSeedIds(self): return self._SeedIds def Execute(self): if (self._Surface == None): self.PrintError('vmtkCarotidProfilesSeedSelector Error: Surface not set.') return if (self._SeedIds == None): self.PrintError('vmtkCarotidProfilesSeedSelector Error: SeedIds not set.') return self._SourceSeedIds.Initialize() self._TargetSeedIds.Initialize() minZId = -1 maxZId = -1 minZ = 1E8 maxZ = -1E8 for id in range(self._SeedIds.GetNumberOfIds()): currentZ = self._Surface.GetPoint(self._SeedIds.GetId(id))[2] if (currentZ < minZ): minZ = currentZ minZId = id if (currentZ > maxZ): maxZ = currentZ maxZId = id self._SourceSeedIds.InsertNextId(minZId) self._TargetSeedIds.InsertNextId(maxZId) midZId = 3-(minZId+maxZId) self._TargetSeedIds.InsertNextId(midZId) class vmtkNonManifoldSurfaceChecker(object): def __init__(self): self.Surface = 0 self.NumberOfNonManifoldEdges = 0 self.Report = 0 self.NonManifoldEdgePointIds = vtk.vtkIdList() self.PrintError = None def Execute(self): if (self.Surface == 0): self.PrintError('NonManifoldSurfaceChecker error: Surface not set') return self.NonManifoldEdgesFound = 0 self.Report = '' self.NonManifoldEdgePointIds.Initialize() neighborhoods = vtkvmtk.vtkvmtkNeighborhoods() neighborhoods.SetNeighborhoodTypeToPolyDataManifoldNeighborhood() neighborhoods.SetDataSet(self.Surface) neighborhoods.Build() neighborCellIds = vtk.vtkIdList() cellPointIds = vtk.vtkIdList() self.Surface.BuildCells() self.Surface.BuildLinks(0) self.Surface.Update() numberOfNonManifoldEdges = 0 for i in range(neighborhoods.GetNumberOfNeighborhoods()): neighborhood = neighborhoods.GetNeighborhood(i) for j in range(neighborhood.GetNumberOfPoints()): neighborId = neighborhood.GetPointId(j) if (i2): numberOfNonManifoldEdges = numberOfNonManifoldEdges + 1 self.Report = self.Report + "Non-manifold edge found" + str(i) + ' ' + str(neighborId) + '.\n' self.NonManifoldEdgePointIds.InsertNextId(i) self.NonManifoldEdgePointIds.InsertNextId(neighborId) class vmtkCenterlines(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.SeedSelector = None self.SeedSelectorName = 'pickpoint' self.FlipNormals = 0 self.CapDisplacement = 0.0 self.RadiusArrayName = 'MaximumInscribedSphereRadius' self.CostFunction = '1/R' self.AppendEndPoints = 0 self.CheckNonManifold = 0 self.Resampling = 0 self.ResamplingStepLength = 1.0 self.SimplifyVoronoi = 0 self.EikonalSolutionArrayName = 'EikonalSolution' self.EdgeArrayName = 'EdgeArray' self.EdgePCoordArrayName = 'EdgePCoordArray' self.CostFunctionArrayName = 'CostFunctionArray' self.UseTetGen = 0 self.TetGenDetectInter = 1 self.DelaunayTessellation = None self.VoronoiDiagram = None self.PoleIds = None self.SourceIds = [] self.TargetIds = [] self.SourcePoints = [] self.TargetPoints = [] self.vmtkRenderer = None self.OwnRenderer = 0 self.SetScriptName('vmtkcenterlines') self.SetScriptDoc('compute centerlines from a branching tubular surface (see papers for details); seed points can be interactively selected on the surface, or specified as the barycenters of the open boundaries of the surface; if vmtk is compiled with support for TetGen, TetGen can be employed to compute the Delaunay tessellation of the input points') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['SeedSelectorName','seedselector','str',1,'["pickpoint","openprofiles","carotidprofiles","idlist","pointlist"]','seed point selection method (pickpoint: interactive; openprofiles: choose among barycenters of open profiles of the surface; carotidprofiles: open profiles are automatically selected based on their z-axis coordinate (lower to higher: CCA, ECA, ICA)); idlist: list of surface point ids (specified as argument to -sourceids and -targetids); pointlist: list of surface points (specified as argument to -sourcepoints and -targetpoints)'], ['SourceIds','sourceids','int',-1,'','list of source point ids'], ['TargetIds','targetids','int',-1,'','list of target point ids'], ['SourcePoints','sourcepoints','float',-1,'','list of source point coordinates'], ['TargetPoints','targetpoints','float',-1,'','list of target point coordinates'], ['AppendEndPoints','endpoints','bool',1,'','toggle append open profile barycenters to centerlines'], ['CheckNonManifold','nonmanifoldcheck','bool',1,'','toggle checking the surface for non-manifold edges'], ['FlipNormals','flipnormals','bool',1,'','flip normals after outward normal computation; outward oriented normals must be computed for the removal of outer tetrahedra; the algorithm might fail so for weird geometries, so changing this might solve the problem'], ['CapDisplacement','capdisplacement','float',1,'','displacement of the center points of caps at open profiles along their normals (avoids the creation of degenerate tetrahedra)'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where radius values of maximal inscribed spheres have to be stored'], ['AppendEndPoints','endpoints','bool',1,'','toggle append open profile barycenters to centerlines'], ['Resampling','resampling','bool',1,'','toggle centerlines resampling'], ['ResamplingStepLength','resamplingstep','float',1,'(0.0,)','distance between points in the resampled line'], ['DelaunayTessellation','delaunaytessellation','vtkUnstructuredGrid',1,'','optional input Delaunay tessellation'], ['SimplifyVoronoi','simplifyvoronoi','bool',1,'','toggle simplification of Voronoi diagram'], ['UseTetGen','usetetgen','bool',1,'','toggle use TetGen to compute Delaunay tessellation'], ['TetGenDetectInter','tetgendetectinter','bool',1,'','TetGen option'], ['CostFunction','costfunction','str',1,'','specify cost function to be minimized during centerline computation'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer']]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where radius values of maximal inscribed spheres are stored'], ['EikonalSolutionArrayName','eikonalsolutionarray','str',1], ['EdgeArrayName','edgearray','str',1], ['EdgePCoordArrayName','edgepcoordarray','str',1], ['CostFunctionArrayName','costfunctionarray','str',1], ['DelaunayTessellation','delaunaytessellation','vtkUnstructuredGrid',1,'','','vmtkmeshwriter'], ['VoronoiDiagram','voronoidiagram','vtkPolyData',1,'','','vmtksurfacewriter'], ['PoleIds','poleids','vtkIdList',1]]) def PrintProgress(self,obj,event): self.OutputProgress(obj.GetProgress(),10) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.CheckNonManifold: self.PrintLog('NonManifold check.') nonManifoldChecker = vmtkNonManifoldSurfaceChecker() nonManifoldChecker.Surface = self.Surface nonManifoldChecker.PrintError = self.PrintError nonManifoldChecker.Execute() if (nonManifoldChecker.NumberOfNonManifoldEdges > 0): self.PrintLog(nonManifoldChecker.Report) return if not self.vmtkRenderer and self.SeedSelectorName in ['pickpoint','openprofiles']: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.PrintLog('Cleaning surface.') surfaceCleaner = vtk.vtkCleanPolyData() surfaceCleaner.SetInput(self.Surface) surfaceCleaner.Update() self.PrintLog('Triangulating surface.') surfaceTriangulator = vtk.vtkTriangleFilter() surfaceTriangulator.SetInput(surfaceCleaner.GetOutput()) surfaceTriangulator.PassLinesOff() surfaceTriangulator.PassVertsOff() surfaceTriangulator.Update() centerlineInputSurface = surfaceTriangulator.GetOutput() capCenterIds = None if (self.SeedSelectorName == 'openprofiles') | (self.SeedSelectorName == 'carotidprofiles') | (self.SeedSelectorName == 'pickpoint'): self.PrintLog('Capping surface.') surfaceCapper = vtkvmtk.vtkvmtkCapPolyData() surfaceCapper.SetInput(surfaceTriangulator.GetOutput()) surfaceCapper.SetDisplacement(self.CapDisplacement) surfaceCapper.SetInPlaneDisplacement(self.CapDisplacement) surfaceCapper.Update() centerlineInputSurface = surfaceCapper.GetOutput() capCenterIds = surfaceCapper.GetCapCenterIds() if self.SeedSelector: pass elif self.SeedSelectorName: if self.SeedSelectorName == 'pickpoint': self.SeedSelector = vmtkPickPointSeedSelector() self.SeedSelector.vmtkRenderer = self.vmtkRenderer self.SeedSelector.Script = self elif self.SeedSelectorName == 'openprofiles': self.SeedSelector = vmtkOpenProfilesSeedSelector() self.SeedSelector.vmtkRenderer = self.vmtkRenderer self.SeedSelector.Script = self self.SeedSelector.SetSeedIds(surfaceCapper.GetCapCenterIds()) elif self.SeedSelectorName == 'carotidprofiles': self.SeedSelector = vmtkCarotidProfilesSeedSelector() self.SeedSelector.SetSeedIds(surfaceCapper.GetCapCenterIds()) elif (self.SeedSelectorName == 'idlist'): self.SeedSelector = vmtkIdListSeedSelector() self.SeedSelector.SourceIds = self.SourceIds self.SeedSelector.TargetIds = self.TargetIds elif (self.SeedSelectorName == 'pointlist'): self.SeedSelector = vmtkPointListSeedSelector() self.SeedSelector.SourcePoints = self.SourcePoints self.SeedSelector.TargetPoints = self.TargetPoints else: self.PrintError("SeedSelectorName unknown (available: pickpoint | openprofiles | carotidprofiles | idlist | pointlist)") return else: self.PrintError('vmtkCenterlines error: either SeedSelector or SeedSelectorName must be specified') return self.SeedSelector.SetSurface(centerlineInputSurface) self.SeedSelector.InputInfo = self.InputInfo self.SeedSelector.InputText = self.InputText self.SeedSelector.OutputText = self.OutputText self.SeedSelector.PrintError = self.PrintError self.SeedSelector.PrintLog = self.PrintLog self.SeedSelector.Execute() inletSeedIds = self.SeedSelector.GetSourceSeedIds() outletSeedIds = self.SeedSelector.GetTargetSeedIds() self.PrintLog('Computing centerlines.') self.InputInfo('Computing centerlines...') centerlineFilter = vtkvmtk.vtkvmtkPolyDataCenterlines() centerlineFilter.SetInput(centerlineInputSurface) if (self.SeedSelectorName == 'openprofiles') | (self.SeedSelectorName == 'carotidprofiles'): centerlineFilter.SetCapCenterIds(capCenterIds) centerlineFilter.SetSourceSeedIds(inletSeedIds) centerlineFilter.SetTargetSeedIds(outletSeedIds) centerlineFilter.SetRadiusArrayName(self.RadiusArrayName) centerlineFilter.SetCostFunction(self.CostFunction) centerlineFilter.SetFlipNormals(self.FlipNormals) centerlineFilter.SetAppendEndPointsToCenterlines(self.AppendEndPoints) centerlineFilter.SetSimplifyVoronoi(self.SimplifyVoronoi) if self.DelaunayTessellation != None: centerlineFilter.GenerateDelaunayTessellationOff() centerlineFilter.SetDelaunayTessellation(self.DelaunayTessellation) if self.UseTetGen==1: self.PrintLog('Running TetGen.') import vmtkscripts surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = centerlineInputSurface surfaceToMesh.Execute() tetgen = vmtkscripts.vmtkTetGen() tetgen.Mesh = surfaceToMesh.Mesh tetgen.PLC = 1 tetgen.NoMerge = 1 tetgen.Quality = 0 if self.TetGenDetectInter == 1: tetgen.DetectInter = 1 tetgen.NoMerge = 0 tetgen.OutputSurfaceElements = 0 tetgen.Execute() centerlineFilter.GenerateDelaunayTessellationOff() centerlineFilter.SetDelaunayTessellation(tetgen.Mesh) centerlineFilter.SetCenterlineResampling(self.Resampling) centerlineFilter.SetResamplingStepLength(self.ResamplingStepLength) centerlineFilter.Update() self.Centerlines = centerlineFilter.GetOutput() self.VoronoiDiagram = centerlineFilter.GetVoronoiDiagram() self.DelaunayTessellation = centerlineFilter.GetDelaunayTessellation() self.PoleIds = centerlineFilter.GetPoleIds() self.EikonalSolutionArrayName = centerlineFilter.GetEikonalSolutionArrayName() self.EdgeArrayName = centerlineFilter.GetEdgeArrayName() self.EdgePCoordArrayName = centerlineFilter.GetEdgePCoordArrayName() self.CostFunctionArrayName = centerlineFilter.GetCostFunctionArrayName() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkpointsplitextractor.py0000664000175000017500000000621311757446472021117 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkpointSplitextractor.py,v $ ## Language: Python ## Date: $Date: 2006/03/01 11:54:16 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkpointsplitextractor = 'vmtkPointSplitExtractor' class vmtkPointSplitExtractor(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.RadiusArrayName = '' self.GroupIdsArrayName = 'GroupIds' self.CenterlineIdsArrayName = 'CenterlineIds' self.BlankingArrayName = 'Blanking' self.TractIdsArrayName = 'TractIds' self.SplitPoint = [0.0,0.0,0.0] self.GapLength = 1.0 self.Tolerance = 1E-4 self.SetScriptName('vmtkpointsplitextractor') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','','vmtksurfacereader'], ['GroupIdsArrayName','groupidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['RadiusArrayName','radiusarray','str',1], ['BlankingArrayName','blankingarray','str',1], ['SplitPoint','splitpoint','float',3], ['GapLength','gaplength','float',1,'(0.0,)'], ['Tolerance','tolerance','float',1,'(0.0,)'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['GroupIdsArrayName','groupidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['BlankingArrayName','blankingarray','str',1] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') pointSplitExtractor = vtkvmtk.vtkvmtkCenterlineSplitExtractor() pointSplitExtractor.SetInput(self.Centerlines) pointSplitExtractor.SetRadiusArrayName(self.RadiusArrayName) pointSplitExtractor.SetGroupIdsArrayName(self.GroupIdsArrayName) pointSplitExtractor.SetTractIdsArrayName(self.TractIdsArrayName) pointSplitExtractor.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) pointSplitExtractor.SetBlankingArrayName(self.BlankingArrayName) pointSplitExtractor.SetSplitPoint(self.SplitPoint) pointSplitExtractor.SetGapLength(self.GapLength) pointSplitExtractor.SetTolerance(self.Tolerance) pointSplitExtractor.Update() self.Centerlines = pointSplitExtractor.GetOutput() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfaceviewer.py0000664000175000017500000001534311757446472017634 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceviewer.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.10 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vmtkrenderer import pypes vmtksurfaceviewer = 'vmtkSurfaceViewer' class vmtkSurfaceViewer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Display = 1 self.Opacity = 1.0 self.ArrayName = '' self.ScalarRange = [0.0, 0.0] self.Legend = 0 self.LegendTitle = '' self.Grayscale = 0 self.FlatInterpolation = 0 self.DisplayCellData = 0 self.Color = [-1.0, -1.0, -1.0] self.LineWidth = 1 self.Representation = 'surface' self.Actor = None self.ScalarBarActor = None self.SetScriptName('vmtksurfaceviewer') self.SetScriptDoc('display a surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['Display','display','bool',1,'','toggle rendering'], ['Opacity','opacity','float',1,'(0.0,1.0)','obejct opacity in the scene'], ['ArrayName','array','str',1,'','name of the array where the scalars to be displayed are stored'], ['ScalarRange','scalarrange','float',2,'','range of the scalar map'], ['Legend','legend','bool',1,'','toggle scalar bar'], ['Grayscale','grayscale','bool',1,'','toggle color or grayscale'], ['FlatInterpolation','flat','bool',1,'','toggle flat or shaded surface display'], ['DisplayCellData','celldata','bool',1,'','toggle display of point or cell data'], ['Color','color','float',3,'','RGB color of the object in the scene'], ['LineWidth','linewidth','int',1,'(0.0,)','width of line objects in the scene'], ['LegendTitle','legendtitle','str',1,'','title of the scalar bar']]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['Actor','oactor','vtkActor',1,'','the output actor'] ]) def RepresentationCallback(self, obj): if not self.Actor: return if self.Representation == 'surface': self.Representation = 'edges' elif self.Representation == 'edges': self.Representation = 'wireframe' elif self.Representation == 'wireframe': self.Representation = 'surface' if self.Representation == 'surface': self.Actor.GetProperty().SetRepresentationToSurface() self.Actor.GetProperty().EdgeVisibilityOff() elif self.Representation == 'edges': self.Actor.GetProperty().SetRepresentationToSurface() self.Actor.GetProperty().EdgeVisibilityOn() elif self.Representation == 'wireframe': self.Actor.GetProperty().SetRepresentationToWireframe() self.Actor.GetProperty().EdgeVisibilityOff() self.vmtkRenderer.RenderWindow.Render() def BuildView(self): if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if self.Actor: self.vmtkRenderer.Renderer.RemoveActor(self.Actor) if self.ScalarBarActor: self.vmtkRenderer.Renderer.RemoveActor(self.ScalarBarActor) if self.Surface: mapper = vtk.vtkPolyDataMapper() mapper.SetInput(self.Surface) if self.ArrayName: if self.DisplayCellData == 0: self.Surface.GetPointData().SetActiveScalars(self.ArrayName) array = self.Surface.GetPointData().GetScalars() else: self.Surface.GetCellData().SetActiveScalars(self.ArrayName) array = self.Surface.GetCellData().GetScalars() mapper.SetScalarModeToUseCellData() if (self.ScalarRange[1] > self.ScalarRange[0]): mapper.SetScalarRange(self.ScalarRange) elif array: mapper.SetScalarRange(array.GetRange(0)) if self.Grayscale: lut = vtk.vtkLookupTable() lut.SetValueRange(0.0,1.0) lut.SetSaturationRange(0.0,0.0) mapper.SetLookupTable(lut) else: mapper.ScalarVisibilityOff() self.Actor = vtk.vtkActor() self.Actor.SetMapper(mapper) if (self.Color[0] >= 0.0): self.Actor.GetProperty().SetColor(self.Color) self.Actor.GetProperty().SetOpacity(self.Opacity) self.Actor.GetProperty().SetLineWidth(self.LineWidth) if self.FlatInterpolation: self.Actor.GetProperty().SetInterpolationToFlat() self.vmtkRenderer.Renderer.AddActor(self.Actor) self.vmtkRenderer.AddKeyBinding('w','Change surface representation.',self.RepresentationCallback) if self.Legend and self.Actor: self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.Actor.GetMapper().GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() ## self.ScalarBarActor.GetLabelTextProperty().SetColor(0.0,0.0,0.0) self.ScalarBarActor.SetLabelFormat('%.2f') self.ScalarBarActor.SetTitle(self.LegendTitle) self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) if self.Display: self.vmtkRenderer.Render() ## self.vmtkRenderer.Renderer.RemoveActor(self.Actor) ## self.vmtkRenderer.Renderer.RemoveActor(self.ScalarBarActor) if self.OwnRenderer: self.vmtkRenderer.Deallocate() def Execute(self): if (not self.Surface) and self.Display: self.PrintError('Error: no Surface.') self.BuildView() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkicpregistration.py0000664000175000017500000001457211757446472020173 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkicpregistration.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkicpregistration = 'vmtkICPRegistration' class vmtkICPRegistration(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.ReferenceSurface = None self.Surface = None self.DistanceArrayName = '' self.SignedDistanceArrayName = '' self.FarThreshold = 0.0 self.Level = 0.0 self.MaximumMeanDistance = 1E-2 self.MaximumNumberOfLandmarks = 1000 self.MaximumNumberOfIterations = 100 self.Matrix4x4 = None self.MatrixCoefficients = None self.FlipNormals = 0 self.SetScriptName('vmtkicpregistration') self.SetScriptDoc('register a surface to a reference surface using the ICP algorithm') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ReferenceSurface','r','vtkPolyData',1,'','the reference surface','vmtksurfacereader'], ['DistanceArrayName','distancearray','str',1,'','name of the array where the distance of the input surface to the reference surface has to be stored'], ['SignedDistanceArrayName','signeddistancearray','str',1,'','name of the array where the signed distance of the input surface to the reference surface is stored; distance is positive if distance vector and normal to the reference surface have negative dot product, i.e. if the input surface is outer with respect to the reference surface'], ['FarThreshold','farthreshold','float',1,'','threshold distance beyond which points are discarded during optimization'], ['FlipNormals','flipnormals','bool',1,'','flip normals to the reference surface after computing them'], ['MaximumNumberOfLandmarks','landmarks','int',1,'','maximum number of landmarks sampled from the two surfaces for evaluation of the registration metric'], ['MaximumNumberOfIterations','iterations','int',1,'','maximum number of iterations for the optimization problems'], ['MaximumMeanDistance','maxmeandistance','float',1,'','convergence threshold based on the maximum mean distance between the two surfaces'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['MatrixCoefficients','omatrixcoefficients','float',16,'','the output transform matrix coefficients'], ['Matrix4x4','omatrix4x4','vtkMatrix4x4',1,'','the output transform matrix'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') if self.ReferenceSurface == None: self.PrintError('Error: No ReferenceSurface.') ## if (self.SignedDistanceArrayName != '') & (self.ReferenceSurface.GetPointData().GetNormals() == None): if (self.SignedDistanceArrayName != ''): normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(self.ReferenceSurface) normalsFilter.AutoOrientNormalsOn() normalsFilter.ConsistencyOn() normalsFilter.SplittingOff() normalsFilter.SetFlipNormals(self.FlipNormals) normalsFilter.Update() self.ReferenceSurface.GetPointData().SetNormals(normalsFilter.GetOutput().GetPointData().GetNormals()) self.PrintLog('Computing ICP transform.') icpTransform = vtkvmtk.vtkvmtkIterativeClosestPointTransform() icpTransform.SetSource(self.Surface) icpTransform.SetTarget(self.ReferenceSurface) icpTransform.GetLandmarkTransform().SetModeToRigidBody() icpTransform.StartByMatchingCentroidsOn() icpTransform.CheckMeanDistanceOn() icpTransform.SetMaximumNumberOfLandmarks(self.MaximumNumberOfLandmarks) icpTransform.SetMaximumNumberOfIterations(self.MaximumNumberOfIterations) icpTransform.SetMaximumMeanDistance(self.MaximumMeanDistance) if self.FarThreshold > 0.0: icpTransform.UseFarThresholdOn() icpTransform.SetFarThreshold(self.FarThreshold) else: icpTransform.UseFarThresholdOff() transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInput(self.Surface) transformFilter.SetTransform(icpTransform) transformFilter.Update() self.PrintLog('Mean distance: '+str(icpTransform.GetMeanDistance())) self.Surface = transformFilter.GetOutput() self.Matrix4x4 = icpTransform.GetMatrix() matrix = self.Matrix4x4 self.MatrixCoefficients = [ matrix.GetElement(0,0), matrix.GetElement(0,1), matrix.GetElement(0,2), matrix.GetElement(0,3), matrix.GetElement(1,0), matrix.GetElement(1,1), matrix.GetElement(1,2), matrix.GetElement(1,3), matrix.GetElement(2,0), matrix.GetElement(2,1), matrix.GetElement(2,2), matrix.GetElement(2,3), matrix.GetElement(3,0), matrix.GetElement(3,1), matrix.GetElement(3,2), matrix.GetElement(3,3)] self.PrintLog('Transform matrix:\n %f %f %f %f\n %f %f %f %f\n %f %f %f %f\n %f %f %f %f' % tuple(self.MatrixCoefficients)) if (self.DistanceArrayName != '') | (self.SignedDistanceArrayName != ''): self.PrintLog('Computing distance.') surfaceDistance = vtkvmtk.vtkvmtkSurfaceDistance() surfaceDistance.SetInput(self.Surface) surfaceDistance.SetReferenceSurface(self.ReferenceSurface) if (self.DistanceArrayName != ''): surfaceDistance.SetDistanceArrayName(self.DistanceArrayName) if (self.SignedDistanceArrayName != ''): surfaceDistance.SetSignedDistanceArrayName(self.SignedDistanceArrayName) surfaceDistance.Update() self.Surface = surfaceDistance.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacecelldatatopointdata.py0000664000175000017500000000343011757446472022345 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacecelldatatopointdata.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfacecelldatatopointdata = 'vmtkSurfaceCellDataToPointData' class vmtkSurfaceCellDataToPointData(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.SetScriptName('vmtksurfacecelldatatopointdata') self.SetScriptDoc('convert cell data arrays to point data surface arrays') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') cellDataToPointDataFilter = vtk.vtkCellDataToPointData() cellDataToPointDataFilter.SetInput(self.Surface) cellDataToPointDataFilter.PassCellDataOn() cellDataToPointDataFilter.Update() self.Surface = cellDataToPointDataFilter.GetPolyDataOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagecurvedmpr.py0000664000175000017500000000660311757446472017773 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vtkvmtkImageCurvedMPR.py,v $ ## Language: Python ## Date: $Date: 2008/02/12 13.44 $ ## Version: $Revision: 1.0 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Hugo Gratama van Andel ## Academic Medical Centre - University of Amsterdam ## Dept. Biomedical Engineering & Physics import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkimagecurvedmpr = 'vmtkImageCurvedMPR' class vmtkImageCurvedMPR(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.Centerlines = None self.NormalsArrayName = 'ParallelTransportNormals' self.FrenetTangentArrayName = 'FrenetTangent' self.InplaneOutputSize = 100 self.InplaneOutputSpacing = 1.0 self.ReslicingBackgroundLevel = 0.0 self.SetScriptName('vtkvmtkimagecurvedmpr') self.SetScriptDoc('Make an MPR image from a centerline and an input image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['Centerlines','centerlines','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['NormalsArrayName','normalsarray','str',1,'','name of the array where parallel transport normals to the centerlines are stored'], ['InplaneOutputSize','size','int',1,'(1,)','size of the square in pixels that each resulting MPR image should have'], ['ReslicingBackgroundLevel','background','float',1,'','value of the pixels in the mpr image that are outside of the inputimage'], ['InplaneOutputSpacing','spacing','float',1,'(0.001,)','spacing between the pixels in the output MPR images'], ['FrenetTangentArrayName','frenettangentarray','str',1,'','name of the array where tangent vectors of the Frenet reference system are stored'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter']]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') curvedMPRImageFilter = vtkvmtk.vtkvmtkCurvedMPRImageFilter() curvedMPRImageFilter.SetInput(self.Image) curvedMPRImageFilter.SetCenterline(self.Centerlines) curvedMPRImageFilter.SetParallelTransportNormalsArrayName(self.NormalsArrayName) curvedMPRImageFilter.SetFrenetTangentArrayName(self.FrenetTangentArrayName) curvedMPRImageFilter.SetInplaneOutputSpacing(self.InplaneOutputSpacing, self.InplaneOutputSpacing) curvedMPRImageFilter.SetInplaneOutputSize(self.InplaneOutputSize, self.InplaneOutputSize) curvedMPRImageFilter.SetReslicingBackgroundLevel(self.ReslicingBackgroundLevel) curvedMPRImageFilter.Update() self.Image = curvedMPRImageFilter.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkpointtransform.py0000664000175000017500000000407711757446472020051 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkpointtransform.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkpointtransform = 'vmtkPointTransform' class vmtkPointTransform(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Points = [] self.MatrixCoefficients = [] self.InvertMatrix = 0 self.SetScriptName('vmtkpointtransform') self.SetScriptDoc('transform points with a provided matrix') self.SetInputMembers([ ['Points','i','float',-1,'','point coordinates'], ['MatrixCoefficients','matrix','float',16,'','coefficients of transform matrix'], ['InvertMatrix','invert','bool',1,'','invert matrix before applying transformation'] ]) self.SetOutputMembers([ ['Points','o','float',-1,'','output point coordinates'] ]) def Execute(self): if len(self.Points) % 3 != 0: self.PrintError('Error: Points not made up of triplets.') return matrix = vtk.vtkMatrix4x4() matrix.DeepCopy(self.MatrixCoefficients) if self.InvertMatrix: matrix.Invert() transform = vtk.vtkMatrixToLinearTransform() transform.SetInput(matrix) outputPoints = [] for i in range(len(self.Points)/3): point = [self.Points[3*i+0],self.Points[3*i+1],self.Points[3*i+2]] outputPoint = transform.TransformPoint(point) outputPoints.append(outputPoint) self.Points = outputPoints if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacewriter.py0000664000175000017500000002127511757446472017650 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacewriter.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacewriter = 'vmtkSurfaceWriter' class vmtkSurfaceWriter(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.OutputFileName = '' self.Surface = None self.Input = None self.CellData = 0 self.SetScriptName('vmtksurfacewriter') self.SetScriptDoc('write surface to disk') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Format','f','str',1,'["vtkxml","vtk","stl","ply","pointdata","tecplot"]','file format'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['CellData','celldata','bool',1,'','write CellData when using pointdata format'], ['OutputFileName','ofile','str',1,'','output file name'], ['OutputFileName','o','str',1,'','output file name (deprecated: use -ofile)'] ]) self.SetOutputMembers([]) def WriteVTKSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK surface file.') writer = vtk.vtkPolyDataWriter() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) writer.Write() def WriteVTKXMLSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK XML surface file.') writer = vtk.vtkXMLPolyDataWriter() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) #writer.SetDataModeToAscii() writer.Write() def WriteSTLSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing STL surface file.') writer = vtk.vtkSTLWriter() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) writer.Write() def WritePLYSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PLY surface file.') writer = vtk.vtkPLYWriter() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) writer.Write() def WritePointDataSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PointData file.') f=open(self.OutputFileName, 'w') line = "X Y Z" arrayNames = [] dataArrays = self.Surface.GetPointData() if self.CellData: dataArrays = self.Surface.GetCellData(); for i in range(dataArrays.GetNumberOfArrays()): array = dataArrays.GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ' ' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ' ' + arrayName + str(j) line = line + '\n' f.write(line) numberOfLines = self.Surface.GetNumberOfPoints() if self.CellData: numberOfLines = self.Surface.GetNumberOfCells() for i in range(numberOfLines): point = None if not self.CellData: point = self.Surface.GetPoint(i) else: point = self.Surface.GetCell(i).GetPoints().GetPoint(0) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = dataArrays.GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) def WriteTecplotSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Tecplot file.') triangleFilter = vtk.vtkTriangleFilter() triangleFilter.SetInput(self.Surface) triangleFilter.PassVertsOff() triangleFilter.PassLinesOff() triangleFilter.Update() self.Surface = triangleFilter.GetOutput() f=open(self.OutputFileName, 'w') line = "VARIABLES = X,Y,Z" arrayNames = [] for i in range(self.Surface.GetPointData().GetNumberOfArrays()): array = self.Surface.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ',' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ',' + arrayName + str(j) line = line + '\n' f.write(line) line = "ZONE " + "N=" + str(self.Surface.GetNumberOfPoints()) + ',' + "E=" + str(self.Surface.GetNumberOfCells()) + ',' + "F=FEPOINT" + ',' + "ET=TRIANGLE" + '\n' f.write(line) for i in range(self.Surface.GetNumberOfPoints()): point = self.Surface.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Surface.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) for i in range(self.Surface.GetNumberOfCells()): cellPointIds = self.Surface.GetCell(i).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if (j>0): line = line + ' ' line = line + str(cellPointIds.GetId(j)+1) line = line + '\n' f.write(line) def Execute(self): if self.Surface == None: if self.Input == None: self.PrintError('Error: no Surface.') self.Surface = self.Input extensionFormats = {'vtp':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'stl':'stl', 'ply':'ply', 'tec':'tecplot', 'dat':'pointdata'} if self.OutputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.OutputFileName = tkFileDialog.asksaveasfilename(title="Output surface",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.OutputFileName) if not self.OutputFileName: self.PrintError('Error: no OutputFileName.') if self.GuessFormat and self.OutputFileName and not self.Format: import os.path extension = os.path.splitext(self.OutputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.WriteVTKSurfaceFile() elif (self.Format == 'vtkxml'): self.WriteVTKXMLSurfaceFile() elif (self.Format == 'stl'): self.WriteSTLSurfaceFile() elif (self.Format == 'ply'): self.WritePLYSurfaceFile() elif (self.Format == 'pointdata'): self.WritePointDataSurfaceFile() elif (self.Format == 'tecplot'): self.WriteTecplotSurfaceFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkactivetubes.py0000664000175000017500000000620611757446472017276 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkactivetubes.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.3 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. ## Developed with support from the EC FP7/2007-2013: ARCH, Project n. 224390 import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkactivetubes = 'vmtkActiveTubes' class vmtkActiveTubes(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerline = None self.Image = None self.RadiusArrayName = '' self.NumberOfIterations = 100 self.PotentialWeight = 1.0 self.StiffnessWeight = 1.0 self.Convergence = 1E-5 self.CFLCoefficient = 0.1 self.MinimumRadius = 0.0 self.NumberOfAngularEvaluations = 16 self.NegativeNormWarnings = False self.SetScriptName('vmtkactivetubes') self.SetScriptDoc('') self.SetInputMembers([ ['Centerline','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Image','image','vtkImageData',1,'','','vmtkimagereader'], ['RadiusArrayName','radiusarray','str',1,''], ['NumberOfIterations','iterations','int',1,'(0,)'], ['PotentialWeight','potentialweight','float',1,'(0.0,)'], ['StiffnessWeight','stiffnessweight','float',1,'(0.0,)'], ['Convergence','convergence','float',1,'(0.0,)'], ['CFLCoefficient','cfl','float',1,'(0.0,)'], ['MinimumRadius','minradius','float',1,'(0.0,)'], ['NegativeNormWarnings','warnings','bool',1,''], ['NumberOfAngularEvaluations','angularevaluations','int',1,'(0,)']] ) self.SetOutputMembers([ ['Centerline','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: Image not set.') activeTubes = vtkvmtk.vtkvmtkActiveTubeFilter() activeTubes.SetInput(self.Centerline) activeTubes.SetPotentialImage(self.Image) activeTubes.SetRadiusArrayName(self.RadiusArrayName) activeTubes.SetConvergence(self.Convergence) activeTubes.SetPotentialWeight(self.PotentialWeight) activeTubes.SetStiffnessWeight(self.StiffnessWeight) activeTubes.SetNumberOfIterations(self.NumberOfIterations) activeTubes.SetCFLCoefficient(self.CFLCoefficient) activeTubes.SetMinimumRadius(self.MinimumRadius) activeTubes.SetNumberOfAngularEvaluations(self.NumberOfAngularEvaluations) activeTubes.SetNegativeNormWarnings(self.NegativeNormWarnings) activeTubes.Update() self.Centerline = activeTubes.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacetransformtoras.py0000664000175000017500000000421511757446472021413 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacetransformtoras.py,v $ ## Language: Python ## Date: $Date: Sun Feb 21 17:02:37 CET 2010$ ## Version: $Revision: 1.0 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacetransformtoras = 'vmtkSurfaceTransformToRAS' class vmtkSurfaceTransformToRAS(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.XyzToRasMatrixCoefficients = None self.SetScriptName('vmtksurfacetransformtoras') self.SetScriptDoc('transform a surface generated in XYZ image space into RAS space') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['XyzToRasMatrixCoefficients','matrix','float',16,'','coefficients of XYZToRAS transform matrix'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: no Surface.') if self.XyzToRasMatrixCoefficients == None: self.PrintError('Error: no XyzToRasMatrixCoefficients.') matrix = vtk.vtkMatrix4x4() matrix.DeepCopy(self.XyzToRasMatrixCoefficients) transform = vtk.vtkTransform() transform.SetMatrix(matrix) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInput(self.Surface) transformFilter.SetTransform(transform) transformFilter.Update() self.Surface = transformFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbranchextractor.py0000664000175000017500000000523311757446472020150 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchextractor.py,v $ ## Language: Python ## Date: $Date: 2006/02/23 09:31:39 $ ## Version: $Revision: 1.11 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbranchextractor = 'vmtkBranchExtractor' class vmtkBranchExtractor(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.RadiusArrayName = '' self.BlankingArrayName = 'Blanking' self.GroupIdsArrayName = 'GroupIds' self.CenterlineIdsArrayName = 'CenterlineIds' self.TractIdsArrayName = 'TractIds' self.SetScriptName('vmtkbranchextractor') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1], ['GroupIdsArrayName','groupidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['BlankingArrayName','blankingarray','str',1], ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['GroupIdsArrayName','groupidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['BlankingArrayName','blankingarray','str',1] ]) def Execute(self): if not self.Centerlines: self.PrintError('Error: No input centerlines.') branchExtractor = vtkvmtk.vtkvmtkCenterlineBranchExtractor() branchExtractor.SetInput(self.Centerlines) branchExtractor.SetBlankingArrayName(self.BlankingArrayName) branchExtractor.SetRadiusArrayName(self.RadiusArrayName) branchExtractor.SetGroupIdsArrayName(self.GroupIdsArrayName) branchExtractor.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) branchExtractor.SetTractIdsArrayName(self.TractIdsArrayName) branchExtractor.Update() self.Centerlines = branchExtractor.GetOutput() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbifurcationsections.py0000664000175000017500000002705411757446472021041 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbifurcationsections.py,v $ ## Language: Python ## Date: $Date: 2006/10/17 15:16:16 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbifurcationsections = 'vmtkBifurcationSections' class vmtkBifurcationSections(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.BifurcationSections = None self.NumberOfDistanceSpheres = 1 self.RadiusArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.BlankingArrayName = '' self.OutputSectionPointGroupId = None self.OutputSectionPointBifurcationGroupId = None self.OutputSectionPoint = [] self.OutputSectionNormal = [] self.OutputSectionArea = 0.0 self.BifurcationSectionGroupIdsArrayName = 'BifurcationSectionGroupIds' self.BifurcationSectionBifurcationGroupIdsArrayName = 'BifurcationSectionBifurcationGroupIds' self.BifurcationSectionPointArrayName = 'BifurcationSectionPoint' self.BifurcationSectionNormalArrayName = 'BifurcationSectionNormal' self.BifurcationSectionAreaArrayName = 'BifurcationSectionArea' self.BifurcationSectionMinSizeArrayName = 'BifurcationSectionMinSize' self.BifurcationSectionMaxSizeArrayName = 'BifurcationSectionMaxSize' self.BifurcationSectionShapeArrayName = 'BifurcationSectionShape' self.BifurcationSectionClosedArrayName = 'BifurcationSectionClosed' self.BifurcationSectionOrientationArrayName = 'BifurcationSectionOrientation' self.BifurcationSectionDistanceSpheresArrayName = 'BifurcationSectionDistanceSpheres' self.SetScriptName('vmtkbifurcationsections') self.SetScriptDoc('compute branch sections located a fixed number of spheres away from each bifurcation. The script takes in input the surface and the relative centerlines, both already split into branches.') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface, already split into branches','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','the input centerlines, already split into branches','vmtksurfacereader'], ['NumberOfDistanceSpheres','distancespheres','int',1,'','distance from the bifurcation at which the sections have to be taken; the distance is expressed in number of inscribed spheres, where each sphere touches the center of the previous one'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where centerline radius is stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['CenterlineIdsArrayName','centerlineidsarray','str',1,'','name of the array where centerline ids are stored'], ['TractIdsArrayName','tractidsarray','str',1,'','name of the array where centerline tract ids are stored'], ['BlankingArrayName','blankingarray','str',1,'','name of the array where centerline blanking information about branches is stored'], ['BifurcationSectionGroupIdsArrayName','bifurcationsectiongroupids','str',1,'','name of the array where the group id to which each section belongs has to be stored'], ['BifurcationSectionBifurcationGroupIdsArrayName','bifurcationsectionbifurcationgroupids','str',1,'','name of the array where the bifurcation group id to which each section belongs has to be stored'], ['BifurcationSectionPointArrayName','bifurcationsectionpoint','str',1,'','name of the array where the point at which bifurcation sections are defined have to be stored'], ['BifurcationSectionNormalArrayName','bifurcationsectionnormal','str',1,'','name of the array where the bifurcation section normals have to be stored'], ['BifurcationSectionAreaArrayName','bifurcationsectionarea','str',1,'','name of the array where the area of bifurcation sections have to be stored'], ['BifurcationSectionMinSizeArrayName','bifurcationsectionminsize','str',1,'','name of the array where the minimum diameter of each section has to be stored'], ['BifurcationSectionMaxSizeArrayName','bifurcationsectionmaxsize','str',1,'','name of the array where the maximum diameter of each bifurcation sections has to be stored'], ['BifurcationSectionShapeArrayName','bifurcationsectionshape','str',1,'','name of the array where the shape index, i.e. the ratio between minimum and maximum diameter, of each bifurcation section has to be stored'], ['BifurcationSectionClosedArrayName','bifurcationsectionclosed','str',1,'','name of the array containing 1 if a section is closed and 0 otherwise'], ['BifurcationSectionOrientationArrayName','bifurcationsectionorientation','str',1,'','name of the array containing 0 if a section is upstream and 0 downstream its bifurcation'], ['BifurcationSectionDistanceSpheresArrayName','bifurcationsectiondistancespheres','str',1,'','name of the array containing the number of spheres away from the bifurcation the section is located at'], ['OutputSectionPointGroupId','sectionpointgroupid','int',1,'(0,)'], ['OutputSectionPointBifurcationGroupId','sectionpointbifurcationgroupid','int',1,'(0,)'] ]) self.SetOutputMembers([ ['BifurcationSections','o','vtkPolyData',1,'','the output sections','vmtksurfacewriter'], ['BifurcationSectionGroupIdsArrayName','bifurcationsectiongroupids','str',1,'','name of the array where the group id to which each section belongs are stored'], ['BifurcationSectionBifurcationGroupIdsArrayName','bifurcationsectionbifurcationgroupids','str',1,'','name of the array where the bifurcation group id to which each section belongs has to be stored'], ['BifurcationSectionPointArrayName','bifurcationsectionpoint','str',1,'','name of the array where the point at which bifurcation sections are defined are stored'], ['BifurcationSectionNormalArrayName','bifurcationsectionnormal','str',1,'','name of the array where bifurcation section normals are stored'], ['BifurcationSectionAreaArrayName','bifurcationsectionarea','str',1,'','name of the array where the area of bifurcation sections are stored'], ['BifurcationSectionMinSizeArrayName','bifurcationsectionminsize','str',1,'','name of the array where the minimum diameter of each section are stored'], ['BifurcationSectionMaxSizeArrayName','bifurcationsectionmaxsize','str',1,'','name of the array where the minimum diameter of each bifurcation sections has to be stored'], ['BifurcationSectionShapeArrayName','bifurcationsectionshape','str',1,'','name of the array where the shape index, i.e. the ratio between minimum and maximum diameter, of each bifurcation section are stored'], ['BifurcationSectionClosedArrayName','bifurcationsectionclosed','str',1,'','name of the array containing 1 if a section is closed and 0 otherwise'], ['BifurcationSectionOrientationArrayName','bifurcationsectionorientation','str',1,'','name of the array containing 0 if a section is upstream and 0 downstream its bifurcation'], ['BifurcationSectionDistanceSpheresArrayName','bifurcationsectiondistancespheres','str',1,'','name of the array containing the number of spheres away from the bifurcation the section is located at'], ['OutputSectionPoint','sectionpoint','float',3], ['OutputSectionNormal','sectionnormal','float',3], ['OutputSectionArea','sectionarea','float',1] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') bifurcationSections = vtkvmtk.vtkvmtkPolyDataBifurcationSections() bifurcationSections.SetInput(self.Surface) bifurcationSections.SetGroupIdsArrayName(self.GroupIdsArrayName) bifurcationSections.SetCenterlines(self.Centerlines) bifurcationSections.SetNumberOfDistanceSpheres(self.NumberOfDistanceSpheres) bifurcationSections.SetCenterlineRadiusArrayName(self.RadiusArrayName) bifurcationSections.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) bifurcationSections.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) bifurcationSections.SetCenterlineTractIdsArrayName(self.TractIdsArrayName) bifurcationSections.SetBlankingArrayName(self.BlankingArrayName) bifurcationSections.SetBifurcationSectionGroupIdsArrayName(self.BifurcationSectionGroupIdsArrayName) bifurcationSections.SetBifurcationSectionBifurcationGroupIdsArrayName(self.BifurcationSectionBifurcationGroupIdsArrayName) bifurcationSections.SetBifurcationSectionPointArrayName(self.BifurcationSectionPointArrayName) bifurcationSections.SetBifurcationSectionNormalArrayName(self.BifurcationSectionNormalArrayName) bifurcationSections.SetBifurcationSectionAreaArrayName(self.BifurcationSectionAreaArrayName) bifurcationSections.SetBifurcationSectionMinSizeArrayName(self.BifurcationSectionMinSizeArrayName) bifurcationSections.SetBifurcationSectionMaxSizeArrayName(self.BifurcationSectionMaxSizeArrayName) bifurcationSections.SetBifurcationSectionShapeArrayName(self.BifurcationSectionShapeArrayName) bifurcationSections.SetBifurcationSectionClosedArrayName(self.BifurcationSectionClosedArrayName) bifurcationSections.SetBifurcationSectionOrientationArrayName(self.BifurcationSectionOrientationArrayName) bifurcationSections.SetBifurcationSectionDistanceSpheresArrayName(self.BifurcationSectionDistanceSpheresArrayName) bifurcationSections.Update() self.BifurcationSections = bifurcationSections.GetOutput() if self.OutputSectionPointGroupId != None and self.OutputSectionPointBifurcationGroupId != None: groupIds = self.BifurcationSections.GetCellData().GetArray(self.BifurcationSectionGroupIdsArrayName) bifurcationGroupIds = self.BifurcationSections.GetCellData().GetArray(self.BifurcationSectionBifurcationGroupIdsArrayName) for i in range(self.BifurcationSections.GetNumberOfCells()): if int(groupIds.GetTuple1(i)) == self.OutputSectionPointGroupId and int(bifurcationGroupIds.GetTuple1(i)) == self.OutputSectionPointBifurcationGroupId: self.OutputSectionPoint = self.BifurcationSections.GetCellData().GetArray(self.BifurcationSectionPointArrayName).GetTuple3(i) self.OutputSectionNormal = self.BifurcationSections.GetCellData().GetArray(self.BifurcationSectionNormalArrayName).GetTuple3(i) self.OutputSectionArea = self.BifurcationSections.GetCellData().GetArray(self.BifurcationSectionAreaArrayName).GetTuple1(i) self.InputInfo('SectionPoint: '+str(self.OutputSectionPoint)) self.InputInfo('SectionNormal: '+str(self.OutputSectionNormal)) self.InputInfo('SectionArea: '+str(self.OutputSectionArea)) if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkrendertoimage.py0000664000175000017500000000347211757446472017607 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkrendertoimage.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.10 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vmtkrenderer import pypes vmtkrendertoimage = 'vmtkRenderToImage' class vmtkRenderToImage(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.vmtkRenderer = None self.Magnification = 1 self.Image = None self.SetScriptName('vmtkrendertoimage') self.SetScriptDoc('takes a renderer in input and saves the rendering into an image file') self.SetInputMembers([ ['vmtkRenderer','renderer','vmtkRenderer',1,'','the input renderer'], ['Magnification','magnification','int',1,'','the magnification factor relative to the rendering window']]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if not self.vmtkRenderer: self.PrintError('Error: no Renderer.') windowToImage = vtk.vtkWindowToImageFilter() windowToImage.SetInput(self.vmtkRenderer.RenderWindow) windowToImage.SetMagnification(self.Magnification) windowToImage.Update() self.vmtkRenderer.RenderWindow.Render() self.Image = windowToImage.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbranchsections.py0000664000175000017500000001652411757446472017771 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchsections.py,v $ ## Language: Python ## Date: $Date: 2006/10/17 15:16:16 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbranchsections = 'vmtkBranchSections' class vmtkBranchSections(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.BranchSections = None self.NumberOfDistanceSpheres = 1 self.ReverseDirection = 0 self.RadiusArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.BlankingArrayName = '' self.BranchSectionGroupIdsArrayName = 'BranchSectionGroupIds' self.BranchSectionAreaArrayName = 'BranchSectionArea' self.BranchSectionMinSizeArrayName = 'BranchSectionMinSize' self.BranchSectionMaxSizeArrayName = 'BranchSectionMaxSize' self.BranchSectionShapeArrayName = 'BranchSectionShape' self.BranchSectionClosedArrayName = 'BranchSectionClosed' self.BranchSectionDistanceSpheresArrayName = 'BranchSectionDistanceSpheres' self.SetScriptName('vmtkbranchsections') self.SetScriptDoc('compute geometric properties of branch sections located a fixed number of spheres away from each bifurcation. The script takes in input the surface and the relative centerlines, both already split into branches.') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface, already split into branches','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','the input centerlines, already split into branches','vmtksurfacereader'], ['NumberOfDistanceSpheres','distancespheres','int',1,'(0,)','distance from the bifurcation at which the sections have to be taken; the distance is expressed in number of inscribed spheres, where each sphere touches the center of the previous one'], ['ReverseDirection','reverse','bool',1,'','toggle start generating sections from the end of the branches rather than the start'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where centerline radius is stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['CenterlineIdsArrayName','centerlineidsarray','str',1,'','name of the array where centerline ids are stored'], ['TractIdsArrayName','tractidsarray','str',1,'','name of the array where centerline tract ids are stored'], ['BlankingArrayName','blankingarray','str',1,'','name of the array where centerline blanking information about branches is stored'], ['BranchSectionGroupIdsArrayName','branchsectiongroupids','str',1,'','name of the array where the group id to which each section belongs has to be stored'], ['BranchSectionAreaArrayName','branchsectionarea','str',1,'','name of the array where the area of bifurcation sections have to be stored'], ['BranchSectionMinSizeArrayName','branchsectionminsize','str',1,'','name of the array where the minimum diameter of each section has to be stored'], ['BranchSectionMaxSizeArrayName','branchsectionmaxsize','str',1,'','name of the array where the maximum diameter of each bifurcation sections has to be stored'], ['BranchSectionShapeArrayName','branchsectionshape','str',1,'','name of the array where the shape index, i.e. the ratio between minimum and maximum diameter, of each bifurcation section has to be stored'], ['BranchSectionClosedArrayName','branchsectionclosed','str',1,'','name of the array containing 1 if a section is closed and 0 otherwise'], ['BranchSectionDistanceSpheresArrayName','branchsectiondistancespheres','str',1,'','name of the array containing the number of distance spheres the section is taken at'] ]) self.SetOutputMembers([ ['BranchSections','o','vtkPolyData',1,'','the output sections','vmtksurfacewriter'], ['BranchSectionGroupIdsArrayName','branchsectiongroupids','str',1,'','name of the array where the group id to which each section belongs are stored'], ['BranchSectionAreaArrayName','branchsectionarea','str',1,'','name of the array where the area of bifurcation sections are stored'], ['BranchSectionMinSizeArrayName','branchsectionminsize','str',1,'','name of the array where the minimum diameter of each section are stored'], ['BranchSectionMaxSizeArrayName','branchsectionmaxsize','str',1,'','name of the array where the minimum diameter of each bifurcation sections has to be stored'], ['BranchSectionShapeArrayName','branchsectionshape','str',1,'','name of the array where the shape index, i.e. the ratio between minimum and maximum diameter, of each bifurcation section are stored'], ['BranchSectionClosedArrayName','branchsectionclosed','str',1,'','name of the array containing 1 if a section is closed and 0 otherwise'], ['BranchSectionDistanceSpheresArrayName','branchsectiondistancespheres','str',1,'','name of the array containing the number of distance spheres the section is taken at'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') branchSections = vtkvmtk.vtkvmtkPolyDataBranchSections() branchSections.SetInput(self.Surface) branchSections.SetGroupIdsArrayName(self.GroupIdsArrayName) branchSections.SetCenterlines(self.Centerlines) branchSections.SetNumberOfDistanceSpheres(self.NumberOfDistanceSpheres) branchSections.SetReverseDirection(self.ReverseDirection) branchSections.SetCenterlineRadiusArrayName(self.RadiusArrayName) branchSections.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) branchSections.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) branchSections.SetCenterlineTractIdsArrayName(self.TractIdsArrayName) branchSections.SetBlankingArrayName(self.BlankingArrayName) branchSections.SetBranchSectionGroupIdsArrayName(self.BranchSectionGroupIdsArrayName) branchSections.SetBranchSectionAreaArrayName(self.BranchSectionAreaArrayName) branchSections.SetBranchSectionMinSizeArrayName(self.BranchSectionMinSizeArrayName) branchSections.SetBranchSectionMaxSizeArrayName(self.BranchSectionMaxSizeArrayName) branchSections.SetBranchSectionShapeArrayName(self.BranchSectionShapeArrayName) branchSections.SetBranchSectionClosedArrayName(self.BranchSectionClosedArrayName) branchSections.SetBranchSectionDistanceSpheresArrayName(self.BranchSectionDistanceSpheresArrayName) branchSections.Update() self.BranchSections = branchSections.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshclipper.py0000664000175000017500000000702411757446472017272 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshclipper.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vmtkrenderer import pypes vmtkmeshclipper = 'vmtkMeshClipper' class vmtkMeshClipper(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Actor = None self.BoxWidget = None self.Planes = None self.SetScriptName('vmtkmeshclipper') self.SetScriptDoc('interactively clip a mesh with a box') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def ClipCallback(self, obj): if self.BoxWidget.GetEnabled() != 1: return self.BoxWidget.GetPlanes(self.Planes) self.Clipper.Update() self.Mesh.DeepCopy(self.Clipper.GetClippedOutput()) mapper = vtk.vtkDataSetMapper() mapper.SetInput(self.Mesh) mapper.ScalarVisibilityOff() self.Actor.SetMapper(mapper) self.BoxWidget.Off() def Display(self): self.BoxWidget.SetInput(self.Mesh) self.BoxWidget.PlaceWidget() self.vmtkRenderer.Render() def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') self.Planes = vtk.vtkPlanes() self.Clipper = vtk.vtkClipDataSet() self.Clipper.SetInput(self.Mesh) self.Clipper.SetClipFunction(self.Planes) self.Clipper.GenerateClippedOutputOn() self.Clipper.InsideOutOn() if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) mapper = vtk.vtkDataSetMapper() mapper.SetInput(self.Mesh) mapper.ScalarVisibilityOff() self.Actor = vtk.vtkActor() self.Actor.SetMapper(mapper) self.vmtkRenderer.Renderer.AddActor(self.Actor) self.BoxWidget = vtk.vtkBoxWidget() self.BoxWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.BoxWidget.GetFaceProperty().SetColor(0.6,0.6,0.2) self.BoxWidget.GetFaceProperty().SetOpacity(0.25) self.vmtkRenderer.AddKeyBinding('i','Interact.', self.InteractCallback) self.vmtkRenderer.AddKeyBinding('space','Clip.', self.ClipCallback) self.Display() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacedistance.py0000664000175000017500000000745311757446472020130 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacedistance.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfacedistance = 'vmtkSurfaceDistance' class vmtkSurfaceDistance(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.ReferenceSurface = None self.Surface = None self.DistanceArrayName = '' self.DistanceVectorsArrayName = '' self.SignedDistanceArrayName = '' self.FlipNormals = 0 self.SetScriptName('vmtksurfacedistance') self.SetScriptDoc('compute the pointwise minimum distance of the input surface from a reference surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ReferenceSurface','r','vtkPolyData',1,'','the reference surface','vmtksurfacereader'], ['DistanceArrayName','distancearray','str',1,'','name of the array where the distance of the input surface to the reference surface has to be stored'], ['DistanceVectorsArrayName','distancevectorsarray','str',1,'','name of the array where the distance vectors of the input surface to the reference surface has to be stored'], ['SignedDistanceArrayName','signeddistancearray','str',1,'','name of the array where the signed distance of the input surface to the reference surface is stored; distance is positive if distance vector and normal to the reference surface have negative dot product, i.e. if the input surface is outer with respect to the reference surface'], ['FlipNormals','flipnormals','bool',1,'','flip normals to the reference surface after computing them'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') if self.ReferenceSurface == None: self.PrintError('Error: No ReferenceSurface.') if self.SignedDistanceArrayName != '': normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(self.ReferenceSurface) normalsFilter.AutoOrientNormalsOn() normalsFilter.SetFlipNormals(self.FlipNormals) normalsFilter.Update() self.ReferenceSurface.GetPointData().SetNormals(normalsFilter.GetOutput().GetPointData().GetNormals()) if self.DistanceArrayName != '' or self.DistanceVectorsArrayName != '' or self.SignedDistanceArrayName != '': self.PrintLog('Computing distance.') surfaceDistance = vtkvmtk.vtkvmtkSurfaceDistance() surfaceDistance.SetInput(self.Surface) surfaceDistance.SetReferenceSurface(self.ReferenceSurface) if self.DistanceArrayName != '': surfaceDistance.SetDistanceArrayName(self.DistanceArrayName) if self.DistanceVectorsArrayName != '': surfaceDistance.SetDistanceVectorsArrayName(self.DistanceVectorsArrayName) if self.SignedDistanceArrayName != '': surfaceDistance.SetSignedDistanceArrayName(self.SignedDistanceArrayName) surfaceDistance.Update() self.Surface = surfaceDistance.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimageseeder.py0000664000175000017500000001605611757446472017236 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimageseeder.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkimageseeder = 'vmtkImageSeeder' class vmtkImageSeeder(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Display = 1 self.ArrayName = '' self.Picker = None self.PlaneWidgetX = None self.PlaneWidgetY = None self.PlaneWidgetZ = None self.SeedActor = None self.Seeds = None self.TextureInterpolation = 1 self.KeepSeeds = 0 self.SetScriptName('vmtkimageseeder') self.SetScriptDoc('interactively place seeds in a 3D image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['ArrayName','array','str',1,'','name of the array to display'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['Display','display','bool',1,'','toggle rendering'], ['KeepSeeds','keepseeds','bool',1,'','toggle avoid removal of seeds from renderer'], ['TextureInterpolation','textureinterpolation','bool',1,'','toggle interpolation of graylevels on image planes'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'], ['Seeds','seeds','vtkPolyData',1,'','the placed seeds','vmtksurfacewriter'] ]) def AddSeed(self, obj, event): if self.vmtkRenderer.RenderWindowInteractor.GetControlKey() == 0: return cursorData = [0.0,0.0,0.0,0.0] obj.GetCursorData(cursorData) spacing = self.Image.GetSpacing() origin = self.Image.GetOrigin() extent = self.Image.GetWholeExtent() point = [0.0,0.0,0.0] point[0] = cursorData[0] * spacing[0] + origin[0] point[1] = cursorData[1] * spacing[1] + origin[1] point[2] = cursorData[2] * spacing[2] + origin[2] self.Seeds.GetPoints().InsertNextPoint(point) self.Seeds.Modified() self.vmtkRenderer.RenderWindow.Render() def WidgetsOn(self): self.PlaneWidgetX.On() self.PlaneWidgetY.On() self.PlaneWidgetZ.On() def WidgetsOff(self): self.PlaneWidgetX.Off() self.PlaneWidgetY.Off() self.PlaneWidgetZ.Off() def InitializeSeeds(self): self.Seeds.Initialize() seedPoints = vtk.vtkPoints() self.Seeds.SetPoints(seedPoints) def BuildView(self): if (self.ArrayName != ''): self.Image.GetPointData().SetActiveScalars(self.ArrayName) wholeExtent = self.Image.GetWholeExtent() # self.PlaneWidgetX.SetResliceInterpolateToNearestNeighbour() self.PlaneWidgetX.SetResliceInterpolateToLinear() self.PlaneWidgetX.SetTextureInterpolate(self.TextureInterpolation) self.PlaneWidgetX.SetInput(self.Image) self.PlaneWidgetX.SetPlaneOrientationToXAxes() self.PlaneWidgetX.SetSliceIndex(wholeExtent[0]) self.PlaneWidgetX.DisplayTextOn() self.PlaneWidgetX.KeyPressActivationOff() # self.PlaneWidgetY.SetResliceInterpolateToNearestNeighbour() self.PlaneWidgetY.SetResliceInterpolateToLinear() self.PlaneWidgetY.SetTextureInterpolate(self.TextureInterpolation) self.PlaneWidgetY.SetInput(self.Image) self.PlaneWidgetY.SetPlaneOrientationToYAxes() self.PlaneWidgetY.SetSliceIndex(wholeExtent[2]) self.PlaneWidgetY.DisplayTextOn() self.PlaneWidgetY.KeyPressActivationOff() self.PlaneWidgetY.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) # self.PlaneWidgetZ.SetResliceInterpolateToNearestNeighbour() self.PlaneWidgetZ.SetResliceInterpolateToLinear() self.PlaneWidgetZ.SetTextureInterpolate(self.TextureInterpolation) self.PlaneWidgetZ.SetInput(self.Image) self.PlaneWidgetZ.SetPlaneOrientationToZAxes() self.PlaneWidgetZ.SetSliceIndex(wholeExtent[4]) self.PlaneWidgetZ.DisplayTextOn() self.PlaneWidgetZ.KeyPressActivationOff() self.PlaneWidgetZ.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphs.SetInput(self.Seeds) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToDataScalingOff() glyphs.SetScaleFactor(self.Image.GetLength()*0.01) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) self.SeedActor = vtk.vtkActor() self.SeedActor.SetMapper(glyphMapper) self.SeedActor.GetProperty().SetColor(1.0,0.0,0.0) self.vmtkRenderer.Renderer.AddActor(self.SeedActor) self.WidgetsOn() if (self.Display == 1): self.vmtkRenderer.AddKeyBinding('Ctrl','Add Seed.') self.vmtkRenderer.Render() def Execute(self): if (self.Image == None) & (self.Display == 1): self.PrintError('Error: no Image.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) ##self.PrintLog('Ctrl + left click to add seed.') self.Picker = vtk.vtkCellPicker() self.Picker.SetTolerance(0.005) self.PlaneWidgetX = vtk.vtkImagePlaneWidget() self.PlaneWidgetX.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetX.AddObserver("StartInteractionEvent", self.AddSeed) self.PlaneWidgetX.SetPicker(self.Picker) self.PlaneWidgetY = vtk.vtkImagePlaneWidget() self.PlaneWidgetY.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetY.AddObserver("StartInteractionEvent", self.AddSeed) self.PlaneWidgetY.SetPicker(self.Picker) self.PlaneWidgetZ = vtk.vtkImagePlaneWidget() self.PlaneWidgetZ.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetZ.AddObserver("StartInteractionEvent", self.AddSeed) self.PlaneWidgetZ.SetPicker(self.Picker) self.Seeds = vtk.vtkPolyData() self.InitializeSeeds() self.BuildView() self.WidgetsOff() if not self.KeepSeeds: self.vmtkRenderer.Renderer.RemoveActor(self.SeedActor) if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtklineresampling.py0000664000175000017500000000407211757446472017770 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtklineresampling.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtklineresampling = 'vmtkLineResampling' class vmtkLineResampling(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Length = 0.0; self.SetScriptName('vmtklineresampling') self.SetScriptDoc('resample input lines with a spline filter') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface containing vtkPolyLine cells','vmtksurfacereader'], ['Length','length','float',1,'(0.0,)','length of the resampling interval'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface containing the resampled vtkPolyLine cells','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(self.Surface) cleaner.Update() if self.Length == 0.0: self.Length = cleaner.GetOutput().GetLength() / 100.0 splineFilter = vtk.vtkSplineFilter() splineFilter.SetInput(cleaner.GetOutput()) splineFilter.SetSubdivideToLength() splineFilter.SetLength(self.Length) splineFilter.Update() self.Surface = splineFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbifurcationreferencesystems.py0000664000175000017500000000724711757446472022602 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbifurcationreferencesystems.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbifurcationreferencesystems = 'vmtkBifurcationReferenceSystems' class vmtkBifurcationReferenceSystems(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.ReferenceSystems = None self.RadiusArrayName = '' self.BlankingArrayName = '' self.GroupIdsArrayName = '' self.ReferenceSystemsNormalArrayName = 'Normal' self.ReferenceSystemsUpNormalArrayName = 'UpNormal' self.SetScriptName('vmtkbifurcationreferencesystems') self.SetScriptDoc('compute reference systems for each bifurcation of a tree. The script takes in input the centerlines already split into branches.') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input split centerlines','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','the name of the array where centerline radius values are stored'], ['BlankingArrayName','blankingarray','str',1,'','the name of the array where centerline blanking information about branches is stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','the name of the array where centerline group ids are stored'], ['ReferenceSystemsNormalArrayName','normalarray','str',1,'','the name of the array where reference system plane normals have to be stored'], ['ReferenceSystemsUpNormalArrayName','upnormalarray','str',1,'','the name of the array where reference system upnormals have to be stored'] ]) self.SetOutputMembers([ ['ReferenceSystems','o','vtkPolyData',1,'','the output reference systems, given as points coinciding with the origins','vmtksurfacewriter'], ['ReferenceSystemsNormalArrayName','normalarray','str',1,'','the name of the array where reference system plane normals are stored'], ['ReferenceSystemsUpNormalArrayName','upnormalarray','str',1,'','the name of the array where reference system upnormals are stored'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') bifurcationReferenceSystems = vtkvmtk.vtkvmtkCenterlineBifurcationReferenceSystems() bifurcationReferenceSystems.SetInput(self.Centerlines) bifurcationReferenceSystems.SetRadiusArrayName(self.RadiusArrayName) bifurcationReferenceSystems.SetBlankingArrayName(self.BlankingArrayName) bifurcationReferenceSystems.SetGroupIdsArrayName(self.GroupIdsArrayName) bifurcationReferenceSystems.SetNormalArrayName(self.ReferenceSystemsNormalArrayName) bifurcationReferenceSystems.SetUpNormalArrayName(self.ReferenceSystemsUpNormalArrayName) ## bifurcationReferenceSystems.SetReferenceGroupId(self.ReferenceGroupId) bifurcationReferenceSystems.Update() self.ReferenceSystems = bifurcationReferenceSystems.GetOutput() if self.ReferenceSystems.GetSource(): self.ReferenceSystems.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtktetringenerator.py0000664000175000017500000006765011757446472020206 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtktetringenerator.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.14 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import math import vtk import vtkvmtk import pypes vmtktetringenerator = 'vmtkTetrInGenerator' class SectionProperties: def __init__(self): self.Radius = 0.0 self.Normal = [1.0, 0.0, 0.0] self.Origin = [0.0, 0.0, 0.0] self.NormalizationTransform = None self.FlipOutwardNormal = 0 self.Mesh = None self.SectionBoundaryPointIds = None def ComputeSectionOrigin(self): self.Origin = [0.0, 0.0, 0.0] numberOfIds = self.SectionBoundaryPointIds.GetNumberOfIds() weightSum = 0.0 for i in range(numberOfIds): point = [0.0,0.0,0.0] self.NormalizationTransform.TransformPoint(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),point) weight = pow(vtk.vtkMath.Distance2BetweenPoints(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId((i+1)%numberOfIds))),0.5) + pow(vtk.vtkMath.Distance2BetweenPoints(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId((i+numberOfIds-1)%numberOfIds))),0.5) weightSum += weight for j in range(3): self.Origin[j] += weight * point[j] for j in range(3): self.Origin[j] /= weightSum def ComputeSectionRadius(self): self.Radius = 0.0 numberOfIds = self.SectionBoundaryPointIds.GetNumberOfIds() weightSum = 0.0 for i in range(numberOfIds): point = [0.0,0.0,0.0] self.NormalizationTransform.TransformPoint(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),point) weight = pow(vtk.vtkMath.Distance2BetweenPoints(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId((i+1)%numberOfIds))),0.5) + pow(vtk.vtkMath.Distance2BetweenPoints(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId((i+numberOfIds-1)%numberOfIds))),0.5) weightSum += weight self.Radius += weight * pow(vtk.vtkMath.Distance2BetweenPoints(self.Origin,point),0.5) self.Radius /= weightSum def ComputeSectionNormal(self): self.Normal = [0.0, 0.0, 0.0] numberOfIds = self.SectionBoundaryPointIds.GetNumberOfIds() point1 = [0.0,0.0,0.0] self.NormalizationTransform.TransformPoint(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(0)),point1) vector1 = [point1[0] - self.Origin[0], point1[1] - self.Origin[1], point1[2] - self.Origin[2]] vtk.vtkMath.Normalize(vector1) vector2 = None minAbsDot = 1.0 for i in range(1,numberOfIds): currentPoint = [0.0,0.0,0.0] self.NormalizationTransform.TransformPoint(self.Mesh.GetPoint(self.SectionBoundaryPointIds.GetId(i)),currentPoint) currentVector = [currentPoint[0] - self.Origin[0], currentPoint[1] - self.Origin[1], currentPoint[2] - self.Origin[2]] vtk.vtkMath.Normalize(currentVector) absDot = abs(vtk.vtkMath.Dot(vector1,currentVector)) if (absDotmaxAbsDot): maxAbsDot = absDot farVector = currentVector dot = vtk.vtkMath.Dot(self.Normal,farVector) if (dot < 0.0): self.FlipNormal() def Execute(self): if self.Mesh == None: return if self.SectionBoundaryPointIds == None: return self.ComputeSectionOrigin() self.ComputeSectionRadius() self.ComputeSectionNormal() self.OrientNormalOutward() if (self.FlipOutwardNormal == 1): self.FlipNormal() class vmtkTetrInGenerator(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.OutputFileName = '' self.Mesh = None self.NormalizationTransform = None self.NormalizationRadius = 1.0 self.NormalizationEntity = '' self.InletEntities = [] self.ReverseInletEntities = [] self.OutletEntity = '' self.WallEntity = '' self.HistoryEntity = '' self.UseCellDefinedEntities = 1 self.CellEntityIdsArrayName = '' self.NormalizationEntityId = -1 self.InletEntityIds = [] self.OutletEntityId = -1 self.WallEntityId = -1 self.HistoryEntityId = -1 self.ReverseInlets = [] self.TimeStepsOnly = 0 self.StartTime = 0.0 self.EndTime = 1.0 self.NumberOfTimeSteps = 0 self.NumberOfDumps = 0 self.DumpFlag = '11000' self.WriteWNodeSection = 1 self.WriteWElemSection = 1 ## ['NormalizationEntity','normalizationentity','str',1], ## ['InletEntities','inletentities','str',-1], ## ['OutletEntity','outletentity','str',1], ## ['WallEntity','wallentity','str',1], ## ['HistoryEntity','historyentity','str',1], ## ['UseCellDefinedEntities','celldefinedentities','int',1], self.SetScriptName('vmtktetringenerator') self.SetScriptDoc('generate input files for the newtetr CFD solver') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['OutputFileName','ofile','str',1,'','output file name'], ['TimeStepsOnly','timestepsonly','bool',1,'','only generate the $time section of the tetr.in file'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where entity ids relative to cells are stored'], ['NormalizationEntityId','normalizationid','int',1,'','id of the entity relative to which the mesh has to be normalized'], ['NormalizationRadius','normalizationradius','float',1,'(0.0,)','explicit value of the radius relative to which the mesh has to be normalized (to be used when -normalizationid is not used)'], ['InletEntityIds','inletids','int',-1,'','id of inlet entities'], ['OutletEntityId','outletid','int',1,'','id of the outlet entity'], ['WallEntityId','wallid','int',1,'','id of the wall entity'], ['HistoryEntityId','historyid','int',1,'','id of the entity whose history has to be stored'], ['ReverseInlets','reverseinlets','bool',-1,'','toggle reversal of the nth inlet entity normal'], ['StartTime','starttime','float',1,'','simulation normalized start time'], ['EndTime','endtime','float',1,'','simulation normalized end time'], ['NumberOfTimeSteps','timesteps','int',1,'(0,)','number of time steps between start and end time'], ['NumberOfDumps','dumps','int',1,'(0,)','number of solution dumps between start and end time'], ['DumpFlag','dumpflag','str',1,'','flag identifying solution dump (e.g. 11000 = tetr.pres and tetr.vel)'], ['WriteWNodeSection','wnodesection','bool',1,'','append $wnode section to .in file for subsequent wall shear stress computation'], ['WriteWElemSection','welemsection','bool',1,'','append $welem section to .in file for subsequent wall shear stress computation'] ]) self.SetOutputMembers([]) def ComputeBarycenter(self,pointIds): barycenter = [0.0, 0.0, 0.0] numberOfIds = pointIds.GetNumberOfIds() for i in range(numberOfIds): point = self.Mesh.GetPoint(pointIds.GetId(i)) for j in range(3): barycenter[j] += point[j] for j in range(3): barycenter[j] /= numberOfIds return barycenter def ComputeAngle(self,origin,point0,point1): vector0 = [ point0[0] - origin[0], point0[1] - origin[1], point0[2] - origin[2]] vector1 = [ point1[0] - origin[0], point1[1] - origin[1], point1[2] - origin[2]] vtk.vtkMath.Normalize(vector0) vtk.vtkMath.Normalize(vector1) sum = [ vector0[0] + vector1[0], vector0[1] + vector1[1], vector0[2] + vector1[2]] difference = [ vector0[0] - vector1[0], vector0[1] - vector1[1], vector0[2] - vector1[2]] sumNorm = vtk.vtkMath.Norm(sum) differenceNorm = vtk.vtkMath.Norm(difference) angle = 2.0 * math.atan2(differenceNorm,sumNorm) + math.pi return angle def SortBoundaryPoints(self,sectionBoundaryPointIds): barycenter = self.ComputeBarycenter(sectionBoundaryPointIds) numberOfIds = sectionBoundaryPointIds.GetNumberOfIds() for i in range(0,numberOfIds-1): minAngleId = -1 minAngle = 2.0 * math.pi point0 = self.Mesh.GetPoint(sectionBoundaryPointIds.GetId(i)) for j in range(i+1,numberOfIds): point1 = self.Mesh.GetPoint(sectionBoundaryPointIds.GetId(j)) angle = self.ComputeAngle(barycenter,point0,point1) if angle < minAngle: minAngleId = j minAngle = angle tempId = sectionBoundaryPointIds.GetId(i+1) sectionBoundaryPointIds.SetId(i+1,sectionBoundaryPointIds.GetId(minAngleId)) sectionBoundaryPointIds.SetId(minAngleId,tempId) def GetSectionBoundaryPointIds(self,sectionEntity): if (self.WallEntity == ''): self.PrintLog('Cannot compute section properties if WallEntity is undefined.') return None sectionEntityArray = self.Mesh.GetPointData().GetArray(sectionEntity) wallEntityArray = self.Mesh.GetPointData().GetArray(self.WallEntity) sectionBoundaryPointIds = vtk.vtkIdList() for i in range(self.Mesh.GetNumberOfPoints()): if (sectionEntityArray.GetComponent(i,0) != 0) & (wallEntityArray.GetComponent(i,0) != 0): sectionBoundaryPointIds.InsertNextId(i) self.SortBoundaryPoints(sectionBoundaryPointIds) return sectionBoundaryPointIds def GenerateTetrInFile(self): self.PrintLog('Generating Tetr .in file.') f=open(self.OutputFileName, 'w') line = '$title' + '\n' f.write(line) line = self.OutputFileName + '\n' f.write(line) line = '\n' f.write(line) line = '$compress' + '\n' f.write(line) line = 'gzip -f' + '\n' f.write(line) line = '\n' f.write(line) self.NormalizationTransform.Identity() if (self.NormalizationEntity != ''): sectionBoundaryPointIds = self.GetSectionBoundaryPointIds(self.NormalizationEntity) sectionProperties = SectionProperties() sectionProperties.Mesh = self.Mesh sectionProperties.NormalizationTransform = self.NormalizationTransform sectionProperties.SectionBoundaryPointIds = sectionBoundaryPointIds sectionProperties.Execute() self.NormalizationRadius = sectionProperties.Radius if (self.NormalizationRadius != 0.0) & (self.NormalizationRadius != 1.0): self.NormalizationTransform.Scale(1.0/self.NormalizationRadius,1.0/self.NormalizationRadius,1.0/self.NormalizationRadius) line = '$radius' + '\n' f.write(line) line = str(self.NormalizationRadius) + '\n' f.write(line) line = '\n' f.write(line) line = '$viscosity' + '\n' f.write(line) line = str(0.035) + '\n' f.write(line) line = '\n' f.write(line) line = '$density' + '\n' f.write(line) line = str(1.06) + '\n' f.write(line) line = '\n' f.write(line) line = '$red' + '\n' f.write(line) line = str(0) + '\n' f.write(line) line = '\n' f.write(line) line = '$alpha' + '\n' f.write(line) line = str(0) + '\n' f.write(line) line = '\n' f.write(line) line = '$nsolve' + '\n' f.write(line) line = '22' + '\n' f.write(line) line = '\n' f.write(line) line = '$Uzawa_PC' + '\n' f.write(line) line = '1' + '\n' f.write(line) line = '\n' f.write(line) line = '$node' + '\n' f.write(line) line = str(self.Mesh.GetNumberOfPoints()) + '\n' f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = [0.0,0.0,0.0] self.NormalizationTransform.TransformPoint(self.Mesh.GetPoint(i),point) line = str(i+1) + ' ' + str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) + '\n' f.write(line) line = '\n' f.write(line) line = '$elem' + '\n' f.write(line) quadratidTetraCellType = 24 quadraticTetraCellIds = vtk.vtkIdTypeArray() self.Mesh.GetIdsOfCellsOfType(quadratidTetraCellType,quadraticTetraCellIds) line = str(quadraticTetraCellIds.GetNumberOfTuples()) + '\n' f.write(line) for i in range(quadraticTetraCellIds.GetNumberOfTuples()): line = str(i+1) + ' ' cell = self.Mesh.GetCell(quadraticTetraCellIds.GetValue(i)) line += str(cell.GetPointId(0)+1) + ' ' line += str(cell.GetPointId(4)+1) + ' ' line += str(cell.GetPointId(1)+1) + ' ' line += str(cell.GetPointId(5)+1) + ' ' line += str(cell.GetPointId(2)+1) + ' ' line += str(cell.GetPointId(6)+1) + ' ' line += str(cell.GetPointId(7)+1) + ' ' line += str(cell.GetPointId(8)+1) + ' ' line += str(cell.GetPointId(9)+1) + ' ' line += str(cell.GetPointId(3)+1) + ' ' line += '\n' f.write(line) # inletEntities = self.InletEntities # reversedInlets = self.ReverseInlets # inletEntitiesReversed = zip(inletEntities,reversedInlets) # for inletEntityReversed in inletEntitiesReversed: # inletEntity = inletEntityReversed[0] # reversedInlet = inletEntityReversed[1] # if (inletEntity == ''): # continue for inletEntity in self.InletEntities: reversedInlet = inletEntity in self.ReverseInletEntities line = '\n' f.write(line) line = '$binlet' + ' (' + inletEntity + ') ' + '\n' f.write(line) entityArray = self.Mesh.GetPointData().GetArray(inletEntity) numberOfEntityNodes = 0 for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue numberOfEntityNodes += 1 line = str(numberOfEntityNodes) + '\n' f.write(line) for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue line = str(i+1) + '\n' f.write(line) sectionBoundaryPointIds = self.GetSectionBoundaryPointIds(inletEntity) sectionProperties = SectionProperties() sectionProperties.Mesh = self.Mesh sectionProperties.NormalizationTransform = self.NormalizationTransform sectionProperties.SectionBoundaryPointIds = sectionBoundaryPointIds if not reversedInlet: sectionProperties.FlipOutwardNormal = 1 else: sectionProperties.FlipOutwardNormal = 0 sectionProperties.Execute() line = str(sectionProperties.Radius) + '\n' f.write(line) line = str(sectionProperties.Origin[0]) + ' ' + str(sectionProperties.Origin[1]) + ' ' + str(sectionProperties.Origin[2]) + '\n' f.write(line) line = str(sectionProperties.Normal[0]) + ' ' + str(sectionProperties.Normal[1]) + ' ' + str(sectionProperties.Normal[2]) + '\n' f.write(line) #TODO: for every inlet insert fourier coefficients given points of waveform (spline-interpolate points beforehands to get them equispaced). if (self.OutletEntity != ''): line = '\n' f.write(line) line = '$boutlet' + ' (' + self.OutletEntity + ') ' + '\n' f.write(line) entityArray = self.Mesh.GetPointData().GetArray(self.OutletEntity) numberOfEntityNodes = 0 for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue numberOfEntityNodes += 1 line = str(numberOfEntityNodes) + '\n' f.write(line) for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue line = str(i+1) + '\n' f.write(line) sectionBoundaryPointIds = self.GetSectionBoundaryPointIds(self.OutletEntity) sectionProperties = SectionProperties() sectionProperties.Mesh = self.Mesh sectionProperties.NormalizationTransform = self.NormalizationTransform sectionProperties.SectionBoundaryPointIds = sectionBoundaryPointIds sectionProperties.FlipOutwardNormal = 0 sectionProperties.Execute() line = str(sectionProperties.Radius) + '\n' f.write(line) line = str(sectionProperties.Origin[0]) + ' ' + str(sectionProperties.Origin[1]) + ' ' + str(sectionProperties.Origin[2]) + '\n' f.write(line) line = str(sectionProperties.Normal[0]) + ' ' + str(sectionProperties.Normal[1]) + ' ' + str(sectionProperties.Normal[2]) + '\n' f.write(line) if (self.WallEntity != ''): line = '\n' f.write(line) line = '$bwall' + '\n' f.write(line) entityArray = self.Mesh.GetPointData().GetArray(self.WallEntity) numberOfEntityNodes = 0 for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue numberOfEntityNodes += 1 line = str(numberOfEntityNodes) + '\n' f.write(line) for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue line = str(i+1) + '\n' f.write(line) wallPointIdsMap = vtk.vtkIdList() if (self.WriteWNodeSection == 1): line = '\n' f.write(line) line = '$wnode' + '\n' f.write(line) line = str(numberOfEntityNodes) + '\n' f.write(line) count = 0 wallPointIdsMap.SetNumberOfIds(entityArray.GetNumberOfTuples()) extractSurface = vtk.vtkGeometryFilter() extractSurface.SetInput(self.Mesh) extractSurface.Update() normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(extractSurface.GetOutput()) normalsFilter.AutoOrientNormalsOn() normalsFilter.ConsistencyOn() normalsFilter.Update() normalsSurface = normalsFilter.GetOutput() locator = vtk.vtkMergePoints() locator.SetDataSet(normalsSurface) locator.BuildLocator() for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): wallPointIdsMap.SetId(i,-1) continue wallPointIdsMap.SetId(i,count) point = self.Mesh.GetPoint(i) surfacePointId = locator.FindClosestPoint(point) normal = normalsSurface.GetPointData().GetNormals().GetTuple3(surfacePointId) line = str(count+1) + ' ' + str(i+1) + ' ' + str(normal[0]) + ' ' + str(normal[1]) + ' ' + str(normal[2]) + '\n' f.write(line) count += 1 if (self.WriteWElemSection == 1): line = '\n' f.write(line) line = '$welem' + '\n' f.write(line) dataArray = vtk.vtkIntArray() dataArray.SetNumberOfComponents(8) for i in range(self.Mesh.GetNumberOfCells()): qtetra = self.Mesh.GetCell(i) for j in range(qtetra.GetNumberOfFaces()): face = qtetra.GetFace(j) isBoundaryFace = 1 for k in range(face.GetNumberOfPoints()): if (entityArray.GetComponent(face.GetPointId(k),0) != 1.0): isBoundaryFace = 0 break if (isBoundaryFace == 0): continue dataArray.InsertNextValue(i) dataArray.InsertNextValue(j) for k in range(face.GetNumberOfPoints()): dataArray.InsertNextValue(face.GetPointId(k)) line = str(dataArray.GetNumberOfTuples()) + '\n' f.write(line) for i in range(dataArray.GetNumberOfTuples()): line = str(i+1) + ' ' line += str(int(dataArray.GetComponent(i,0))+1) + ' ' faceId = int(dataArray.GetComponent(i,1)) newTetrFaceIdsMap = [2, 4, 3, 1] line += str(newTetrFaceIdsMap[faceId]) + ' ' for j in range(2,dataArray.GetNumberOfComponents()): line += str(wallPointIdsMap.GetId(int(dataArray.GetComponent(i,j)))+1) + ' ' line += '\n' f.write(line) if (self.HistoryEntity != ''): line = '\n' f.write(line) line = '$history' + '\n' f.write(line) entityArray = self.Mesh.GetPointData().GetArray(self.HistoryEntity) numberOfEntityNodes = 0 for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue numberOfEntityNodes += 1 line = str(numberOfEntityNodes) + '\n' f.write(line) for i in range(entityArray.GetNumberOfTuples()): if (entityArray.GetComponent(i,0) != 1.0): continue line = str(i+1) + '\n' f.write(line) self.WriteTimeSteps(f) def GenerateTimeStepsFile(self): self.PrintLog('Generating $time section.') f=open(self.OutputFileName, 'w') self.WriteTimeSteps(f) def WriteTimeSteps(self,f): if (self.NumberOfTimeSteps > 0): line = '\n' f.write(line) line = '$time' + '\n' f.write(line) line = str(self.NumberOfTimeSteps) + '\n' f.write(line) line = str(self.StartTime) + '\n' f.write(line) timeStep = (self.EndTime - self.StartTime) / float(self.NumberOfTimeSteps) for i in range(1,self.NumberOfTimeSteps+1): time = self.StartTime + float(i) * timeStep dumpFlag = '0000' if (i % (self.NumberOfTimeSteps / self.NumberOfDumps) == 0): dumpFlag = self.DumpFlag nsub = 0 line = str(time) + ' ' + dumpFlag + ' ' + str(nsub) + '\n' f.write(line) def BuildPointEntityArray(self,entityId,pointEntityArray): cellEntityArray = self.Mesh.GetCellData().GetArray(self.CellEntityIdsArrayName) pointEntityArray.SetNumberOfTuples(self.Mesh.GetNumberOfPoints()) pointEntityArray.FillComponent(0,0.0) for i in range(self.Mesh.GetNumberOfCells()): cellEntityId = int(cellEntityArray.GetComponent(i,0)) if cellEntityId != entityId: continue cell = self.Mesh.GetCell(i) for j in range(cell.GetNumberOfPoints()): pointEntityArray.SetComponent(cell.GetPointId(j),0,1) def Execute(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') if self.TimeStepsOnly: self.GenerateTimeStepsFile() return if self.Mesh == None: self.PrintError('Error: no Mesh.') self.NormalizationTransform = vtk.vtkTransform() if self.UseCellDefinedEntities == 1: entityIds = [] entityNames = [] if self.NormalizationEntityId != -1: entityIds.append(self.NormalizationEntityId) entityNames.append('NormalizationEntity') self.NormalizationEntity = 'NormalizationEntity' for inletEntityId in self.InletEntityIds: entityIds.append(inletEntityId) entityNames.append('InletEntity'+str(inletEntityId)) self.InletEntities.append('InletEntity'+str(inletEntityId)) for reverseInletEntityId in self.ReverseInlets: self.ReverseInletEntities.append('InletEntity'+str(reverseInletEntityId)) if self.OutletEntityId != -1: entityIds.append(self.OutletEntityId) entityNames.append('OutletEntity') self.OutletEntity = 'OutletEntity' if self.WallEntityId != -1: entityIds.append(self.WallEntityId) entityNames.append('WallEntity') self.WallEntity = 'WallEntity' if self.HistoryEntityId != -1: entityIds.append(self.HistoryEntityId) entityNames.append('HistoryEntity') self.HistoryEntity = 'HistoryEntity' for i in range(len(entityIds)): entityId = entityIds[i] entityName = entityNames[i] pointEntityArray = vtk.vtkIntArray() pointEntityArray.SetName(entityName) self.BuildPointEntityArray(entityId,pointEntityArray) self.Mesh.GetPointData().AddArray(pointEntityArray) self.GenerateTetrInFile() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinesections.py0000664000175000017500000001134011757446472020653 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinesections.py,v $ ## Language: Python ## Date: $Date: 2006/10/17 15:16:16 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkcenterlinesections = 'vmtkCenterlineSections' class vmtkCenterlineSections(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.CenterlineSections = None self.CenterlineSectionAreaArrayName = 'CenterlineSectionArea' self.CenterlineSectionMinSizeArrayName = 'CenterlineSectionMinSize' self.CenterlineSectionMaxSizeArrayName = 'CenterlineSectionMaxSize' self.CenterlineSectionShapeArrayName = 'CenterlineSectionShape' self.CenterlineSectionClosedArrayName = 'CenterlineSectionClosed' self.SetScriptName('vmtkcenterlinesections') self.SetScriptDoc('compute geometric properties of sections located along centerlines. The script takes in input the surface and the relative centerlines.') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['CenterlineSectionAreaArrayName','branchsectionarea','str',1,'','name of the array where the area of bifurcation sections have to be stored'], ['CenterlineSectionMinSizeArrayName','branchsectionminsize','str',1,'','name of the array where the minimum diameter of each section has to be stored'], ['CenterlineSectionMaxSizeArrayName','branchsectionmaxsize','str',1,'','name of the array where the maximum diameter of each bifurcation sections has to be stored'], ['CenterlineSectionShapeArrayName','centerlinesectionshape','str',1,'','name of the array where the shape index, i.e. the ratio between minimum and maximum diameter, of each bifurcation section has to be stored'], ['CenterlineSectionClosedArrayName','branchsectionclosed','str',1,'','name of the array containing 1 if a section is closed and 0 otherwise'] ]) self.SetOutputMembers([ ['CenterlineSections','o','vtkPolyData',1,'','the output sections','vmtksurfacewriter'], ['Centerlines','ocenterlines','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'], ['CenterlineSectionAreaArrayName','branchsectionarea','str',1,'','name of the array where the area of bifurcation sections are stored'], ['CenterlineSectionMinSizeArrayName','branchsectionminsize','str',1,'','name of the array where the minimum diameter of each section are stored'], ['CenterlineSectionMaxSizeArrayName','branchsectionmaxsize','str',1,'','name of the array where the minimum diameter of each bifurcation sections has to be stored'], ['CenterlineSectionShapeArrayName','centerlinesectionshape','str',1,'','name of the array where the shape index, i.e. the ratio between minimum and maximum diameter, of each bifurcation section are stored'], ['CenterlineSectionClosedArrayName','branchsectionclosed','str',1,'','name of the array containing 1 if a section is closed and 0 otherwise'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') centerlineSections = vtkvmtk.vtkvmtkPolyDataCenterlineSections() centerlineSections.SetInput(self.Surface) centerlineSections.SetCenterlines(self.Centerlines) centerlineSections.SetCenterlineSectionAreaArrayName(self.CenterlineSectionAreaArrayName) centerlineSections.SetCenterlineSectionMinSizeArrayName(self.CenterlineSectionMinSizeArrayName) centerlineSections.SetCenterlineSectionMaxSizeArrayName(self.CenterlineSectionMaxSizeArrayName) centerlineSections.SetCenterlineSectionShapeArrayName(self.CenterlineSectionShapeArrayName) centerlineSections.SetCenterlineSectionClosedArrayName(self.CenterlineSectionClosedArrayName) centerlineSections.Update() self.CenterlineSections = centerlineSections.GetOutput() self.Centerlines = centerlineSections.GetCenterlines() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagereader.py0000664000175000017500000003662511757446472017235 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagereader.py,v $ ## Language: Python ## Date: $Date: 2006/05/22 08:33:12 $ ## Version: $Revision: 1.16 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkimagereader = 'vmtkImageReader' class vmtkImageReader(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.UseITKIO = 1 self.InputFileName = '' self.InputFilePrefix = '' self.InputFilePattern = '' self.InputDirectoryName = '' self.Image = 0 self.Output = 0 self.DataExtent = [-1, -1, -1, -1, -1, -1] self.DataSpacing = [1.0, 1.0, 1.0] self.DataOrigin = [0.0, 0.0, 0.0] self.DataByteOrder = 'littleendian' self.DataScalarType = 'float' self.DesiredOrientation = 'native' self.HeaderSize = 0 self.FileDimensionality = 3 self.Flip = [0, 0, 0] self.AutoOrientDICOMImage = 1 self.RasToIjkMatrixCoefficients = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] self.XyzToRasMatrixCoefficients = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] self.SetScriptName('vmtkimagereader') self.SetScriptDoc('read an image and stores it in a vtkImageData object') self.SetInputMembers([ ['Format','f','str',1,'["vtkxml","vtk","dicom","raw","meta","tiff","png"]','file format'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['UseITKIO','useitk','bool',1,'','use ITKIO mechanism'], ['Image','i','vtkImageData',1,'','the input image'], ['InputFileName','ifile','str',1,'','input file name'], ['InputFilePrefix','prefix','str',1,'','input file prefix (e.g. foo_)'], ['InputFilePattern','pattern','str',1,'','input file pattern (e.g. %s%04d.png)'], ['InputDirectoryName','d','str',1,'','input directory name - dicom only'], ['DataExtent','extent','int',6,'','3D extent of the image - raw and png'], ['HeaderSize','headersize','int',1,'(0,)','size of the image header - raw only'], ['DataSpacing','spacing','float',3,'','spacing of the image - raw, tiff, png, itk'], ['DataOrigin','origin','float',3,'','origin of the image - raw, tiff, png, itk'], ['DesiredOrientation','orientation','str',1,'["native","axial","coronal","sagittal"]','desired data orientation - itk only'], ['DataByteOrder','byteorder','str',1,'["littleendian","bigendian"]','byte ordering - raw only'], ['DataScalarType','scalartype','str',1,'["float","double","int","short","ushort","uchar"]','scalar type - raw only'], ['FileDimensionality','filedimensionality','int',1,'(2,3)','dimensionality of the file to read - raw only'], ['Flip','flip','bool',3,'','toggle flipping of the corresponding axis'], ['AutoOrientDICOMImage','autoorientdicom','bool',1,'','flip a dicom stack in order to have a left-to-right, posterio-to-anterior, inferior-to-superior image; this is based on the \"image orientation (patient)\" field in the dicom header'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'], ['RasToIjkMatrixCoefficients','rastoijkmatrix','float',16], ['XyzToRasMatrixCoefficients','xyztorasmatrix','float',16] ]) def ReadVTKXMLImageFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading VTK XML image file.') reader = vtk.vtkXMLImageDataReader() reader.SetFileName(self.InputFileName) reader.Update() self.Image = reader.GetOutput() def ReadVTKImageFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading VTK image file.') reader = vtk.vtkStructuredPointsReader() reader.SetFileName(self.InputFileName) reader.Update() self.Image = reader.GetOutput() def ReadRawImageFile(self): if (self.InputFileName == '') & (self.InputFilePrefix == ''): self.PrintError('Error: no InputFileName or InputFilePrefix.') self.PrintLog('Reading RAW image file.') reader = vtk.vtkImageReader() if self.InputFileName != '': reader.SetFileName(self.InputFileName) else: reader.SetFilePrefix(self.InputFilePrefix) if self.InputFilePattern != '': reader.SetFilePattern(self.InputFilePattern) else: reader.SetFilePattern("%s%04d.png") reader.SetFileDimensionality(self.FileDimensionality) if self.DataByteOrder == 'littleendian': reader.SetDataByteOrderToLittleEndian() elif self.DataByteOrder == 'bigendian': reader.SetDataByteOrderToBigEndian() reader.SetDataExtent(self.DataExtent) reader.SetDataSpacing(self.DataSpacing) reader.SetDataOrigin(self.DataOrigin) reader.SetHeaderSize(self.HeaderSize) if self.DataScalarType == 'float': reader.SetDataScalarTypeToFloat() elif self.DataScalarType == 'double': reader.SetDataScalarTypeToDouble() elif self.DataScalarType == 'int': reader.SetDataScalarTypeToInt() elif self.DataScalarType == 'short': reader.SetDataScalarTypeToShort() elif self.DataScalarType == 'ushort': reader.SetDataScalarTypeToUnsignedShort() elif self.DataScalarType == 'uchar': reader.SetDataScalarTypeToUnsignedChar() reader.Update() self.Image = reader.GetOutput() def ReadMetaImageFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading meta image file.') reader = vtk.vtkMetaImageReader() reader.SetFileName(self.InputFileName) reader.Update() self.Image = reader.GetOutput() def ReadTIFFImageFile(self): if (self.InputFileName == '') & (self.InputFilePrefix == ''): self.PrintError('Error: no InputFileName or InputFilePrefix.') self.PrintLog('Reading TIFF image file.') reader = vtk.vtkTIFFReader() if self.InputFileName != '': reader.SetFileName(self.InputFileName) else: reader.SetFilePrefix(self.InputFilePrefix) if self.InputFilePattern != '': reader.SetFilePattern(self.InputFilePattern) else: reader.SetFilePattern("%s%04d.png") reader.SetDataExtent(self.DataExtent) reader.SetDataSpacing(self.DataSpacing) reader.SetDataOrigin(self.DataOrigin) reader.Update() self.Image = reader.GetOutput() def ReadPNGImageFile(self): if (self.InputFileName == '') & (self.InputFilePrefix == ''): self.PrintError('Error: no InputFileName or InputFilePrefix.') self.PrintLog('Reading PNG image file.') reader = vtk.vtkPNGReader() if self.InputFileName != '': reader.SetFileName(self.InputFileName) else: reader.SetFilePrefix(self.InputFilePrefix) if self.InputFilePattern != '': reader.SetFilePattern(self.InputFilePattern) else: reader.SetFilePattern("%s%04d.png") reader.SetDataExtent(self.DataExtent) reader.SetDataSpacing(self.DataSpacing) reader.SetDataOrigin(self.DataOrigin) reader.Update() self.Image = reader.GetOutput() def ReadDICOMFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading DICOM file.') reader = vtkvmtk.vtkvmtkDICOMImageReader() reader.SetFileName(self.InputFileName) reader.SetAutoOrientImage(self.AutoOrientDICOMImage) reader.Update() self.Image = reader.GetOutput() def ReadDICOMDirectory(self): if (self.InputDirectoryName == ''): self.PrintError('Error: no InputDirectoryName.') self.PrintLog('Reading DICOM directory.') reader = vtkvmtk.vtkvmtkDICOMImageReader() reader.SetDirectoryName(self.InputDirectoryName) reader.SetAutoOrientImage(self.AutoOrientDICOMImage) reader.Update() self.Image = reader.GetOutput() def ReadITKIO(self): if self.InputFileName == '': self.PrintError('Error: no InputFileName.') reader = vtkvmtk.vtkvmtkITKArchetypeImageSeriesScalarReader() reader.SetArchetype(self.InputFileName) reader.SetDefaultDataSpacing(self.DataSpacing) reader.SetDefaultDataOrigin(self.DataOrigin) reader.SetOutputScalarTypeToNative() if self.DesiredOrientation == 'native': reader.SetDesiredCoordinateOrientationToNative() elif self.DesiredOrientation == 'axial': reader.SetDesiredCoordinateOrientationToAxial() elif self.DesiredOrientation == 'coronal': reader.SetDesiredCoordinateOrientationToCoronal() elif self.DesiredOrientation == 'sagittal': reader.SetDesiredCoordinateOrientationToSagittal() reader.SetSingleFile(0) reader.Update() self.Image = vtk.vtkImageData() self.Image.DeepCopy(reader.GetOutput()) matrix = reader.GetRasToIjkMatrix() self.RasToIjkMatrixCoefficients = [ matrix.GetElement(0,0), matrix.GetElement(0,1), matrix.GetElement(0,2), matrix.GetElement(0,3), matrix.GetElement(1,0), matrix.GetElement(1,1), matrix.GetElement(1,2), matrix.GetElement(1,3), matrix.GetElement(2,0), matrix.GetElement(2,1), matrix.GetElement(2,2), matrix.GetElement(2,3), matrix.GetElement(3,0), matrix.GetElement(3,1), matrix.GetElement(3,2), matrix.GetElement(3,3)] matrix.Invert() origin = [matrix.GetElement(0,3), matrix.GetElement(1,3), matrix.GetElement(2,3)] translationToOrigin = [-origin[0], -origin[1], -origin[2]] for i in range(3): direction = [matrix.GetElement(0,i), matrix.GetElement(1,i), matrix.GetElement(2,i)] vtk.vtkMath.Normalize(direction) matrix.SetElement(0,i,direction[0]) matrix.SetElement(1,i,direction[1]) matrix.SetElement(2,i,direction[2]) matrix.SetElement(0,3,0.0) matrix.SetElement(1,3,0.0) matrix.SetElement(2,3,0.0) transform = vtk.vtkTransform() transform.PostMultiply() transform.Translate(translationToOrigin) transform.Concatenate(matrix) transform.Translate(origin) matrix = transform.GetMatrix() self.XyzToRasMatrixCoefficients = [ matrix.GetElement(0,0), matrix.GetElement(0,1), matrix.GetElement(0,2), matrix.GetElement(0,3), matrix.GetElement(1,0), matrix.GetElement(1,1), matrix.GetElement(1,2), matrix.GetElement(1,3), matrix.GetElement(2,0), matrix.GetElement(2,1), matrix.GetElement(2,2), matrix.GetElement(2,3), matrix.GetElement(3,0), matrix.GetElement(3,1), matrix.GetElement(3,2), matrix.GetElement(3,3)] def Execute(self): extensionFormats = {'vti':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'dcm':'dicom', 'raw':'raw', 'mhd':'meta', 'mha':'meta', 'tif':'tiff', 'png':'png'} if self.InputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.InputFileName = tkFileDialog.askopenfilename(title="Input image",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.InputFileName) if not self.InputFileName: self.PrintError('Error: no InputFileName.') if self.InputDirectoryName == 'BROWSER': import tkFileDialog initialDir = pypes.pypeScript.lastVisitedPath self.InputDirectoryName = tkFileDialog.askdirectory(title="Input directory",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = self.InputDirectoryName if not self.InputDirectoryName: self.PrintError('Error: no InputDirectoryName.') if self.GuessFormat and self.InputFileName and not self.Format: import os.path extension = os.path.splitext(self.InputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if self.UseITKIO and self.InputFileName and self.Format not in ['vtkxml','vtk','raw'] and not self.InputDirectoryName: self.ReadITKIO() else: if self.Format == 'vtkxml': self.ReadVTKXMLImageFile() elif self.Format == 'vtk': self.ReadVTKImageFile() elif self.Format == 'dicom': if self.InputDirectoryName != '': self.ReadDICOMDirectory() else: self.ReadDICOMFile() elif self.Format == 'raw': self.ReadRawImageFile() elif self.Format == 'meta': self.ReadMetaImageFile() elif self.Format == 'png': self.ReadPNGImageFile() elif self.Format == 'tiff': self.ReadTIFFImageFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if (self.Flip[0] == 1) | (self.Flip[1] == 1) | (self.Flip[2] == 1): temp0 = self.Image if self.Flip[0] == 1: flipFilter = vtk.vtkImageFlip() flipFilter.SetInput(self.Image) flipFilter.SetFilteredAxis(0) flipFilter.Update() temp0 = flipFilter.GetOutput() temp1 = temp0 if self.Flip[1] == 1: flipFilter = vtk.vtkImageFlip() flipFilter.SetInput(temp0) flipFilter.SetFilteredAxis(1) flipFilter.Update() temp1 = flipFilter.GetOutput() temp2 = temp1 if self.Flip[2] == 1: flipFilter = vtk.vtkImageFlip() flipFilter.SetInput(temp1) flipFilter.SetFilteredAxis(2) flipFilter.Update() temp2 = flipFilter.GetOutput() self.Image = temp2 self.PrintLog('Spacing %f %f %f' % self.Image.GetSpacing()) self.PrintLog('Origin %f %f %f' % self.Image.GetOrigin()) self.PrintLog('Dimensions %d %d %d' % self.Image.GetDimensions()) if self.Image.GetSource(): self.Image.GetSource().UnRegisterAllOutputs() self.Output = self.Image if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbranchmetrics.py0000664000175000017500000001214511757446472017603 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchmetrics.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbranchmetrics = 'vmtkBranchMetrics' class vmtkBranchMetrics(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.ComputeAbscissaMetric = 1 self.ComputeAngularMetric = 1 self.AbscissasArrayName = '' self.NormalsArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.RadiusArrayName = '' self.BlankingArrayName = '' self.AngularMetricArrayName = 'AngularMetric' self.AbscissaMetricArrayName = 'AbscissaMetric' self.SetScriptName('vmtkbranchmetrics') self.SetScriptDoc('') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['ComputeAbscissaMetric','abscissametric','bool',1], ['ComputeAngularMetric','angularmetric','bool',1], ['AbscissasArrayName','abscissasarray','str',1], ['NormalsArrayName','normalsarray','str',1], ['GroupIdsArrayName','groupidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['RadiusArrayName','radiusarray','str',1], ['BlankingArrayName','blankingarray','str',1], ['AngularMetricArrayName','angularmetricarray','str',1], ['AbscissaMetricArrayName','abscissametricarray','str',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['AngularMetricArrayName','angularmetricarray','str',1], ['AbscissaMetricArrayName','abscissametricarray','str',1] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') if self.ComputeAngularMetric == 1: self.PrintLog('Computing angular metric') angularMetricFilter = vtkvmtk.vtkvmtkPolyDataCenterlineAngularMetricFilter() angularMetricFilter.SetInput(self.Surface) angularMetricFilter.SetMetricArrayName(self.AngularMetricArrayName) angularMetricFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) angularMetricFilter.SetCenterlines(self.Centerlines) angularMetricFilter.SetRadiusArrayName(self.RadiusArrayName) angularMetricFilter.SetCenterlineNormalsArrayName(self.NormalsArrayName) angularMetricFilter.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) angularMetricFilter.SetCenterlineTractIdsArrayName(self.TractIdsArrayName) angularMetricFilter.UseRadiusInformationOff() angularMetricFilter.IncludeBifurcationsOff() angularMetricFilter.SetBlankingArrayName(self.BlankingArrayName) angularMetricFilter.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) angularMetricFilter.Update() self.Surface = angularMetricFilter.GetOutput() if self.ComputeAbscissaMetric == 1: self.PrintLog('Computing abscissa metric') abscissaMetricFilter = vtkvmtk.vtkvmtkPolyDataCenterlineAbscissaMetricFilter() abscissaMetricFilter.SetInput(self.Surface) abscissaMetricFilter.SetMetricArrayName(self.AbscissaMetricArrayName) abscissaMetricFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) abscissaMetricFilter.SetCenterlines(self.Centerlines) abscissaMetricFilter.SetRadiusArrayName(self.RadiusArrayName) abscissaMetricFilter.SetAbscissasArrayName(self.AbscissasArrayName) abscissaMetricFilter.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) abscissaMetricFilter.SetCenterlineTractIdsArrayName(self.TractIdsArrayName) abscissaMetricFilter.UseRadiusInformationOff() abscissaMetricFilter.IncludeBifurcationsOn() abscissaMetricFilter.SetBlankingArrayName(self.BlankingArrayName) abscissaMetricFilter.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) abscissaMetricFilter.Update() self.Surface = abscissaMetricFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfaceclipper.py0000664000175000017500000001254011757446472017765 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceclipper.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vmtkrenderer import pypes vmtksurfaceclipper = 'vmtkSurfaceClipper' class vmtkSurfaceClipper(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.vmtkRenderer = None self.OwnRenderer = 0 self.WidgetType = 'box' self.Actor = None self.ClipWidget = None self.ClipFunction = None self.CleanOutput = 1 self.Transform = None self.SetScriptName('vmtksurfaceclipper') self.SetScriptDoc('interactively clip a surface with a box') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['WidgetType','type','str',1,'["box","sphere"]','type of widget used for clipping'], ['Transform','transform','vtkTransform',1,'','the widget transform, useful in case of piping of multiple clipping scripts'], ['CleanOutput','cleanoutput','bool',1,'','toggle cleaning the unused points'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['Transform','otransform','vtkTransform',1,'','the output widget transform'] ]) def ClipCallback(self, obj): if self.ClipWidget.GetEnabled() != 1: return if self.WidgetType == "box": self.ClipWidget.GetPlanes(self.ClipFunction) elif self.WidgetType == "sphere": self.ClipWidget.GetSphere(self.ClipFunction) self.Clipper.Update() self.Surface.DeepCopy(self.Clipper.GetClippedOutput()) self.Surface.Update() self.ClipWidget.Off() def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def Display(self): self.ClipWidget.SetInput(self.Surface) self.ClipWidget.PlaceWidget() if self.Transform: self.ClipWidget.SetTransform(self.Transform) self.ClipWidget.On() #self.vmtkRenderer.RenderWindowInteractor.Initialize() self.vmtkRenderer.Render() #self.vmtkRenderer.RenderWindowInteractor.Start() def Execute(self): if self.Surface == None: self.PrintError('Error: no Surface.') if self.WidgetType == "box": self.ClipFunction = vtk.vtkPlanes() elif self.WidgetType == "sphere": self.ClipFunction = vtk.vtkSphere() self.Clipper = vtk.vtkClipPolyData() self.Clipper.SetInput(self.Surface) self.Clipper.SetClipFunction(self.ClipFunction) self.Clipper.GenerateClippedOutputOn() self.Clipper.InsideOutOn() if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) mapper = vtk.vtkPolyDataMapper() mapper.SetInput(self.Surface) mapper.ScalarVisibilityOff() self.Actor = vtk.vtkActor() self.Actor.SetMapper(mapper) self.vmtkRenderer.Renderer.AddActor(self.Actor) if self.WidgetType == "box": self.ClipWidget = vtk.vtkBoxWidget() self.ClipWidget.GetFaceProperty().SetColor(0.6,0.6,0.2) self.ClipWidget.GetFaceProperty().SetOpacity(0.25) elif self.WidgetType == "sphere": self.ClipWidget = vtk.vtkSphereWidget() self.ClipWidget.GetSphereProperty().SetColor(0.6,0.6,0.2) self.ClipWidget.GetSphereProperty().SetOpacity(0.25) self.ClipWidget.GetSelectedSphereProperty().SetColor(0.6,0.0,0.0) self.ClipWidget.GetSelectedSphereProperty().SetOpacity(0.75) self.ClipWidget.SetRepresentationToSurface() self.ClipWidget.SetPhiResolution(20) self.ClipWidget.SetThetaResolution(20) self.ClipWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.vmtkRenderer.AddKeyBinding('space','Clip.',self.ClipCallback) self.vmtkRenderer.AddKeyBinding('i','Interact.',self.InteractCallback) self.Display() self.Transform = vtk.vtkTransform() self.ClipWidget.GetTransform(self.Transform) if self.OwnRenderer: self.vmtkRenderer.Deallocate() if self.CleanOutput == 1: cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(self.Surface) cleaner.Update() self.Surface = cleaner.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkscripts.py0000664000175000017500000000565611757446472016457 0ustar lucaluca__all__ = [ 'vmtkactivetubes', 'vmtkbifurcationprofiles', 'vmtkbifurcationreferencesystems', 'vmtkbifurcationsections', 'vmtkbifurcationvectors', 'vmtkboundarylayer', 'vmtkboundaryreferencesystems', 'vmtkbranchclipper', 'vmtkbranchextractor', 'vmtkbranchgeometry', 'vmtkbranchmapping', 'vmtkbranchmetrics', 'vmtkbranchpatching', 'vmtkbranchsections', 'vmtkcenterlineattributes', 'vmtkcenterlinegeometry', 'vmtkcenterlinelabeler', 'vmtkcenterlinemerge', 'vmtkcenterlinemodeller', 'vmtkcenterlineoffsetattributes', 'vmtkcenterlineresampling', 'vmtkcenterlines', 'vmtkcenterlinesections', 'vmtkcenterlinesmoothing', 'vmtkcenterlineviewer', 'vmtkdelaunayvoronoi', 'vmtkdistancetocenterlines', 'vmtkendpointextractor', 'vmtkflowextensions', 'vmtkicpregistration', 'vmtkimagecast', 'vmtkimagecompose', 'vmtkimagecurvedmpr', 'vmtkimagefeaturecorrection', 'vmtkimagefeatures', 'vmtkimageinitialization', 'vmtkimagelinetracer', 'vmtkimagemipviewer', 'vmtkimageobjectenhancement', 'vmtkimagereader', 'vmtkimagereslice', 'vmtkimageseeder', 'vmtkimageshiftscale', 'vmtkimagesmoothing', 'vmtkimageviewer', 'vmtkimagevesselenhancement', 'vmtkimagevoipainter', 'vmtkimagevoiselector', 'vmtkimagewriter', 'vmtklevelsetsegmentation', 'vmtklineartoquadratic', 'vmtklineresampling', 'vmtklocalgeometry', 'vmtkmarchingcubes', 'vmtkmeshboundaryinspector', 'vmtkmeshbranchclipper', 'vmtkmeshclipper', 'vmtkmeshdatareader', 'vmtkmeshlambda2', 'vmtkmeshlinearize', 'vmtkmeshgenerator', 'vmtkmeshprojection', 'vmtkmeshreader', 'vmtkmeshscaling', 'vmtkmeshtetrahedralize', 'vmtkmeshtosurface', 'vmtkmeshtransform', 'vmtkmeshtransformtoras', 'vmtkmeshvectorfromcomponents', 'vmtkmeshviewer', 'vmtkmeshvorticityhelicity', 'vmtkmeshwallshearrate', 'vmtkmeshwriter', 'vmtknetworkeditor', 'vmtknetworkextraction', 'vmtknetworkwriter', 'vmtkpointsplitextractor', 'vmtkpointtransform', 'vmtkpolyballmodeller', 'vmtkpotentialfit', 'vmtkpythonscript', 'vmtkrenderer', 'vmtkrendertoimage', 'vmtkrbfinterpolation', 'vmtksurfaceappend', 'vmtksurfacecapper', 'vmtksurfacecelldatatopointdata', 'vmtksurfacecenterlineprojection', 'vmtksurfaceclipper', 'vmtksurfaceconnectivity', 'vmtksurfacedecimation', 'vmtksurfacedistance', 'vmtksurfacekiteremoval', 'vmtksurfacemodeller', 'vmtksurfacenormals', 'vmtksurfacepointdatatocelldata', 'vmtksurfaceprojection', 'vmtksurfacereader', 'vmtksurfacereferencesystemtransform', 'vmtksurfaceremeshing', 'vmtksurfacescaling', 'vmtksurfacesmoothing', 'vmtksurfacesubdivision', 'vmtksurfacetransform', 'vmtksurfacetransforminteractive', 'vmtksurfacetransformtoras', 'vmtksurfacetriangle', 'vmtksurfacetomesh', 'vmtksurfaceviewer', 'vmtksurfacewriter', 'vmtksurfmesh', 'vmtktetgen', 'vmtktetringenerator' ] for item in __all__: exec('from '+item+' import *') vmtk-1.0.1/vmtkScripts/vmtkrbfinterpolation.py0000664000175000017500000000645511757446472020347 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagereslice.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtkvmtk import vtk import sys import pypes vmtkrbfinterpolation = 'vmtkRBFInterpolation' class vmtkRBFInterpolation(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Seeds = None self.RBFType = 'biharmonic' self.Image = None self.Dimensions = [0, 0, 0] self.Bounds = [0.0, 1.0, 0.0, 1.0, 0.0, 1.0] self.SetScriptName('vmtkrbfinterpolation') self.SetScriptDoc('perform RBF interpolation from a set of seeds') self.SetInputMembers([ ['Seeds','i','vtkPolyData',1,'','the input seeds','vmtksurfacereader'], ['Image','r','vtkImageData',1,'','the reference image','vmtkimagereader'], ['Dimensions','dimensions','int',3,''], ['Bounds','bounds','float',6,''], ['RBFType','rbftype','str',1,'["thinplatespline","biharmonic","triharmonic"]','the type of RBF interpolation'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Seeds == None: self.PrintError('Error: No input seeds.') rbf = vtkvmtk.vtkvmtkRBFInterpolation() rbf.SetSource(self.Seeds) if self.RBFType == "thinplatespline": rbf.SetRBFTypeToThinPlateSpline() elif self.RBFType == "biharmonic": rbf.SetRBFTypeToBiharmonic() elif self.RBFType == "triharmonic": rbf.SetRBFTypeToTriharmonic() rbf.ComputeCoefficients() if self.Image: origin = self.Image.GetOrigin() spacing = self.Image.GetSpacing() extent = self.Image.GetExtent() dimensions = self.Image.GetDimensions() modelBounds = [0.0,0.0,0.0,0.0,0.0,0.0] modelBounds[0] = origin[0] + spacing[0]*extent[0] modelBounds[1] = origin[0] + spacing[0]*extent[1] modelBounds[2] = origin[1] + spacing[1]*extent[2] modelBounds[3] = origin[1] + spacing[1]*extent[3] modelBounds[4] = origin[2] + spacing[2]*extent[4] modelBounds[5] = origin[2] + spacing[2]*extent[5] else: dimensions = self.Dimensions modelBounds = self.Bounds sampleFunction = vtk.vtkSampleFunction() sampleFunction.SetImplicitFunction(rbf) sampleFunction.SetOutputScalarTypeToDouble() sampleFunction.SetSampleDimensions(dimensions) sampleFunction.SetModelBounds(modelBounds) sampleFunction.CappingOff() sampleFunction.ComputeNormalsOff() sampleFunction.Update() self.Image = sampleFunction.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshboundaryinspector.py0000664000175000017500000001401211757446472021401 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshboundaryinspector.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.3 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkmeshboundaryinspector = 'vmtkMeshBoundaryInspector' class vmtkMeshBoundaryInspector(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.CellEntityIdsArrayName = '' self.VolumeCellEntityId = 0 self.WallCellEntityId = 1 self.vmtkRenderer = None self.OwnRenderer = 0 self.ReferenceSystems = None self.SetScriptName('vmtkmeshboundaryinspector') self.SetScriptDoc('') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['CellEntityIdsArrayName','entityidsarray','str',1,''], ['VolumeCellEntityId','volumeid','int',1], ['WallCellEntityId','wallid','int',1], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer']]) self.SetOutputMembers([ ['ReferenceSystems','o','vtkPolyData',1,'','the output reference systems with boundary information','vmtksurfacewriter'] ]) def Execute(self): if not self.Mesh: self.PrintError('Error: No input mesh.') return if not self.CellEntityIdsArrayName: self.PrintError('Error: No input CellEntityIdsArrayName.') return if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) threshold = vtk.vtkThreshold() threshold.SetInput(self.Mesh) threshold.ThresholdByUpper(self.VolumeCellEntityId+0.5) threshold.SetInputArrayToProcess(0,0,0,1,self.CellEntityIdsArrayName) threshold.Update() boundaryMesh = threshold.GetOutput() boundaryMesh.GetCellData().SetActiveScalars(self.CellEntityIdsArrayName) boundaryMapper = vtk.vtkDataSetMapper() boundaryMapper.SetInput(boundaryMesh) boundaryMapper.ScalarVisibilityOn() boundaryMapper.SetScalarModeToUseCellData() boundaryMapper.SetScalarRange(boundaryMesh.GetCellData().GetScalars().GetRange()) boundaryActor = vtk.vtkActor() boundaryActor.SetMapper(boundaryMapper) self.vmtkRenderer.Renderer.AddActor(boundaryActor) wallThreshold = vtk.vtkThreshold() wallThreshold.SetInput(boundaryMesh) wallThreshold.ThresholdByLower(self.WallCellEntityId+0.5) wallThreshold.SetInputArrayToProcess(0,0,0,1,self.CellEntityIdsArrayName) wallThreshold.Update() wallMeshToSurface = vtk.vtkGeometryFilter() wallMeshToSurface.SetInput(wallThreshold.GetOutput()) wallMeshToSurface.Update() boundaryReferenceSystems = vtkvmtk.vtkvmtkBoundaryReferenceSystems() boundaryReferenceSystems.SetInput(wallMeshToSurface.GetOutput()) boundaryReferenceSystems.SetBoundaryRadiusArrayName("BoundaryRadius") boundaryReferenceSystems.SetBoundaryNormalsArrayName("BoundaryNormals") boundaryReferenceSystems.SetPoint1ArrayName("Point1Array") boundaryReferenceSystems.SetPoint2ArrayName("Point2Array") boundaryReferenceSystems.Update() self.ReferenceSystems = boundaryReferenceSystems.GetOutput() cellEntityIdsArray = vtk.vtkIntArray() cellEntityIdsArray.SetName(self.CellEntityIdsArrayName) cellEntityIdsArray.SetNumberOfTuples(self.ReferenceSystems.GetNumberOfPoints()) self.ReferenceSystems.GetPointData().AddArray(cellEntityIdsArray) wallMeshToSurface = vtk.vtkGeometryFilter() wallMeshToSurface.SetInput(boundaryMesh) wallMeshToSurface.Update() boundarySurface = wallMeshToSurface.GetOutput() pointCells = vtk.vtkIdList() surfaceCellEntityIdsArray = vtk.vtkIntArray() surfaceCellEntityIdsArray.DeepCopy(boundarySurface.GetCellData().GetArray(self.CellEntityIdsArrayName)) self.PrintLog('') for i in range(self.ReferenceSystems.GetNumberOfPoints()): pointId = boundarySurface.FindPoint(self.ReferenceSystems.GetPoint(i)) boundarySurface.GetPointCells(pointId,pointCells) cellId = pointCells.GetId(0) cellEntityId = surfaceCellEntityIdsArray.GetValue(cellId) cellEntityIdsArray.SetValue(i,cellEntityId) origin = self.ReferenceSystems.GetPoint(i) normal = self.ReferenceSystems.GetPointData().GetArray("BoundaryNormals").GetTuple3(i) radius = self.ReferenceSystems.GetPointData().GetArray("BoundaryRadius").GetTuple1(i) logLine = 'CellEntityId: %d\n' % cellEntityId logLine += ' Origin: %f, %f, %f\n' % (origin[0],origin[1],origin[2]) logLine += ' Normal: %f, %f, %f\n' % (normal[0],normal[1],normal[2]) logLine += ' Radius: %f\n' % radius self.PrintLog(logLine) self.ReferenceSystems.GetPointData().SetActiveScalars(self.CellEntityIdsArrayName) labelsMapper = vtk.vtkLabeledDataMapper(); labelsMapper.SetInput(self.ReferenceSystems) labelsMapper.SetLabelModeToLabelScalars() labelsActor = vtk.vtkActor2D() labelsActor.SetMapper(labelsMapper) self.vmtkRenderer.Renderer.AddActor(labelsActor) self.vmtkRenderer.Render() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagecompare.py0000664000175000017500000000671311757446472017414 0ustar lucaluca#!/usr/bin/env python import sys import vtk import vtkvmtk import pypes vmtkimagecompare = 'vmtkImageCompare' class vmtkImageCompare(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.ReferenceImage = None self.Method = '' self.Tolerance = 1E-8 self.Result = '' self.ResultLog = '' self.SetScriptName('vmtkimagecompare') self.SetScriptDoc('compares an image against a reference') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['ReferenceImage','r','vtkImageData',1,'','the reference image to compare against','vmtkimagereader'], ['Method','method','str',1,'["subtraction","range"]','method of the test'], ['Tolerance','tolerance','float',1,'','tolerance for numerical comparisons'], ]) self.SetOutputMembers([ ['Result','result','bool',1,'','Output boolean stating if images are equal or not'], ['ResultLog','log','str',1,'','Result Log'] ]) def rangeCompare(self): imageRange = self.Image.GetPointData().GetScalars().GetRange() referenceRange = self.ReferenceImage.GetPointData().GetScalars().GetRange() rangeDiff = (imageRange[0] - referenceRange[0], imageRange[1] - referenceRange[1]) self.InputInfo('Image Range: '+ str(imageRange)) self.InputInfo('Reference Image Range: '+ str(referenceRange)) self.InputInfo('Range Difference: '+ str(rangeDiff)) if max([abs(d) for d in rangeDiff]) < self.Tolerance: return True return False def subtractionCompare(self): imagePoints = self.Image.GetNumberOfPoints() referencePoints = self.ReferenceImage.GetNumberOfPoints() self.InputInfo('Image Points: ' + str(imagePoints)) self.InputInfo('Reference Image Points: ' + str(referencePoints)) if abs(imagePoints - referencePoints) > 0 : self.ResultLog = 'Uneven NumberOfPoints' return False imageScalarType = self.Image.GetScalarType() referenceScalarType = self.ReferenceImage.GetScalarType() minScalarType = min(imageScalarType,referenceScalarType) self.Image.SetScalarType(minScalarType) self.ReferenceImage.SetScalarType(minScalarType) imageMath = vtk.vtkImageMathematics() imageMath.SetInput1(self.Image) imageMath.SetInput2(self.ReferenceImage) imageMath.SetOperationToSubtract() imageMath.Update() differenceImage = imageMath.GetOutput() differenceRange = differenceImage.GetPointData().GetScalars().GetRange() self.InputInfo('Difference Range: ' + str(differenceRange)) if max([abs(d) for d in differenceRange]) < self.Tolerance: return True return False def Execute(self): if not self.Image: self.PrintError('Error: No image.') if not self.ReferenceImage: self.PrintError('Error: No reference image.') if not self.Method: self.PrintError('Error: No method.') if (self.Method == 'subtraction'): self.Result = self.subtractionCompare() elif (self.Method == 'range'): self.Result = self.rangeCompare() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshbranchclipper.py0000664000175000017500000001224211757446472020446 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshbranchclipper.py,v $ ## Language: Python ## Date: $Date: 2006/02/23 09:31:39 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes import vmtkrenderer import vmtkcenterlineviewer vmtkmeshbranchclipper = 'vmtkMeshBranchClipper' class vmtkMeshBranchClipper(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.Centerlines = None self.RadiusArrayName = '' self.CutoffRadiusFactor = 1E16 self.ClipValue = 0.0 self.BlankingArrayName = '' self.GroupIdsArrayName = '' self.GroupIds = [] self.InsideOut = 0 self.UseRadiusInformation = 1 self.vmtkRenderer = None self.OwnRenderer = 0 self.Interactive = 0 self.SetScriptName('vmtkmeshbranchclipper') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','','vmtkmeshreader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['GroupIdsArrayName','groupidsarray','str',1], ['GroupIds','groupids','int',-1], ['InsideOut','insideout','bool',1], ['UseRadiusInformation','useradius','bool',1], ['RadiusArrayName','radiusarray','str',1], ['BlankingArrayName','blankingarray','str',1], ['CutoffRadiusFactor','cutoffradiusfactor','float',1,'(0.0,)'], ['ClipValue','clipvalue','float',1], ['Interactive','interactive','bool',1], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','','vmtkmeshwriter'], ['Centerlines','ocenterlines','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def GroupIdsValidator(self,text): import string if not text: return 0 if not text.split(): return 0 for char in text: if char not in string.digits + " ": return 0 return 1 def Execute(self): if not self.Mesh: self.PrintError('Error: No input mesh.') if not self.Centerlines: self.PrintError('Error: No input centerlines.') if self.Interactive and not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 if self.Interactive: self.vmtkRenderer.RegisterScript(self) viewer = vmtkcenterlineviewer.vmtkCenterlineViewer() viewer.Centerlines = self.Centerlines viewer.CellDataArrayName = self.GroupIdsArrayName viewer.vmtkRenderer = self.vmtkRenderer viewer.InputText = self.InputText viewer.OutputText = self.OutputText viewer.PrintError = self.PrintError viewer.PringLog = self.PrintLog viewer.Display = 0 viewer.Execute() groupIdsString = self.InputText("Please input groupIds to clip:\n",self.GroupIdsValidator) self.GroupIds = [int(groupId) for groupId in groupIdsString.split()] clipper = vtkvmtk.vtkvmtkUnstructuredGridCenterlineGroupsClipper() clipper.SetInput(self.Mesh) clipper.SetCenterlines(self.Centerlines) clipper.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) clipper.SetGroupIdsArrayName(self.GroupIdsArrayName) clipper.SetCenterlineRadiusArrayName(self.RadiusArrayName) clipper.SetBlankingArrayName(self.BlankingArrayName) clipper.SetCutoffRadiusFactor(self.CutoffRadiusFactor) clipper.SetClipValue(self.ClipValue) clipper.SetUseRadiusInformation(self.UseRadiusInformation) if self.GroupIds: groupIds = vtk.vtkIdList() for groupId in self.GroupIds: groupIds.InsertNextId(groupId) clipper.SetCenterlineGroupIds(groupIds) clipper.ClipAllCenterlineGroupIdsOff() else: clipper.ClipAllCenterlineGroupIdsOn() if not self.InsideOut: clipper.GenerateClippedOutputOff() else: clipper.GenerateClippedOutputOn() clipper.Update() if not self.InsideOut: self.Mesh = clipper.GetOutput() else: self.Mesh = clipper.GetClippedOutput() if self.Mesh: if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagevesselenhancement.py0000664000175000017500000001636011757446472021474 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagevesselenhancement.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkimagevesselenhancement = 'vmtkImageVesselEnhancement' class vmtkImageVesselEnhancement(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.Method = "frangi" self.EnhancedImage = None self.SigmaMin = 1.0 self.SigmaMax = 1.0 self.NumberOfSigmaSteps = 1 self.SigmaStepMethod = 'equispaced' self.Alpha = 0.5 self.Beta = 0.5 self.Gamma = 5.0 self.Alpha1 = 0.5 self.Alpha2 = 2.0 self.C = 1E-6 self.TimeStep = 1E-2 self.Epsilon = 1E-2 self.WStrength = 25.0 self.Sensitivity = 5.0 self.NumberOfIterations = 0 self.NumberOfDiffusionSubIterations = 0 self.SetScriptName('vmtkimagevesselenhancement') self.SetScriptDoc('compute a feature image for use in segmentation') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['Method','method','str',1,'["frangi","sato","ved","vedm"]'], ['SigmaMin','sigmamin','float',1,'(0.0,)'], ['SigmaMax','sigmamax','float',1,'(0.0,)'], ['NumberOfSigmaSteps','sigmasteps','int',1,'(0,)'], ['SigmaStepMethod','stepmethod','str',1,'["equispaced","logarithmic"]'], ['Alpha1','alpha1','float',1,'(0.0,)','(sato)'], ['Alpha2','alpha2','float',1,'(0.0,)','(sato)'], ['Alpha','alpha','float',1,'(0.0,)','(frangi, ved, vedm)'], ['Beta','beta','float',1,'(0.0,)','(frangi, ved, vedm)'], ['Gamma','gamma','float',1,'(0.0,)','(frangi, ved, vedm)'], ['C','c','float',1,'(0.0,)','(ved)'], ['TimeStep','timestep','float',1,'(0.0,)','(ved, vedm)'], ['Epsilon','epsilon','float',1,'(0.0,)','(ved, vedm)'], ['WStrength','wstrength','float',1,'(0.0,)','(ved, vedm)'], ['Sensitivity','sensitivity','float',1,'(0.0,)','(ved, vedm)'], ['NumberOfIterations','iterations','int',1,'(0,)','(ved, vedm)'], ['NumberOfDiffusionSubIterations','subiterations','int',1,'(1,)','(ved, vedm)'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def ApplyFrangiVesselness(self): vesselness = vtkvmtk.vtkvmtkVesselnessMeasureImageFilter() vesselness.SetInput(self.Image) vesselness.SetSigmaMin(self.SigmaMin) vesselness.SetSigmaMax(self.SigmaMax) vesselness.SetNumberOfSigmaSteps(self.NumberOfSigmaSteps) vesselness.SetAlpha(self.Alpha) vesselness.SetBeta(self.Beta) vesselness.SetGamma(self.Gamma) if self.SigmaStepMethod == 'equispaced': vesselness.SetSigmaStepMethodToEquispaced() elif self.SigmaStepMethod == 'logarithmic': vesselness.SetSigmaStepMethodToLogarithmic() vesselness.Update() self.EnhancedImage = vtk.vtkImageData() self.EnhancedImage.DeepCopy(vesselness.GetOutput()) def ApplySatoVesselness(self): vesselness = vtkvmtk.vtkvmtkSatoVesselnessMeasureImageFilter() vesselness.SetInput(self.Image) vesselness.SetSigmaMin(self.SigmaMin) vesselness.SetSigmaMax(self.SigmaMax) vesselness.SetNumberOfSigmaSteps(self.NumberOfSigmaSteps) vesselness.SetAlpha1(self.Alpha1) vesselness.SetAlpha2(self.Alpha2) if self.SigmaStepMethod == 'equispaced': vesselness.SetSigmaStepMethodToEquispaced() elif self.SigmaStepMethod == 'logarithmic': vesselness.SetSigmaStepMethodToLogarithmic() vesselness.Update() self.EnhancedImage = vtk.vtkImageData() self.EnhancedImage.DeepCopy(vesselness.GetOutput()) def ApplyVED(self): vesselness = vtkvmtk.vtkvmtkVesselEnhancingDiffusionImageFilter() vesselness.SetInput(self.Image) vesselness.SetSigmaMin(self.SigmaMin) vesselness.SetSigmaMax(self.SigmaMax) vesselness.SetNumberOfSigmaSteps(self.NumberOfSigmaSteps) vesselness.SetAlpha(self.Alpha) vesselness.SetBeta(self.Beta) vesselness.SetGamma(self.Gamma) vesselness.SetC(self.C) vesselness.SetTimeStep(self.TimeStep) vesselness.SetEpsilon(self.Epsilon) vesselness.SetWStrength(self.WStrength) vesselness.SetSensitivity(self.Sensitivity) vesselness.SetNumberOfIterations(self.NumberOfIterations) vesselness.SetNumberOfDiffusionSubIterations(self.NumberOfDiffusionSubIterations) if self.SigmaStepMethod == 'equispaced': vesselness.SetSigmaStepMethodToEquispaced() elif self.SigmaStepMethod == 'logarithmic': vesselness.SetSigmaStepMethodToLogarithmic() vesselness.Update() self.EnhancedImage = vtk.vtkImageData() self.EnhancedImage.DeepCopy(vesselness.GetOutput()) def ApplyVEDManniesing(self): vesselness = vtkvmtk.vtkvmtkVesselEnhancingDiffusion3DImageFilter() vesselness.SetInput(self.Image) vesselness.SetSigmaMin(self.SigmaMin) vesselness.SetSigmaMax(self.SigmaMax) vesselness.SetNumberOfSigmaSteps(self.NumberOfSigmaSteps) vesselness.SetAlpha(self.Alpha) vesselness.SetBeta(self.Beta) vesselness.SetGamma(self.Gamma) vesselness.SetTimeStep(self.TimeStep) vesselness.SetEpsilon(self.Epsilon) vesselness.SetOmega(self.WStrength) vesselness.SetSensitivity(self.Sensitivity) vesselness.SetNumberOfIterations(self.NumberOfIterations) vesselness.SetRecalculateVesselness(self.NumberOfDiffusionSubIterations) if self.SigmaStepMethod == 'equispaced': vesselness.SetSigmaStepMethodToEquispaced() elif self.SigmaStepMethod == 'logarithmic': vesselness.SetSigmaStepMethodToLogarithmic() vesselness.Update() self.EnhancedImage = vtk.vtkImageData() self.EnhancedImage.DeepCopy(vesselness.GetOutput()) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.SigmaMax < self.SigmaMin: self.SigmaMax = self.SigmaMin if self.Method == 'frangi': self.ApplyFrangiVesselness() elif self.Method == 'sato': self.ApplySatoVesselness() elif self.Method == 'ved': self.ApplyVED() elif self.Method == 'vedm': self.ApplyVEDManniesing() else: self.PrintError('Error: unsupported vessel enhancement method') self.Image = self.EnhancedImage if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagefeatures.py0000664000175000017500000001671611757446472017610 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagefeatures.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkimagefeatures = 'vmtkImageFeatures' class vmtkImageFeatures(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.FeatureImage = None self.Dimensionality = 3 self.DerivativeSigma = 0.0 self.SigmoidRemapping = 0 self.FeatureImageType = 'gradient' self.UpwindFactor = 1.0 self.FWHMRadius = [3, 3, 3] self.FWHMBackgroundValue = 0.0 self.SetScriptName('vmtkimagefeatures') self.SetScriptDoc('compute a feature image for use in segmentation') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['FeatureImageType','featureimagetype','str',1,'["vtkgradient","gradient","upwind","fwhm"]'], ['Dimensionality','dimensionality','int',1,'(2,3,1)'], ['SigmoidRemapping','sigmoid','bool',1], ['DerivativeSigma','derivativesigma','float',1,'(0.0,)'], ['UpwindFactor','upwindfactor','float',1,'(0.0,1.0)'], ['FWHMRadius','fwhmradius','int',3,'(0,)'], ['FWHMBackgroundValue','fwhmbackgroundvalue','float',1] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def BuildVTKGradientBasedFeatureImage(self): cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() gradientMagnitude = vtk.vtkImageGradientMagnitude() gradientMagnitude.SetInput(cast.GetOutput()) gradientMagnitude.SetDimensionality(self.Dimensionality) gradientMagnitude.Update() imageAdd = vtk.vtkImageMathematics() imageAdd.SetInput(gradientMagnitude.GetOutput()) imageAdd.SetOperationToAddConstant() imageAdd.SetConstantC(1.0) imageAdd.Update() imageInvert = vtk.vtkImageMathematics() imageInvert.SetInput(imageAdd.GetOutput()) imageInvert.SetOperationToInvert() imageInvert.SetConstantC(1E20) imageInvert.DivideByZeroToCOn() imageInvert.Update() self.FeatureImage = vtk.vtkImageData() self.FeatureImage.DeepCopy(imageInvert.GetOutput()) self.FeatureImage.Update() def BuildFWHMBasedFeatureImage(self): cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() fwhmFeatureImageFilter = vtkvmtk.vtkvmtkFWHMFeatureImageFilter() fwhmFeatureImageFilter.SetInput(cast.GetOutput()) fwhmFeatureImageFilter.SetRadius(self.FWHMRadius) fwhmFeatureImageFilter.SetBackgroundValue(self.FWHMBackgroundValue) fwhmFeatureImageFilter.Update() self.FeatureImage = vtk.vtkImageData() self.FeatureImage.DeepCopy(fwhmFeatureImageFilter.GetOutput()) self.FeatureImage.Update() def BuildUpwindGradientBasedFeatureImage(self): cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() gradientMagnitude = vtkvmtk.vtkvmtkUpwindGradientMagnitudeImageFilter() gradientMagnitude.SetInput(cast.GetOutput()) gradientMagnitude.SetUpwindFactor(self.UpwindFactor) gradientMagnitude.Update() featureImage = None if self.SigmoidRemapping==1: scalarRange = gradientMagnitude.GetOutput().GetPointData().GetScalars().GetRange() inputMinimum = scalarRange[0] inputMaximum = scalarRange[1] alpha = - (inputMaximum - inputMinimum) / 6.0 beta = (inputMaximum + inputMinimum) / 2.0 sigmoid = vtkvmtk.vtkvmtkSigmoidImageFilter() sigmoid.SetInput(gradientMagnitude.GetOutput()) sigmoid.SetAlpha(alpha) sigmoid.SetBeta(beta) sigmoid.SetOutputMinimum(0.0) sigmoid.SetOutputMaximum(1.0) sigmoid.Update() featureImage = sigmoid.GetOutput() else: boundedReciprocal = vtkvmtk.vtkvmtkBoundedReciprocalImageFilter() boundedReciprocal.SetInput(gradientMagnitude.GetOutput()) boundedReciprocal.Update() featureImage = boundedReciprocal.GetOutput() self.FeatureImage = vtk.vtkImageData() self.FeatureImage.DeepCopy(featureImage) self.FeatureImage.Update() def BuildGradientBasedFeatureImage(self): cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() if (self.DerivativeSigma > 0.0): gradientMagnitude = vtkvmtk.vtkvmtkGradientMagnitudeRecursiveGaussianImageFilter() gradientMagnitude.SetInput(cast.GetOutput()) gradientMagnitude.SetSigma(self.DerivativeSigma) gradientMagnitude.SetNormalizeAcrossScale(0) gradientMagnitude.Update() else: gradientMagnitude = vtkvmtk.vtkvmtkGradientMagnitudeImageFilter() gradientMagnitude.SetInput(cast.GetOutput()) gradientMagnitude.Update() featureImage = None if self.SigmoidRemapping==1: scalarRange = gradientMagnitude.GetOutput().GetPointData().GetScalars().GetRange() inputMinimum = scalarRange[0] inputMaximum = scalarRange[1] alpha = - (inputMaximum - inputMinimum) / 6.0 beta = (inputMaximum + inputMinimum) / 2.0 sigmoid = vtkvmtk.vtkvmtkSigmoidImageFilter() sigmoid.SetInput(gradientMagnitude.GetOutput()) sigmoid.SetAlpha(alpha) sigmoid.SetBeta(beta) sigmoid.SetOutputMinimum(0.0) sigmoid.SetOutputMaximum(1.0) sigmoid.Update() featureImage = sigmoid.GetOutput() else: boundedReciprocal = vtkvmtk.vtkvmtkBoundedReciprocalImageFilter() boundedReciprocal.SetInput(gradientMagnitude.GetOutput()) boundedReciprocal.Update() featureImage = boundedReciprocal.GetOutput() self.FeatureImage = vtk.vtkImageData() self.FeatureImage.DeepCopy(featureImage) self.FeatureImage.Update() def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.FeatureImageType == 'vtkgradient': self.BuildVTKGradientBasedFeatureImage() elif self.FeatureImageType == 'gradient': self.BuildGradientBasedFeatureImage() elif self.FeatureImageType == 'upwind': self.BuildUpwindGradientBasedFeatureImage() elif self.FeatureImageType == 'fwhm': self.BuildFWHMBasedFeatureImage() else: self.PrintError('Error: unsupported feature image type') self.Image = self.FeatureImage if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacesubdivision.py0000664000175000017500000000450111757446472020663 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacesubdivision.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacesubdivision = 'vmtkSurfaceSubdivision' class vmtkSurfaceSubdivision(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.NumberOfSubdivisions = 1 self.Method = 'linear' self.SetScriptName('vmtksurfacesubdivision') self.SetScriptDoc('subdivide a triangulated surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['NumberOfSubdivisions','subdivisions','int',1,'(0,)','number of triangle subdivisions'], ['Method','method','str',1,'["linear","butterfly","loop"]','subdivision method'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') subdivisionFilter = None if self.Method == 'linear': subdivisionFilter = vtk.vtkLinearSubdivisionFilter() elif self.Method == 'butterfly': subdivisionFilter = vtk.vtkButterflySubdivisionFilter() elif self.Method == 'loop': subdivisionFilter = vtk.vtkLoopSubdivisionFilter() else: self.PrintError('Error: Unsupported subdivision method.') subdivisionFilter.SetInput(self.Surface) subdivisionFilter.SetNumberOfSubdivisions(self.NumberOfSubdivisions) subdivisionFilter.Update() self.Surface = subdivisionFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlineattributes.py0000664000175000017500000000507111757446472021216 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlineattributes.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkcenterlineattributes = 'vmtkCenterlineAttributes' class vmtkCenterlineAttributes(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.AbscissasArrayName = 'Abscissas' self.NormalsArrayName = 'ParallelTransportNormals' self.SetScriptName('vmtkcenterlineattributes') self.SetScriptDoc('compute centerline attributes like abscissa and parallel transport normals; this is a requried step for mapping') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['AbscissasArrayName','abscissasarray','str',1,'','name of the array where centerline abscissas have to be stored'], ['NormalsArrayName','normalsarray','str',1,'','name of the array where parallel transport normals to the centerlines have to be stored'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['AbscissasArrayName','abscissasarray','str',1,'','name of the array where centerline abscissas are stored'], ['NormalsArrayName','normalsarray','str',1,'','name of the array where parallel transport normals to the centerlines are stored'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') centerlineAttributes = vtkvmtk.vtkvmtkCenterlineAttributesFilter() centerlineAttributes.SetInput(self.Centerlines) centerlineAttributes.SetAbscissasArrayName(self.AbscissasArrayName) centerlineAttributes.SetParallelTransportNormalsArrayName(self.NormalsArrayName) centerlineAttributes.Update() self.Centerlines = centerlineAttributes.GetOutput() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshviewer.py0000664000175000017500000001106611757446472017136 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshviewer.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vmtkrenderer import pypes vmtkmeshviewer = 'vmtkMeshViewer' class vmtkMeshViewer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Display = 1 self.Opacity = 1.0 self.ArrayName = '' self.ScalarRange = [0.0, 0.0] self.Legend = 0 self.Grayscale = 0 self.FlatInterpolation = 0 self.Actor = None self.ScalarBarActor = None self.SetScriptName('vmtkmeshviewer') self.SetScriptDoc('display a mesh') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['Display','display','bool',1,'','toggle rendering'], ['Opacity','opacity','float',1,'(0.0,1.0)','object opacity in the scene'], ['ArrayName','array','str',1,'','name of the array where the scalars to be displayed are stored'], ['ScalarRange','scalarrange','float',2,'','range of the scalar map'], ['Legend','legend','bool',1,'','toggle scalar bar'], ['Grayscale','grayscale','bool',1,'','toggle color or grayscale'], ['FlatInterpolation','flat','bool',1,'','toggle flat or shaded surface display'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def BuildView(self): if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if self.Actor != None: self.vmtkRenderer.Renderer.RemoveActor(self.Actor) if self.ScalarBarActor != None: self.vmtkRenderer.Renderer.RemoveActor(self.ScalarBarActor) if self.Mesh != None: mapper = vtk.vtkDataSetMapper() mapper.SetInput(self.Mesh) if (self.ArrayName != ''): self.Mesh.GetPointData().SetActiveScalars(self.ArrayName) if (self.Mesh.GetPointData().GetScalars() != None): array = self.Mesh.GetPointData().GetScalars() if (self.ScalarRange[1] > self.ScalarRange[0]): mapper.SetScalarRange(self.ScalarRange) else: mapper.SetScalarRange(array.GetRange(0)) if (self.Grayscale == 1): lut = vtk.vtkLookupTable() lut.SetValueRange(0.0,1.0) lut.SetSaturationRange(0.0,0.0) mapper.SetLookupTable(lut) self.Actor = vtk.vtkActor() self.Actor.SetMapper(mapper) if (self.FlatInterpolation == 1): self.Actor.GetProperty().SetInterpolationToFlat() self.Actor.GetProperty().SetOpacity(self.Opacity) self.vmtkRenderer.Renderer.AddActor(self.Actor) if (self.Legend == 1) & (self.Actor != None): self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.Actor.GetMapper().GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() ## self.ScalarBarActor.GetLabelTextProperty().SetColor(0.0,0.0,0.0) self.ScalarBarActor.SetLabelFormat('%.2f') self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) if (self.Display == 1): self.vmtkRenderer.Render() if self.OwnRenderer: self.vmtkRenderer.Deallocate() def Execute(self): if (self.Mesh == None) & (self.Display == 1): self.PrintError('Error: no Mesh.') self.BuildView() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkpythonscript.py0000664000175000017500000000465611757446472017535 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagesmoothing.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkpythonscript = 'vmtkPythonScript' class vmtkPythonScript(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.Image2 = None self.Surface = None self.Surface2 = None self.Mesh = None self.Mesh2 = None self.PythonScriptFileName = '' self.SetScriptName('vmtkpythonscript') self.SetScriptDoc('execute a python script contained in a file') self.SetInputMembers([ ['Image','image','vtkImageData',1,'','the input image','vmtkimagereader'], ['Image2','image2','vtkImageData',1,'','the second input image','vmtkimagereader'], ['Surface','surface','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Surface2','surface2','vtkPolyData',1,'','the second input surface','vmtksurfacereader'], ['Mesh','mesh','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['Mesh2','mesh2','vtkUnstructuredGrid',1,'','the second input mesh','vmtkmeshreader'], ['PythonScriptFileName','scriptfile','str',1,'','the name of the file were the Python script resides'] ]) self.SetOutputMembers([ ['Image','oimage','vtkImageData',1,'','the output image','vmtkimagewriter'], ['Surface','osurface','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['Mesh','omesh','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if self.PythonScriptFileName == '': self.PrintError('Error: no PythonScriptFileName') try: execfile(self.PythonScriptFileName) except Exception, error: self.PrintError("Python script error: %s" % error) if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacetransform.py0000664000175000017500000000737711757446472020356 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacetransform.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 improved by ## Hugo Gratama van Andel ## Academic Medical Centre - University of Amsterdam ## Dept. Biomedical Engineering & Physics import vtk import sys import pypes vmtksurfacetransform = 'vmtkSurfaceTransform' class vmtkSurfaceTransform(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.MatrixCoefficients = [] self.InvertMatrix = 0 self.Matrix4x4 = None self.Rotation = [0.0,0.0,0.0] self.Translation = [0.0,0.0,0.0] self.Scaling = [1.0,1.0,1.0] #TODO: define covariant vector array names self.SetScriptName('vmtksurfacetransform') self.SetScriptDoc('transform a surface with a provided matrix') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Matrix4x4','matrix4x4','vtkMatrix4x4',1,'','the input transform matrix'], ['MatrixCoefficients','matrix','float',16,'','coefficients of transform matrix'], ['InvertMatrix','invert','bool',1,'','invert matrix before applying transformation'], ['Rotation','rotation','float',3,'','rotations around the x-,y- and z-axis'], ['Translation','translation','float',3,'','translation in the x-,y- and z-directions'], ['Scaling','scaling','float',3,'','scaling of the x-,y- and z-directions'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if (self.Surface == None): self.PrintError('Error: no Surface.') if not self.Matrix4x4: self.Matrix4x4 = vtk.vtkMatrix4x4() if self.MatrixCoefficients != []: self.PrintLog('Setting up transform matrix using specified coefficients') self.Matrix4x4.DeepCopy(self.MatrixCoefficients) elif self.Translation != [0.0,0.0,0.0] or self.Rotation != [0.0,0.0,0.0] or self.Scaling != [1.0,1.0,1.0]: self.PrintLog('Setting up transform matrix using specified translation, rotation and/or scaling') transform = vtk.vtkTransform() transform.RotateX(self.Rotation[0]) transform.RotateY(self.Rotation[1]) transform.RotateZ(self.Rotation[2]) transform.Translate(self.Translation[0], self.Translation[1], self.Translation[2]) transform.Scale(self.Scaling[0], self.Scaling[1], self.Scaling[2]) self.Matrix4x4.DeepCopy(transform.GetMatrix()) if self.InvertMatrix: self.Matrix4x4.Invert() transform = vtk.vtkMatrixToLinearTransform() transform.SetInput(self.Matrix4x4) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInput(self.Surface) transformFilter.SetTransform(transform) transformFilter.Update() self.Surface = transformFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbranchpatching.py0000664000175000017500000001005411757446472017727 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchpatching.py,v $ ## Language: Python ## Date: $Date: 2006/07/07 10:46:17 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbranchpatching = 'vmtkBranchPatching' class vmtkBranchPatching(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.PatchedData = None self.CircularPatching = 1 self.UseConnectivity = 1 self.LongitudinalPatchSize = 1.0 self.CircularNumberOfPatches = 1 self.PatchSize = [0.0, 0.0] self.GroupIdsArrayName = '' self.LongitudinalMappingArrayName = '' self.CircularMappingArrayName = '' self.LongitudinalPatchNumberArrayName = 'Slab' self.CircularPatchNumberArrayName = 'Sector' self.PatchAreaArrayName = 'PatchArea' self.SetScriptName('vmtkbranchpatching') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['PatchSize','patchsize','float',2,'(0.0,)'], ['LongitudinalPatchSize','longitudinalpatchsize','float',1,'(0.0,)'], ['CircularNumberOfPatches','circularpatches','int',1,'(0,)'], ['CircularPatching','circularpatching','bool',1], ['UseConnectivity','connectivity','bool',1], ['GroupIdsArrayName','groupidsarray','str',1], ['LongitudinalMappingArrayName','longitudinalmappingarray','str',1], ['CircularMappingArrayName','circularmappingarray','str',1], ['LongitudinalPatchNumberArrayName','longitudinalpatchnumberarray','str',1], ['CircularPatchNumberArrayName','circularpatchnumberarray','str',1], ['PatchAreaArrayName','patchareaarray','str',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['PatchedData','patcheddata','vtkImageData',1,'','','vmtkimagewriter'], ['PatchSize','patchsize','float',2], ['LongitudinalPatchNumberArrayName','longitudinalpatchnumberarray','str',1], ['CircularPatchNumberArrayName','circularpatchnumberarray','str',1], ['PatchAreaArrayName','patchareaarray','str',1] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') self.PatchSize = [self.LongitudinalPatchSize, 1.0/float(self.CircularNumberOfPatches)] patchingFilter = vtkvmtk.vtkvmtkPolyDataPatchingFilter() patchingFilter.SetInput(self.Surface) patchingFilter.SetCircularPatching(self.CircularPatching) patchingFilter.SetUseConnectivity(self.UseConnectivity) patchingFilter.SetLongitudinalMappingArrayName(self.LongitudinalMappingArrayName) patchingFilter.SetCircularMappingArrayName(self.CircularMappingArrayName) patchingFilter.SetLongitudinalPatchNumberArrayName(self.LongitudinalPatchNumberArrayName) patchingFilter.SetCircularPatchNumberArrayName(self.CircularPatchNumberArrayName) patchingFilter.SetPatchAreaArrayName(self.PatchAreaArrayName) patchingFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) patchingFilter.SetPatchSize(self.PatchSize) patchingFilter.Update() self.Surface = patchingFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() self.PatchedData = patchingFilter.GetPatchedData() if self.PatchedData.GetSource(): self.PatchedData.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinemeshsections.py0000664000175000017500000001245611757446472021541 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinemeshsections.py,v $ ## Language: Python ## Date: $Date: 2006/10/17 15:16:16 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkcenterlinemeshsections = 'vmtkCenterlineMeshSections' class vmtkCenterlineMeshSections(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.Centerlines = None self.SectionSource = None self.CenterlineSections = None self.TransformSections = False self.UseSectionSource = False self.SourceScaling = False self.SectionIdsArrayName = 'SectionIds' self.SectionNormalsArrayName = 'SectionNormals' self.SectionUpNormalsArrayName = '' self.AdditionalNormalsArrayName = None self.AdditionalScalarsArrayName = None self.OriginOffset = [0.0, 0.0, 0.0] self.VectorsArrayName = '' self.SetScriptName('vmtkcenterlinemeshsections') self.SetScriptDoc('extract mesh sections along centerlines. The script takes in input the mesh and the relative centerlines.') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['Centerlines','centerlines','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['SectionSource','source','vtkPolyData',1,'','the input section source with which to probe the mesh (optional)','vmtksurfacereader'], ['UseSectionSource','usesource','bool',1,'','if off, slice mesh with plane to generate sections; if on, use the SectionSource to probe the mesh'], ['SourceScaling','sourcescaling','bool',1,'','toggle scaling the source with the local radius'], ['TransformSections','transformsections','bool',1,'','transform sections so that they are at the origin, with normal 0,0,1 and upNormal 0,1,0'], ['SectionIdsArrayName','sectionidsarray','str',1,'','the name of the array where the ids identifying sections are stored'], ['SectionNormalsArrayName','normalsarray','str',1,'','the name of the array where normals determining the section planes are stored'], ['SectionUpNormalsArrayName','upnormalsarray','str',1,'','the name of the array where normals determining the "up" orientation of sections are stored'], ['AdditionalNormalsArrayName','additionalnormalsarray','str',1,'','the name of the array that contains normals that will be transformed and assigned to additional data points'], ['AdditionalScalarsArrayName','additionalscalarsarray','str',1,'','the name of the array that contains scalars that will be assigned to additional data points'], ['VectorsArrayName','vectorsarray','str',1,'','the name of the array where vectors, e.g. velocity vectors, are stored'], ['OriginOffset','originoffset','float',3,'','offset of subsequent sections after transformation'] ]) self.SetOutputMembers([ ['CenterlineSections','o','vtkPolyData',1,'','the output sections','vmtksurfacewriter'], ['SectionPointsPolyData','sectionpoints','vtkPolyData',1,'','the additional output poly data storing information about the location and orientation of sections','vmtksurfacewriter'] ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') centerlineSections = vtkvmtk.vtkvmtkUnstructuredGridCenterlineSections() centerlineSections.SetInput(self.Mesh) centerlineSections.SetCenterlines(self.Centerlines) centerlineSections.SetSectionSource(self.SectionSource) centerlineSections.SetUseSectionSource(self.UseSectionSource) centerlineSections.SetSourceScaling(self.SourceScaling) centerlineSections.SetTransformSections(self.TransformSections) centerlineSections.SetOriginOffset(self.OriginOffset) if self.VectorsArrayName: centerlineSections.SetVectorsArrayName(self.VectorsArrayName) centerlineSections.SetSectionIdsArrayName(self.SectionIdsArrayName) centerlineSections.SetSectionNormalsArrayName(self.SectionNormalsArrayName) if self.SectionUpNormalsArrayName: centerlineSections.SetSectionUpNormalsArrayName(self.SectionUpNormalsArrayName) if self.AdditionalNormalsArrayName: centerlineSections.SetAdditionalNormalsArrayName(self.AdditionalNormalsArrayName) if self.AdditionalScalarsArrayName: centerlineSections.SetAdditionalScalarsArrayName(self.AdditionalScalarsArrayName) centerlineSections.Update() self.CenterlineSections = centerlineSections.GetOutput() self.SectionPointsPolyData = centerlineSections.GetSectionPointsPolyData() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagelinetracer.py0000664000175000017500000002163711757446472020120 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagelinetracer.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkimagelinetracer = 'vmtkImageLineTracer' class vmtkImageLineTracer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Line = None self.Axis = 2 self.AutoClose = 0 self.vmtkRenderer = None self.OwnRenderer = 0 self.ImageTracerWidget = None self.ImageActor = None self.SliceVOI = [0,0,0,0,0,0] self.Type = 'freehand' self.Image = None self.SetScriptName('vmtkimagelinetracer') self.SetScriptDoc('interactively trace lines on 3D images; press n and p to move to the next and previous slice, respectively') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['Axis','axis','int',1,'','id of the drawing plane normal'], ['AutoClose','autoclose','bool',1,'','toggle auto close line'], ['Type','type','str',1,'["freehand","contour"]','type of widget to use: freehand drawing or control point-based contour'] ]) self.SetOutputMembers([ ['Line','line','vtkPolyData',1,'','the output line','vmtksurfacewriter'] ]) def NextCallback(self, obj): if self.SliceVOI[self.Axis*2+1] < self.Image.GetWholeExtent()[self.Axis*2+1]: self.SliceVOI[self.Axis*2+1] += 1 self.SliceVOI[self.Axis*2] = self.SliceVOI[self.Axis*2+1] origin = self.Image.GetOrigin() spacing = self.Image.GetSpacing() newOrigin = [origin[0], origin[1], origin[2]] newOrigin[self.Axis] = origin[self.Axis]-spacing[self.Axis] self.Image.SetOrigin(newOrigin) self.ImageActor.SetDisplayExtent(self.SliceVOI) obj.Render() def PreviousCallback(self, obj): if self.SliceVOI[self.Axis*2] > self.Image.GetWholeExtent()[self.Axis*2]: self.SliceVOI[self.Axis*2] -= 1 self.SliceVOI[self.Axis*2+1] = self.SliceVOI[self.Axis*2] origin = self.Image.GetOrigin() spacing = self.Image.GetSpacing() newOrigin = [origin[0], origin[1], origin[2]] newOrigin[self.Axis] = origin[self.Axis]+spacing[self.Axis] self.Image.SetOrigin(newOrigin) self.ImageActor.SetDisplayExtent(self.SliceVOI) obj.Render() def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def SetWidgetProjectionPosition(self,obj,event): self.ImageTracerWidget.SetProjectionPosition(self.SliceVOI[self.Axis*2]*self.Image.GetSpacing()[self.Axis]+self.Image.GetOrigin()[self.Axis]) self.vmtkRenderer.Renderer.Render() def GetLineFromWidget(self,obj,event): if self.Type == 'freehand': path = vtk.vtkPolyData() obj.GetPath(path) elif self.Type == 'contour': path = self.ImageTracerWidget.GetRepresentation().GetContourRepresentationAsPolyData() spacing = self.Image.GetSpacing() translation = [0.0,0.0,0.0] translation[self.Axis] = self.SliceVOI[self.Axis*2]*spacing[self.Axis] transform = vtk.vtkTransform() transform.Translate(translation) pathTransform = vtk.vtkTransformPolyDataFilter() pathTransform.SetInput(path) pathTransform.SetTransform(transform) pathTransform.Update() self.Line = pathTransform.GetOutput() if self.Line.GetSource(): self.Line.GetSource().UnRegisterAllOutputs() def ChangeSlice(self,obj,event): currentSlice = self.SliceVOI[self.Axis*2] slice = int(self.SliderWidget.GetRepresentation().GetValue()) self.SliceVOI[self.Axis*2] = slice self.SliceVOI[self.Axis*2+1] = slice origin = self.Image.GetOrigin() spacing = self.Image.GetSpacing() newOrigin = [origin[0], origin[1], origin[2]] newOrigin[self.Axis] = origin[self.Axis] - (slice - currentSlice) * spacing[self.Axis] self.Image.SetOrigin(newOrigin) self.ImageActor.SetDisplayExtent(self.SliceVOI) self.vmtkRenderer.Renderer.Render() def Display(self): wholeExtent = self.Image.GetExtent() self.SliceVOI[0] = wholeExtent[0] self.SliceVOI[1] = wholeExtent[1] self.SliceVOI[2] = wholeExtent[2] self.SliceVOI[3] = wholeExtent[3] self.SliceVOI[4] = wholeExtent[4] self.SliceVOI[5] = wholeExtent[5] self.SliceVOI[self.Axis*2] = wholeExtent[self.Axis*2] self.SliceVOI[self.Axis*2+1] = wholeExtent[self.Axis*2] range = self.Image.GetScalarRange() imageShifter = vtk.vtkImageShiftScale() imageShifter.SetInput(self.Image) imageShifter.SetShift(-1.0*range[0]) imageShifter.SetScale(255.0/(range[1]-range[0])) imageShifter.SetOutputScalarTypeToUnsignedChar() widgetImage = imageShifter.GetOutput() self.ImageActor.SetInput(widgetImage) self.ImageActor.SetDisplayExtent(self.SliceVOI) self.vmtkRenderer.Renderer.AddActor(self.ImageActor) if self.Type == 'freehand': self.ImageTracerWidget.SetCaptureRadius(1.5) self.ImageTracerWidget.SetViewProp(self.ImageActor) self.ImageTracerWidget.SetInput(widgetImage) self.ImageTracerWidget.ProjectToPlaneOn() self.ImageTracerWidget.SetProjectionNormal(self.Axis) self.ImageTracerWidget.PlaceWidget() self.ImageTracerWidget.SetAutoClose(self.AutoClose) self.ImageTracerWidget.AddObserver("StartInteractionEvent",self.SetWidgetProjectionPosition) self.ImageTracerWidget.AddObserver("EndInteractionEvent",self.GetLineFromWidget) elif self.Type == 'contour': self.ImageTracerWidget.AddObserver("EndInteractionEvent",self.GetLineFromWidget) self.ImageTracerWidget.ContinuousDrawOff() sliderRep = vtk.vtkSliderRepresentation2D() sliderRep.SetValue(0.5*(wholeExtent[self.Axis*2]+wholeExtent[self.Axis*2+1])) sliderRep.SetMinimumValue(wholeExtent[self.Axis*2]) sliderRep.SetMaximumValue(wholeExtent[self.Axis*2+1]) sliderRep.SetTitleText("Slice") sliderRep.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay() sliderRep.GetPoint1Coordinate().SetValue(0.2,0.9) sliderRep.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay() sliderRep.GetPoint2Coordinate().SetValue(0.8,0.9) sliderRep.SetSliderLength(0.02) sliderRep.SetSliderWidth(0.03) sliderRep.SetEndCapLength(0.01) sliderRep.SetEndCapWidth(0.03) sliderRep.SetTubeWidth(0.005) sliderRep.SetLabelFormat("%.0f") self.SliderWidget.AddObserver("InteractionEvent",self.ChangeSlice) self.SliderWidget.SetRepresentation(sliderRep) self.SliderWidget.EnabledOn() interactorStyle = vtk.vtkInteractorStyleImage() self.vmtkRenderer.RenderWindowInteractor.SetInteractorStyle(interactorStyle) self.vmtkRenderer.Render() def Execute(self): if self.Image == None: self.PrintError('Error: no Image.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if self.Type == 'freehand': self.ImageTracerWidget = vtk.vtkImageTracerWidget() elif self.Type == 'contour': self.ImageTracerWidget = vtk.vtkContourWidget() self.ImageTracerWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.SliderWidget = vtk.vtkSliderWidget() self.SliderWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.ImageActor = vtk.vtkImageActor() self.vmtkRenderer.AddKeyBinding('n','Next.',self.NextCallback) self.vmtkRenderer.AddKeyBinding('p','Previous.',self.PreviousCallback) self.vmtkRenderer.AddKeyBinding('i','Interact.', self.InteractCallback) self.Display() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbifurcationprofiles.py0000664000175000017500000001213011757446472021022 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbifurcationprofiles.py,v $ ## Language: Python ## Date: $Date: 2006/10/17 15:16:16 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbifurcationprofiles = 'vmtkBifurcationProfiles' class vmtkBifurcationProfiles(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.BifurcationProfiles = None self.RadiusArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.BlankingArrayName = '' self.BifurcationProfileGroupIdsArrayName = 'BifurcationProfileGroupIds' self.BifurcationProfileBifurcationGroupIdsArrayName = 'BifurcationProfileBifurcationGroupIds' self.BifurcationProfileOrientationArrayName = 'BifurcationProfileOrientation' self.SetScriptName('vmtkbifurcationprofiles') self.SetScriptDoc('compute bifurcation profiles, i.e. the bifurcation splitting lines. The script takes in input the surface and the relative centerlines, both already split into branches.') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface, already split into branches','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','the input centerlines, already split into branches','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where centerline radius is stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['CenterlineIdsArrayName','centerlineidsarray','str',1,'','name of the array where centerline ids are stored'], ['TractIdsArrayName','tractidsarray','str',1,'','name of the array where centerline tract ids are stored'], ['BlankingArrayName','blankingarray','str',1,'','name of the array where centerline blanking information about branches is stored'], ['BifurcationProfileGroupIdsArrayName','bifurcationprofilegroupids','str',1,'','name of the array where the group id to which each profile belongs has to be stored'], ['BifurcationProfileBifurcationGroupIdsArrayName','bifurcationprofilebifurcationgroupids','str',1,'','name of the array where the bifurcation group id to which each profile belongs has to be stored'], ['BifurcationProfileOrientationArrayName','bifurcationprofileorientation','str',1,'','name of the array containing 0 if a profile is upstream and 0 downstream its bifurcation'] ]) self.SetOutputMembers([ ['BifurcationProfiles','o','vtkPolyData',1,'','the output sections','vmtksurfacewriter'], ['BifurcationProfileGroupIdsArrayName','bifurcationprofilegroupids','str',1,'','name of the array where the group id to which each profile belongs are stored'], ['BifurcationProfileBifurcationGroupIdsArrayName','bifurcationprofilebifurcationgroupids','str',1,'','name of the array where the bifurcation group id to which each profile belongs has to be stored'], ['BifurcationProfileOrientationArrayName','bifurcationprofileorientation','str',1,'','name of the array containing 0 if a profile is upstream and 0 downstream its bifurcation'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') bifurcationProfiles = vtkvmtk.vtkvmtkPolyDataBifurcationProfiles() bifurcationProfiles.SetInput(self.Surface) bifurcationProfiles.SetGroupIdsArrayName(self.GroupIdsArrayName) bifurcationProfiles.SetCenterlines(self.Centerlines) bifurcationProfiles.SetCenterlineRadiusArrayName(self.RadiusArrayName) bifurcationProfiles.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) bifurcationProfiles.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) bifurcationProfiles.SetCenterlineTractIdsArrayName(self.TractIdsArrayName) bifurcationProfiles.SetBlankingArrayName(self.BlankingArrayName) bifurcationProfiles.SetBifurcationProfileGroupIdsArrayName(self.BifurcationProfileGroupIdsArrayName) bifurcationProfiles.SetBifurcationProfileBifurcationGroupIdsArrayName(self.BifurcationProfileBifurcationGroupIdsArrayName) bifurcationProfiles.SetBifurcationProfileOrientationArrayName(self.BifurcationProfileOrientationArrayName) bifurcationProfiles.Update() self.BifurcationProfiles = bifurcationProfiles.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbifurcationvectors.py0000664000175000017500000001520311757446472020670 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbifurcationvectors.py,v $ ## Language: Python ## Date: $Date: 2006/10/17 15:16:16 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbifurcationvectors = 'vmtkBifurcationVectors' class vmtkBifurcationVectors(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.ReferenceSystems = None self.BifurcationVectors = None self.RadiusArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.BlankingArrayName = '' self.ReferenceSystemsNormalArrayName = '' self.ReferenceSystemsUpNormalArrayName = '' self.BifurcationVectorsArrayName = 'BifurcationVectors' self.InPlaneBifurcationVectorsArrayName = 'InPlaneBifurcationVectors' self.OutOfPlaneBifurcationVectorsArrayName = 'OutOfPlaneBifurcationVectors' self.InPlaneBifurcationVectorAnglesArrayName = 'InPlaneBifurcationVectorAngles' self.OutOfPlaneBifurcationVectorAnglesArrayName = 'OutOfPlaneBifurcationVectorAngles' self.BifurcationVectorsOrientationArrayName = 'BifurcationVectorsOrientation' self.BifurcationGroupIdsArrayName = 'BifurcationGroupIds' self.NormalizeBifurcationVectors = 0 self.SetScriptName('vmtkbifurcationvectors') self.SetScriptDoc('.') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input split centerlines','vmtksurfacereader'], ['ReferenceSystems','referencesystems','vtkPolyData',1,'','reference systems relative to the split centerlines','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where centerline radius values are stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['CenterlineIdsArrayName','centerlineidsarray','str',1,'','name of the array where centerline ids are stored'], ['TractIdsArrayName','tractidsarray','str',1,'','name of the array where centerline tract ids are stored'], ['BlankingArrayName','blankingarray','str',1,'','name of the array where blanking information about branches is stored'], ['ReferenceSystemsNormalArrayName','normalarray','str',1,'','name of the array where reference system normal vectors are stored'], ['ReferenceSystemsUpNormalArrayName','upnormalarray','str',1,'','name of the array where reference system upnormal vectors are stored'], ['BifurcationVectorsArrayName','vectorsarray','str',1,''], ['InPlaneBifurcationVectorsArrayName','inplanevectorsarray','str',1,''], ['OutOfPlaneBifurcationVectorsArrayName','outofplanevectorsarray','str',1,''], ['InPlaneBifurcationVectorAnglesArrayName','inplaneanglesarray','str',1,''], ['OutOfPlaneBifurcationVectorAnglesArrayName','outofplaneanglesarray','str',1,''], ['BifurcationVectorsOrientationArrayName','orientationarray','str',1,''], ['BifurcationGroupIdsArrayName','bifurcationgroupidsarray','str',1,''], ['NormalizeBifurcationVectors','normalizevectors','bool',1,''] ]) self.SetOutputMembers([ ['BifurcationVectors','o','vtkPolyData',1,'','the output data','vmtksurfacewriter'], ['BifurcationVectorsArrayName','vectorsarray','str',1,''], ['InPlaneBifurcationVectorsArrayName','inplanevectorsarray','str',1,''], ['OutOfPlaneBifurcationVectorsArrayName','outofplanevectorsarray','str',1,''], ['InPlaneBifurcationVectorAnglesArrayName','inplaneanglesarray','str',1,''], ['OutOfPlaneBifurcationVectorAnglesArrayName','outofplaneanglesarray','str',1,''], ['BifurcationVectorsOrientationArrayName','orientationarray','str',1,''], ['BifurcationGroupIdsArrayName','bifurcationgroupidsarray','str',1,''] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') if self.ReferenceSystems == None: self.PrintError('Error: No input reference systems.') centerlineBifurcationVectors = vtkvmtk.vtkvmtkCenterlineBifurcationVectors() centerlineBifurcationVectors.SetInput(self.Centerlines) centerlineBifurcationVectors.SetReferenceSystems(self.ReferenceSystems) centerlineBifurcationVectors.SetRadiusArrayName(self.RadiusArrayName) centerlineBifurcationVectors.SetGroupIdsArrayName(self.GroupIdsArrayName) centerlineBifurcationVectors.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) centerlineBifurcationVectors.SetTractIdsArrayName(self.TractIdsArrayName) centerlineBifurcationVectors.SetBlankingArrayName(self.BlankingArrayName) centerlineBifurcationVectors.SetReferenceSystemGroupIdsArrayName(self.GroupIdsArrayName) centerlineBifurcationVectors.SetReferenceSystemNormalArrayName(self.ReferenceSystemsNormalArrayName) centerlineBifurcationVectors.SetReferenceSystemUpNormalArrayName(self.ReferenceSystemsUpNormalArrayName) centerlineBifurcationVectors.SetBifurcationVectorsArrayName(self.BifurcationVectorsArrayName) centerlineBifurcationVectors.SetInPlaneBifurcationVectorsArrayName(self.InPlaneBifurcationVectorsArrayName) centerlineBifurcationVectors.SetOutOfPlaneBifurcationVectorsArrayName(self.OutOfPlaneBifurcationVectorsArrayName) centerlineBifurcationVectors.SetInPlaneBifurcationVectorAnglesArrayName(self.InPlaneBifurcationVectorAnglesArrayName) centerlineBifurcationVectors.SetOutOfPlaneBifurcationVectorAnglesArrayName(self.OutOfPlaneBifurcationVectorAnglesArrayName) centerlineBifurcationVectors.SetBifurcationVectorsOrientationArrayName(self.BifurcationVectorsOrientationArrayName) centerlineBifurcationVectors.SetBifurcationGroupIdsArrayName(self.BifurcationGroupIdsArrayName) centerlineBifurcationVectors.SetNormalizeBifurcationVectors(self.NormalizeBifurcationVectors) centerlineBifurcationVectors.Update() self.BifurcationVectors = centerlineBifurcationVectors.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagemipviewer.py0000664000175000017500000000763111757446472017775 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagemipviewer.py,v $ ## Language: Python ## Date: $Date: 2006/06/20 12:12:05 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkimagemipviewer = 'vmtkImageMIPViewer' class vmtkImageMIPViewer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Display = 1 self.ArrayName = '' self.SampleDistance = 1.0 self.AutoSampleDistance = 1 self.WindowLevel = [0.0, 0.0] self.Volume = None self.SetScriptName('vmtkimagemipviewer') self.SetScriptDoc('display a 3D image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['ArrayName','array','str',1,'','name of the array to display'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['SampleDistance','sampledistance','float',1,'(0.0,)','the distance at sample projections are generated'], ['AutoSampleDistance','autosampledistance','bool',1,'','toggle automatic sample distance'], ['WindowLevel','windowlevel','float',2,'','the window/level for generating the rendering'], ['Display','display','bool',1,'','toggle rendering'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def BuildView(self): if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if self.Volume: self.vmtkRenderer.Renderer.RemoveVolume(self.Volume) if (self.ArrayName != ''): self.Image.GetPointData().SetActiveScalars(self.ArrayName) scalarRange = [0.0, 0.0] if self.WindowLevel[0] > 0.0: scalarRange = [self.WindowLevel[1] - self.WindowLevel[0]/2.0, self.WindowLevel[1] + self.WindowLevel[0]/2.0] else: scalarRange = self.Image.GetScalarRange() colorTransferFunction = vtk.vtkColorTransferFunction() colorTransferFunction.AddRGBPoint(scalarRange[0], 0.0, 0.0, 0.0) colorTransferFunction.AddRGBPoint(scalarRange[1], 1.0, 1.0, 1.0) volumeMapper = vtk.vtkFixedPointVolumeRayCastMapper() volumeMapper.SetInput(self.Image) volumeMapper.SetBlendModeToMaximumIntensity() if self.AutoSampleDistance: volumeMapper.AutoAdjustSampleDistancesOn() else: volumeMapper.SetSampleDistance(self.SampleDistance) volumeProperty = vtk.vtkVolumeProperty() volumeProperty.ShadeOn() volumeProperty.SetInterpolationTypeToLinear() volumeProperty.SetColor(colorTransferFunction) self.Volume = vtk.vtkVolume() self.Volume.SetMapper(volumeMapper) self.Volume.SetProperty(volumeProperty) self.vmtkRenderer.Renderer.AddVolume(self.Volume) if (self.Display == 1): self.vmtkRenderer.Render() if self.OwnRenderer: self.vmtkRenderer.Deallocate() def Execute(self): if (self.Image == None) & (self.Display == 1): self.PrintError('Error: no Image.') self.BuildView() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshreader.py0000664000175000017500000003355611757446472017107 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshreader.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.16 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import vtk import vtkvmtk import pypes vmtkmeshreader = 'vmtkMeshReader' class vmtkMeshReader(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.InputFileName = '' self.Mesh = 0 self.Output = 0 self.GhostNodes = 1 self.VolumeElementsOnly = 0 self.CellEntityIdsArrayName = 'CellEntityIds' self.SetScriptName('vmtkmeshreader') self.SetScriptDoc('read a mesh and stores it in a vtkUnstructuredGrid object') self.SetInputMembers([ ['Format','f','str',1,'["vtkxml","vtk","fdneut","ngneut","tecplot","tetgen","gambit"]','file format (fdneut - FIDAP neutral format, ngneut - Netgen neutral format)'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh'], ['InputFileName','ifile','str',1,'','input file name'], ['GhostNodes','ghostnodes','bool',1,'','store all nodes for 9-noded quads, 7-noded triangles, 27-noded hexahedra, 18-noded wedges; otherwise, store them as 8-noded quads, 6-noded triangles, 20-noded hexahedra, 15-noded wedges - fdneut only'], ['VolumeElementsOnly','volumeelementsonly','bool',1,'','only read volume elements - fdneut and ngneut'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where entity ids have to be stored - ngneut and tetgen'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where entity ids have been stored - ngneut and tetgen'] ]) def ReadTetGenMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading TetGen mesh file.') import os.path inputFileName = os.path.splitext(self.InputFileName)[0] reader = vtkvmtk.vtkvmtkTetGenReader() reader.SetFileName(inputFileName) reader.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) reader.Update() self.Mesh = reader.GetOutput() def ReadGAMBITMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading GAMBIT mesh file.') reader = vtk.vtkGAMBITReader() reader.SetFileName(self.InputFileName) reader.Update() self.Mesh = reader.GetOutput() def ReadVTKMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading VTK mesh file.') reader = vtk.vtkUnstructuredGridReader() reader.SetFileName(self.InputFileName) reader.Update() self.Mesh = reader.GetOutput() def ReadVTKXMLMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading VTK XML mesh file.') reader = vtk.vtkXMLUnstructuredGridReader() reader.SetFileName(self.InputFileName) reader.Update() self.Mesh = reader.GetOutput() def ReadXdaMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintError('Error: Xda reader not yet implemented.') return # self.PrintLog('Reading Xda mesh file.') # reader = vtkvmtk.vtkvmtkXdaReader() # reader.SetFileName(self.InputFileName) # reader.Update() # self.Mesh = reader.GetOutput() def ReadFDNEUTMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading FDNEUT mesh file.') reader = vtkvmtk.vtkvmtkFDNEUTReader() reader.SetFileName(self.InputFileName) reader.SetGhostNodes(self.GhostNodes) reader.SetSingleCellDataEntityArrayName(self.CellEntityIdsArrayName) reader.SetVolumeElementsOnly(self.VolumeElementsOnly) reader.Update() self.Mesh = reader.GetOutput() def ReadNGNEUTMeshFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading ngneut mesh file.') f=open(self.InputFileName, 'r') self.Mesh = vtk.vtkUnstructuredGrid() self.MeshPoints = vtk.vtkPoints() line = f.readline() numberOfPoints = int(line) self.MeshPoints.SetNumberOfPoints(numberOfPoints) for i in range(numberOfPoints): line = f.readline() splitLine = line.strip().split() point = [float(splitLine[0]),float(splitLine[1]),float(splitLine[2])] self.MeshPoints.SetPoint(i,point) self.Mesh.SetPoints(self.MeshPoints) self.Mesh.Allocate(numberOfPoints*4,1000) line = f.readline() numberOfVolumeCells = int(line) cellEntityIdArray = vtk.vtkIntArray() cellEntityIdArray.SetName(self.CellEntityIdsArrayName) for i in range(numberOfVolumeCells): line = f.readline() splitLine = line.strip().split() cellType = -1 numberOfCellPoints = len(splitLine)-1 pointIds = vtk.vtkIdList() if numberOfCellPoints == 4: cellType = 10 # pointIds.InsertNextId(int(splitLine[0+1])-1) # pointIds.InsertNextId(int(splitLine[1+1])-1) # pointIds.InsertNextId(int(splitLine[2+1])-1) # pointIds.InsertNextId(int(splitLine[3+1])-1) pointIds.InsertNextId(int(splitLine[1+1])-1) pointIds.InsertNextId(int(splitLine[2+1])-1) pointIds.InsertNextId(int(splitLine[3+1])-1) pointIds.InsertNextId(int(splitLine[0+1])-1) elif numberOfCellPoints == 10: cellType = 24 # pointIds.InsertNextId(int(splitLine[0+1])-1) # pointIds.InsertNextId(int(splitLine[1+1])-1) # pointIds.InsertNextId(int(splitLine[2+1])-1) # pointIds.InsertNextId(int(splitLine[3+1])-1) # pointIds.InsertNextId(int(splitLine[4+1])-1) # pointIds.InsertNextId(int(splitLine[7+1])-1) # pointIds.InsertNextId(int(splitLine[5+1])-1) # pointIds.InsertNextId(int(splitLine[6+1])-1) # pointIds.InsertNextId(int(splitLine[8+1])-1) # pointIds.InsertNextId(int(splitLine[9+1])-1) pointIds.InsertNextId(int(splitLine[1+1])-1) pointIds.InsertNextId(int(splitLine[2+1])-1) pointIds.InsertNextId(int(splitLine[3+1])-1) pointIds.InsertNextId(int(splitLine[0+1])-1) pointIds.InsertNextId(int(splitLine[7+1])-1) pointIds.InsertNextId(int(splitLine[9+1])-1) pointIds.InsertNextId(int(splitLine[8+1])-1) pointIds.InsertNextId(int(splitLine[4+1])-1) pointIds.InsertNextId(int(splitLine[5+1])-1) pointIds.InsertNextId(int(splitLine[6+1])-1) entityId = int(splitLine[0]) cellEntityIdArray.InsertNextValue(entityId) self.Mesh.InsertNextCell(cellType,pointIds) if self.VolumeElementsOnly == 0: line = f.readline() numberOfSurfaceCells = int(line) for i in range(numberOfSurfaceCells): line = f.readline() splitLine = line.strip().split() cellType = -1 numberOfCellPoints = len(splitLine)-1 pointIds = vtk.vtkIdList() if numberOfCellPoints == 3: cellType = 5 for j in range(numberOfCellPoints): pointIds.InsertNextId(int(splitLine[j+1])-1) elif numberOfCellPoints == 6: cellType = 22 for j in range(3): pointIds.InsertNextId(int(splitLine[j+1])-1) pointIds.InsertNextId(int(splitLine[5+1])-1) pointIds.InsertNextId(int(splitLine[3+1])-1) pointIds.InsertNextId(int(splitLine[4+1])-1) entityId = int(splitLine[0]) cellEntityIdArray.InsertNextValue(entityId) self.Mesh.InsertNextCell(cellType,pointIds) self.Mesh.Squeeze() self.Mesh.GetCellData().AddArray(cellEntityIdArray) def ReadTecplotMeshFile(self): self.PrintLog('Reading Tecplot surface file.') if self.InputFileName[-3:] == '.gz': import gzip f=gzip.open(self.InputFileName, 'r') else: f=open(self.InputFileName, 'r') line = f.readline() if line.split()[0] == 'TITLE': line = f.readline() if (line.split()[0] == 'VARIABLES') | (line.split('=')[0] == 'VARIABLES'): arrayNames = line.split('=')[1].strip().split(',') arrayNames[0:3] = [] self.PrintLog("ArrayNames" + str(arrayNames)) line = f.readline() if line.split()[0] == 'ZONE': lineNid = line.find('N=') lineN = line[lineNid : lineNid+line[lineNid:].find(',') ].split('=')[1] numberOfNodes = int(lineN) lineEid = line.find('E=') lineE = line[lineEid : lineEid+line[lineEid:].find(',') ].split('=')[1] numberOfElements = int(lineE) self.PrintLog("Reading " + str(numberOfNodes)+" nodes.") points = vtk.vtkPoints() cells = vtk.vtkCellArray() points.SetNumberOfPoints(numberOfNodes) self.Mesh = vtk.vtkUnstructuredGrid() self.Mesh.SetPoints(points) for arrayName in arrayNames: array = vtk.vtkDoubleArray() array.SetName(arrayName) array.SetNumberOfTuples(numberOfNodes) self.Mesh.GetPointData().AddArray(array) data = f.read().split() dataCounter = 0 for i in range(numberOfNodes): point = [float(data[dataCounter]),float(data[dataCounter+1]),float(data[dataCounter+2])] dataCounter += 3 points.SetPoint(i,point) for j in range(len(arrayNames)): self.Mesh.GetPointData().GetArray(arrayNames[j]).SetComponent(i,0,float(data[dataCounter])) dataCounter += 1 self.PrintLog("Reading " + str(numberOfElements)+" elements.") cellIds = vtk.vtkIdList() for i in range(numberOfElements): cellIds.Initialize() cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 legal = 1 for j in range(cellIds.GetNumberOfIds()): if cellIds.GetId(j) < 0: legal = 0 break if not legal: continue cells.InsertNextCell(cellIds) self.Mesh.SetCells(10,cells) self.Mesh.Update() def Execute(self): extensionFormats = {'vtu':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'FDNEUT':'fdneut', 'xda':'xda', 'neu':'ngneut', 'gneu':'gambit', 'tec':'tecplot', 'node':'tetgen', 'ele':'tetgen'} if self.InputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.InputFileName = tkFileDialog.askopenfilename(title="Input mesh",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.InputFileName) if not self.InputFileName: self.PrintError('Error: no InputFileName.') if self.GuessFormat and self.InputFileName and not self.Format: import os.path extension = os.path.splitext(self.InputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.ReadVTKMeshFile() elif (self.Format == 'vtkxml'): self.ReadVTKXMLMeshFile() elif (self.Format == 'gambit'): self.ReadGAMBITMeshFile() elif (self.Format == 'fdneut'): self.ReadFDNEUTMeshFile() elif (self.Format == 'ngneut'): self.ReadNGNEUTMeshFile() elif (self.Format == 'xda'): self.ReadXdaMeshFile() elif (self.Format == 'tecplot'): self.ReadTecplotMeshFile() elif (self.Format == 'tetgen'): self.ReadTetGenMeshFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() self.Output = self.Mesh if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagevoipainter.py0000664000175000017500000002012711757446472020141 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagevoipainter.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import math import vtkvmtk import vmtkrenderer import pypes vmtkimagevoipainter = 'vmtkImageVOIPainter' class vmtkImageVOIPainter(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.CubeSource = vtk.vtkCubeSource() self.CubeActor = vtk.vtkActor() self.BoxActive = 0 self.BoxBounds = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.PaintValue = 0.0 self.PaintedImage = vtk.vtkImageData() self.vmtkRenderer = None self.OwnRenderer = 0 self.PlaneWidgetX = None self.PlaneWidgetY = None self.PlaneWidgetZ = None self.BoxWidget = None self.Image = None self.Interactive = 1 self.SetScriptName('vmtkimagevoipainter') self.SetScriptDoc('fill a cubical region of an image with a given gray level') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['Interactive','interactive','bool',1,'','toggle interactivity'], ['BoxBounds','boxbounds','float',6,'','bounds of the cubical region for non-interactive mode'], ['PaintValue','paintvalue','float',1,'','graylevel to fill the region with'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def HideCube(self,object, event): self.CubeActor.VisibilityOff() def UpdateCube(self,object, event): polyData = vtk.vtkPolyData() object.GetPolyData(polyData) polyData.ComputeBounds() self.CubeSource.SetBounds(polyData.GetBounds()) self.CubeSource.Modified() self.CubeActor.VisibilityOn() def Display(self): wholeExtent = self.Image.GetWholeExtent() picker = vtk.vtkCellPicker() picker.SetTolerance(0.005) self.PlaneWidgetX.SetInput(self.Image) self.PlaneWidgetX.SetPlaneOrientationToXAxes() self.PlaneWidgetX.SetSliceIndex(wholeExtent[0]) self.PlaneWidgetX.DisplayTextOn() self.PlaneWidgetX.SetPicker(picker) self.PlaneWidgetX.KeyPressActivationOff() self.PlaneWidgetX.On() self.PlaneWidgetY.SetInput(self.Image) self.PlaneWidgetY.SetPlaneOrientationToYAxes() self.PlaneWidgetY.SetSliceIndex(wholeExtent[2]) self.PlaneWidgetY.DisplayTextOn() self.PlaneWidgetY.SetPicker(picker) self.PlaneWidgetY.KeyPressActivationOff() self.PlaneWidgetY.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) self.PlaneWidgetY.On() self.PlaneWidgetZ.SetInput(self.Image) self.PlaneWidgetZ.SetPlaneOrientationToZAxes() self.PlaneWidgetZ.SetSliceIndex(wholeExtent[4]) self.PlaneWidgetZ.DisplayTextOn() self.PlaneWidgetZ.SetPicker(picker) self.PlaneWidgetZ.KeyPressActivationOff() self.PlaneWidgetZ.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) self.PlaneWidgetZ.On() self.BoxWidget.SetPriority(1.0) self.BoxWidget.SetHandleSize(5E-3) self.BoxWidget.SetInput(self.Image) self.BoxWidget.PlaceWidget() self.BoxWidget.RotationEnabledOff() self.BoxWidget.AddObserver("StartInteractionEvent", self.HideCube) self.BoxWidget.AddObserver("EndInteractionEvent", self.UpdateCube) self.BoxWidget.AddObserver("EnableEvent", self.UpdateCube) self.BoxWidget.AddObserver("DisableEvent", self.HideCube) polyData = vtk.vtkPolyData() self.BoxWidget.GetPolyData(polyData) polyData.ComputeBounds() self.CubeSource.SetBounds(polyData.GetBounds()) cubeMapper = vtk.vtkPolyDataMapper() cubeMapper.SetInput(self.CubeSource.GetOutput()) self.CubeActor.SetMapper(cubeMapper) self.CubeActor.GetProperty().SetColor(0.6,0.6,0.2) self.CubeActor.GetProperty().SetOpacity(0.25) self.CubeActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.CubeActor) self.vmtkRenderer.Render() self.vmtkRenderer.Renderer.RemoveActor(self.CubeActor) self.BoxActive = 0 if self.BoxWidget.GetEnabled() == 1: polyData = vtk.vtkPolyData() self.BoxWidget.GetPolyData(polyData) polyData.ComputeBounds() bounds = polyData.GetBounds() self.BoxBounds[0] = bounds[0] self.BoxBounds[1] = bounds[1] self.BoxBounds[2] = bounds[2] self.BoxBounds[3] = bounds[3] self.BoxBounds[4] = bounds[4] self.BoxBounds[5] = bounds[5] self.BoxActive = 1 self.BoxWidget.Off() def PaintVOI(self): wholeExtent = self.Image.GetWholeExtent() origin = self.Image.GetOrigin() spacing = self.Image.GetSpacing() paintedVOI = [0,0,0,0,0,0] paintedVOI[0] = max(wholeExtent[0],int(math.ceil((self.BoxBounds[0]-origin[0])/spacing[0]))) paintedVOI[1] = min(wholeExtent[1],int(math.floor((self.BoxBounds[1]-origin[0])/spacing[0]))) paintedVOI[2] = max(wholeExtent[2],int(math.ceil((self.BoxBounds[2]-origin[1])/spacing[1]))) paintedVOI[3] = min(wholeExtent[3],int(math.floor((self.BoxBounds[3]-origin[1])/spacing[1]))) paintedVOI[4] = max(wholeExtent[4],int(math.ceil((self.BoxBounds[4]-origin[2])/spacing[2]))) paintedVOI[5] = min(wholeExtent[5],int(math.floor((self.BoxBounds[5]-origin[2])/spacing[2]))) imageBoxPainter = vtkvmtk.vtkvmtkImageBoxPainter() imageBoxPainter.SetInput(self.Image) imageBoxPainter.SetBoxExtent(paintedVOI) imageBoxPainter.SetBoxDefinitionToUseExtent() imageBoxPainter.SetPaintValue(self.PaintValue) imageBoxPainter.Update() self.PaintedImage.ShallowCopy(imageBoxPainter.GetOutput()) self.PaintedImage.Update() if self.PaintedImage.GetSource(): self.PaintedImage.GetSource().UnregisterAllOutputs() def Execute(self): if self.Image == None: self.PrintError('Error: no Image.') if self.Interactive == 1: if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) self.PlaneWidgetX = vtk.vtkImagePlaneWidget() self.PlaneWidgetX.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetY = vtk.vtkImagePlaneWidget() self.PlaneWidgetY.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetZ = vtk.vtkImagePlaneWidget() self.PlaneWidgetZ.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.BoxWidget = vtk.vtkBoxWidget() self.BoxWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.vmtkRenderer.AddKeyBinding('i','Interact.', self.InteractCallback) self.Display() while (self.BoxActive == 1): self.PaintVOI() self.Image = self.PaintedImage self.Display() else: self.PaintVOI() if self.OwnRenderer: self.vmtkRenderer.Deallocate() self.Image = self.PaintedImage if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacetomesh.py0000664000175000017500000000370111757446472017625 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacetomesh.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfacetomesh = 'vmtkSurfaceToMesh' class vmtkSurfaceToMesh(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Mesh = None self.CleanInput = 1 self.SetScriptName('vmtksurfacetomesh') self.SetScriptDoc('convert surface to a mesh') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['CleanInput','cleaninput','bool',1,'','clean unused points in the input'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter']]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.CleanInput == 1: cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(self.Surface) cleaner.Update() self.Surface = cleaner.GetOutput() surfaceToMeshFilter = vtkvmtk.vtkvmtkPolyDataToUnstructuredGridFilter() surfaceToMeshFilter.SetInput(self.Surface) surfaceToMeshFilter.Update() self.Mesh = surfaceToMeshFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacereader.py0000664000175000017500000002223611757446472017574 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacereader.py,v $ ## Language: Python ## Date: $Date: 2006/05/22 08:33:12 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacereader = 'vmtkSurfaceReader' class vmtkSurfaceReader(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.InputFileName = '' self.Surface = 0 self.Output = 0 self.SetScriptName('vmtksurfacereader') self.SetScriptDoc('read a surface and store it in a vtkPolyData object') self.SetInputMembers([ ['Format','f','str',1,'["vtkxml","vtk","stl","ply","tecplot"]','file format'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['Surface','i','vtkPolyData',1,'','the input surface'], ['InputFileName','ifile','str',1,'','input file name'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def ReadVTKSurfaceFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading VTK surface file.') reader = vtk.vtkPolyDataReader() reader.SetFileName(self.InputFileName) reader.Update() self.Surface = reader.GetOutput() def ReadVTKXMLSurfaceFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading VTK XML surface file.') reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(self.InputFileName) reader.Update() self.Surface = reader.GetOutput() def ReadSTLSurfaceFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading STL surface file.') reader = vtk.vtkSTLReader() reader.SetFileName(self.InputFileName) reader.Update() self.Surface = reader.GetOutput() def ReadPLYSurfaceFile(self): if (self.InputFileName == ''): self.PrintError('Error: no InputFileName.') self.PrintLog('Reading PLY surface file.') reader = vtk.vtkPLYReader() reader.SetFileName(self.InputFileName) reader.Update() self.Surface = reader.GetOutput() def ReadTecplotSurfaceFile(self): self.PrintLog('Reading Tecplot surface file.') f=open(self.InputFileName, 'r') line = f.readline() if line.split()[0] == 'TITLE': line = f.readline() if (line.split()[0] == 'VARIABLES') | (line.split('=')[0] == 'VARIABLES'): arrayNames = line.split('=')[1].strip().split(',') arrayNames[0:3] = [] self.PrintLog("ArrayNames" + str(arrayNames)) line = f.readline() if line.split()[0] == 'ZONE': lineNid = line.find('N=') lineN = line[lineNid : lineNid+line[lineNid:].find(',') ].split('=')[1] numberOfNodes = int(lineN) lineEid = line.find('E=') lineE = line[lineEid : lineEid+line[lineEid:].find(',') ].split('=')[1] numberOfElements = int(lineE) elementType = 'TRIANGLE' if line.find('ET=') != -1: if 'TRIANGLE' in line: elementType = 'TRIANGLE' elif 'QUADRILATERAL' in line: elementType = 'QUADRILATERAL' self.PrintLog("Reading " + str(numberOfNodes)+" nodes.") points = vtk.vtkPoints() cells = vtk.vtkCellArray() points.SetNumberOfPoints(numberOfNodes) self.Surface = vtk.vtkPolyData() self.Surface.SetPoints(points) self.Surface.SetPolys(cells) for arrayName in arrayNames: array = vtk.vtkDoubleArray() array.SetName(arrayName) array.SetNumberOfTuples(numberOfNodes) self.Surface.GetPointData().AddArray(array) self.Surface.Update() data = f.read().split() dataCounter = 0 for i in range(numberOfNodes): point = [float(data[dataCounter]),float(data[dataCounter+1]),float(data[dataCounter+2])] dataCounter += 3 points.SetPoint(i,point) for j in range(len(arrayNames)): self.Surface.GetPointData().GetArray(arrayNames[j]).SetComponent(i,0,float(data[dataCounter])) dataCounter += 1 self.PrintLog("Reading " + str(numberOfElements)+" elements.") cellIds = vtk.vtkIdList() for i in range(numberOfElements): cellIds.Initialize() cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 if elementType == "QUADRILATERAL": cellIds.InsertNextId(int(data[dataCounter])-1) dataCounter += 1 cells.InsertNextCell(cellIds) ## self.PrintLog('Reading Tecplot surface file.') ## f=open(self.InputFileName, 'r') ## line = f.readline() ## arrayNames = line.split('=')[1].strip().split(',') ## arrayNames[0:3] = [] ## self.PrintLog("ArrayNames" + str(arrayNames)) ## line = f.readline() ## splitLine = line.split('=') ## numberOfNodes = int(splitLine[1].split(',')[0]) ## numberOfElements = int(splitLine[2].split(',')[0]) ## self.PrintLog("Reading " + str(numberOfNodes)+" nodes.") ## points = vtk.vtkPoints() ## cells = vtk.vtkCellArray() ## points.SetNumberOfPoints(numberOfNodes) ## self.Surface = vtk.vtkPolyData() ## self.Surface.SetPoints(points) ## self.Surface.SetPolys(cells) ## for arrayName in arrayNames: ## array = vtk.vtkDoubleArray() ## array.SetName(arrayName) ## array.SetNumberOfTuples(numberOfNodes) ## self.Surface.GetPointData().AddArray(array) ## self.Surface.Update() ## for i in range(numberOfNodes): ## line = f.readline() ## splitLine = line.strip().split(' ') ## point = [float(splitLine[0]),float(splitLine[1]),float(splitLine[2])] ## points.SetPoint(i,point) ## for j in range(len(arrayNames)): ## self.Surface.GetPointData().GetArray(arrayNames[j]).SetComponent(i,0,float(splitLine[j+3])) ## self.PrintLog("Reading " + str(numberOfElements)+" elements.") ## cellIds = vtk.vtkIdList() ## for i in range(numberOfElements): ## cellIds.Initialize() ## line = f.readline() ## splitLine = line.strip().split(' ') ## cellIds.InsertNextId(int(splitLine[0])-1) ## cellIds.InsertNextId(int(splitLine[1])-1) ## cellIds.InsertNextId(int(splitLine[2])-1) ## cells.InsertNextCell(cellIds) def Execute(self): extensionFormats = {'vtp':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'stl':'stl', 'ply':'ply', 'tec':'tecplot', 'dat':'tecplot'} if self.InputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.InputFileName = tkFileDialog.askopenfilename(title="Input surface",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.InputFileName) if not self.InputFileName: self.PrintError('Error: no InputFileName.') if self.GuessFormat and self.InputFileName and not self.Format: import os.path extension = os.path.splitext(self.InputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.ReadVTKSurfaceFile() elif (self.Format == 'vtkxml'): self.ReadVTKXMLSurfaceFile() elif (self.Format == 'stl'): self.ReadSTLSurfaceFile() elif (self.Format == 'ply'): self.ReadPLYSurfaceFile() elif (self.Format == 'tecplot'): self.ReadTecplotSurfaceFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() self.Output = self.Surface if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimageviewer.py0000664000175000017500000001525011757446472017263 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimageviewer.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkimageviewer = 'vmtkImageViewer' class vmtkImageViewer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Display = 1 self.ArrayName = '' self.Picker = None self.PlaneWidgetX = None self.PlaneWidgetY = None self.PlaneWidgetZ = None self.Margins = 0 self.TextureInterpolation = 1 self.ContinuousCursor = 0 self.WindowLevel = [0.0, 0.0] self.SetScriptName('vmtkimageviewer') self.SetScriptDoc('display a 3D image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['ArrayName','array','str',1,'','name of the array to display'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['WindowLevel','windowlevel','float',2,'','the window/level for displaying the image'], ['Display','display','bool',1,'','toggle rendering'], ['Margins','margins','bool',1,'','toggle margins for tilting image planes'], ['TextureInterpolation','textureinterpolation','bool',1,'','toggle interpolation of graylevels on image planes'], ['ContinuousCursor','continuouscursor','bool',1,'','toggle use of physical continuous coordinates for the cursor'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'], ['PlaneWidgetX','xplane','vtkImagePlaneWidget',1,'','the X image plane widget'], ['PlaneWidgetY','yplane','vtkImagePlaneWidget',1,'','the Y image plane widget'], ['PlaneWidgetZ','zplane','vtkImagePlaneWidget',1,'','the Z image plane widget'] ]) def CharCallback(self, obj): return def BuildView(self): if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if (self.ArrayName != ''): self.Image.GetPointData().SetActiveScalars(self.ArrayName) wholeExtent = self.Image.GetWholeExtent() if self.Picker == None: self.Picker = vtk.vtkCellPicker() if self.PlaneWidgetX == None: self.PlaneWidgetX = vtk.vtkImagePlaneWidget() if self.PlaneWidgetY == None: self.PlaneWidgetY = vtk.vtkImagePlaneWidget() if self.PlaneWidgetZ == None: self.PlaneWidgetZ = vtk.vtkImagePlaneWidget() self.Picker.SetTolerance(0.005) self.PlaneWidgetX.SetResliceInterpolateToLinear() self.PlaneWidgetX.SetTextureInterpolate(self.TextureInterpolation) self.PlaneWidgetX.SetUseContinuousCursor(self.ContinuousCursor) self.PlaneWidgetX.SetInput(self.Image) self.PlaneWidgetX.SetPlaneOrientationToXAxes() self.PlaneWidgetX.SetSliceIndex(wholeExtent[0]) self.PlaneWidgetX.DisplayTextOn() self.PlaneWidgetX.SetPicker(self.Picker) self.PlaneWidgetX.KeyPressActivationOff() self.PlaneWidgetX.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) if self.Margins: self.PlaneWidgetX.SetMarginSizeX(0.05) self.PlaneWidgetX.SetMarginSizeY(0.05) else: self.PlaneWidgetX.SetMarginSizeX(0.0) self.PlaneWidgetX.SetMarginSizeY(0.0) if self.WindowLevel[0] != 0.0: self.PlaneWidgetX.SetWindowLevel(self.WindowLevel[0],self.WindowLevel[1]) self.PlaneWidgetX.On() self.PlaneWidgetY.SetResliceInterpolateToLinear() self.PlaneWidgetY.SetTextureInterpolate(self.TextureInterpolation) self.PlaneWidgetY.SetUseContinuousCursor(self.ContinuousCursor) self.PlaneWidgetY.SetInput(self.Image) self.PlaneWidgetY.SetPlaneOrientationToYAxes() self.PlaneWidgetY.SetSliceIndex(wholeExtent[2]) self.PlaneWidgetY.DisplayTextOn() self.PlaneWidgetY.SetPicker(self.Picker) self.PlaneWidgetY.KeyPressActivationOff() self.PlaneWidgetY.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) self.PlaneWidgetY.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) if self.Margins: self.PlaneWidgetY.SetMarginSizeX(0.05) self.PlaneWidgetY.SetMarginSizeY(0.05) else: self.PlaneWidgetY.SetMarginSizeX(0.0) self.PlaneWidgetY.SetMarginSizeY(0.0) if self.WindowLevel[0] != 0.0: self.PlaneWidgetY.SetWindowLevel(self.WindowLevel[0],self.WindowLevel[1]) self.PlaneWidgetY.On() self.PlaneWidgetZ.SetResliceInterpolateToLinear() self.PlaneWidgetZ.SetTextureInterpolate(self.TextureInterpolation) self.PlaneWidgetZ.SetUseContinuousCursor(self.ContinuousCursor) self.PlaneWidgetZ.SetInput(self.Image) self.PlaneWidgetZ.SetPlaneOrientationToZAxes() self.PlaneWidgetZ.SetSliceIndex(wholeExtent[4]) self.PlaneWidgetZ.DisplayTextOn() self.PlaneWidgetZ.SetPicker(self.Picker) self.PlaneWidgetZ.KeyPressActivationOff() self.PlaneWidgetZ.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) self.PlaneWidgetZ.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) if self.Margins: self.PlaneWidgetZ.SetMarginSizeX(0.05) self.PlaneWidgetZ.SetMarginSizeY(0.05) else: self.PlaneWidgetZ.SetMarginSizeX(0.0) self.PlaneWidgetZ.SetMarginSizeY(0.0) if self.WindowLevel[0] != 0.0: self.PlaneWidgetZ.SetWindowLevel(self.WindowLevel[0],self.WindowLevel[1]) self.PlaneWidgetZ.On() if (self.Display == 1): self.vmtkRenderer.Render() if self.OwnRenderer: self.vmtkRenderer.Deallocate() def Execute(self): if (self.Image == None) & (self.Display == 1): self.PrintError('Error: no Image.') self.BuildView() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacescaling.py0000664000175000017500000000356111757446472017752 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacescaling.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacescaling = 'vmtkSurfaceScaling' class vmtkSurfaceScaling(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ScaleFactor = None self.SetScriptName('vmtksurfacescaling') self.SetScriptDoc('scale a surface by an isotropic factor') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ScaleFactor','scale','float',1,'(0.0,)','isotropic scaling factor'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if (self.Surface == None): self.PrintError('Error: no Surface.') transform = vtk.vtkTransform() transform.Scale(self.ScaleFactor,self.ScaleFactor,self.ScaleFactor) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInput(self.Surface) transformFilter.SetTransform(transform) transformFilter.Update() self.Surface = transformFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshtosurface.py0000664000175000017500000000376711757446472017641 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshtosurface.py,v $ ## Language: Python ## Date: $Date: 2006/04/06 16:47:46 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkmeshtosurface = 'vmtkMeshToSurface' class vmtkMeshToSurface(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Mesh = None self.CleanOutput = 0 self.SetScriptName('vmtkmeshtosurface') self.SetScriptDoc('convert a mesh to a surface by throwing out volume elements and (optionally) the relative points') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['CleanOutput','cleanoutput','bool',1,'','toggle cleaning the unused points'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter']]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') meshToSurfaceFilter = vtk.vtkGeometryFilter() meshToSurfaceFilter.SetInput(self.Mesh) meshToSurfaceFilter.Update() self.Surface = meshToSurfaceFilter.GetOutput() if self.CleanOutput == 1: cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(meshToSurfaceFilter.GetOutput()) cleaner.Update() self.Surface = cleaner.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkdelaunayvoronoi.py0000664000175000017500000002322511757446472020176 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkdelaunayvoronoi.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:52:56 $ ## Version: $Revision: 1.20 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkdelaunayvoronoi = 'vmtkDelaunayVoronoi' class vmtkNonManifoldSurfaceChecker(object): def __init__(self): self.Surface = 0 self.NumberOfNonManifoldEdges = 0 self.Report = 0 self.NonManifoldEdgePointIds = vtk.vtkIdList() self.PrintError = None def Execute(self): if (self.Surface == 0): self.PrintError('NonManifoldSurfaceChecker error: Surface not set') return self.NonManifoldEdgesFound = 0 self.Report = '' self.NonManifoldEdgePointIds.Initialize() neighborhoods = vtkvmtk.vtkvmtkNeighborhoods() neighborhoods.SetNeighborhoodTypeToPolyDataManifoldNeighborhood() neighborhoods.SetDataSet(self.Surface) neighborhoods.Build() neighborCellIds = vtk.vtkIdList() cellPointIds = vtk.vtkIdList() self.Surface.BuildCells() self.Surface.BuildLinks(0) self.Surface.Update() numberOfNonManifoldEdges = 0 for i in range(neighborhoods.GetNumberOfNeighborhoods()): neighborhood = neighborhoods.GetNeighborhood(i) for j in range(neighborhood.GetNumberOfPoints()): neighborId = neighborhood.GetPointId(j) if (i2): numberOfNonManifoldEdges = numberOfNonManifoldEdges + 1 self.Report = self.Report + "Non-manifold edge found" + str(i) + ' ' + str(neighborId) + '.\n' self.NonManifoldEdgePointIds.InsertNextId(i) self.NonManifoldEdgePointIds.InsertNextId(neighborId) class vmtkDelaunayVoronoi(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.FlipNormals = 0 self.CapDisplacement = 0.0 self.RadiusArrayName = 'MaximumInscribedSphereRadius' self.CheckNonManifold = 0 self.RemoveSubresolutionTetrahedra = 0 self.SubresolutionFactor = 1.0 self.SimplifyVoronoi = 0 self.UseTetGen = 0 self.TetGenDetectInter = 1 self.DelaunayTessellation = None self.VoronoiDiagram = None self.PoleIds = None self.SetScriptName('vmtkdelaunayvoronoi') self.SetScriptDoc('') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['CheckNonManifold','nonmanifoldcheck','bool',1,'','toggle checking the surface for non-manifold edges'], ['FlipNormals','flipnormals','bool',1,'','flip normals after outward normal computation; outward oriented normals must be computed for the removal of outer tetrahedra; the algorithm might fail so for weird geometries, so changing this might solve the problem'], ['CapDisplacement','capdisplacement','float',1,'','displacement of the center points of caps at open profiles along their normals (avoids the creation of degenerate tetrahedra)'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where radius values of maximal inscribed spheres have to be stored'], ['DelaunayTessellation','delaunaytessellation','vtkUnstructuredGrid',1,'','optional input Delaunay tessellation'], ['RemoveSubresolutionTetrahedra','removesubresolution','bool',1,'','toggle removal of subresolution tetrahedra from Delaunay tessellation'], ['SubresolutionFactor','subresolutionfactor','float',1,'(0.0,)','factor for removal of subresolution tetrahedra, expressing the size of the circumsphere relative to the local edge length size of surface triangles'], ['SimplifyVoronoi','simplifyvoronoi','bool',1,'','toggle simplification of Voronoi diagram'], ['UseTetGen','usetetgen','bool',1,'','toggle use TetGen to compute Delaunay tessellation'], ['TetGenDetectInter','tetgendetectinter','bool',1,'','TetGen option']]) self.SetOutputMembers([ ['RadiusArrayName','radiusarray','str',1,'','name of the array where radius values of maximal inscribed spheres are stored'], ['DelaunayTessellation','delaunaytessellation','vtkUnstructuredGrid',1,'','','vmtkmeshwriter'], ['VoronoiDiagram','voronoidiagram','vtkPolyData',1,'','','vmtksurfacewriter'], ['PoleIds','poleids','vtkIdList',1]]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.CheckNonManifold: self.PrintLog('NonManifold check.') nonManifoldChecker = vmtkNonManifoldSurfaceChecker() nonManifoldChecker.Surface = self.Surface nonManifoldChecker.PrintError = self.PrintError nonManifoldChecker.Execute() if nonManifoldChecker.NumberOfNonManifoldEdges > 0: self.PrintLog(nonManifoldChecker.Report) return self.PrintLog('Cleaning surface.') surfaceCleaner = vtk.vtkCleanPolyData() surfaceCleaner.SetInput(self.Surface) surfaceCleaner.Update() self.PrintLog('Triangulating surface.') surfaceTriangulator = vtk.vtkTriangleFilter() surfaceTriangulator.SetInput(surfaceCleaner.GetOutput()) surfaceTriangulator.PassLinesOff() surfaceTriangulator.PassVertsOff() surfaceTriangulator.Update() surfaceCapper = vtkvmtk.vtkvmtkCapPolyData() surfaceCapper.SetInput(surfaceTriangulator.GetOutput()) surfaceCapper.SetDisplacement(self.CapDisplacement) surfaceCapper.SetInPlaneDisplacement(self.CapDisplacement) surfaceCapper.Update() capCenterIds = surfaceCapper.GetCapCenterIds() surfaceNormals = vtk.vtkPolyDataNormals() surfaceNormals.SetInput(surfaceCapper.GetOutput()) surfaceNormals.SplittingOff() surfaceNormals.AutoOrientNormalsOn() surfaceNormals.SetFlipNormals(self.FlipNormals) surfaceNormals.ComputePointNormalsOn() surfaceNormals.ConsistencyOn() surfaceNormals.Update() inputSurface = surfaceNormals.GetOutput() if self.UseTetGen: self.PrintLog('Running TetGen.') import vmtkscripts surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = inputSurface surfaceToMesh.Execute() tetgen = vmtkscripts.vmtkTetGen() tetgen.Mesh = surfaceToMesh.Mesh tetgen.PLC = 1 tetgen.NoMerge = 1 tetgen.Quality = 0 if self.TetGenDetectInter: tetgen.DetectInter = 1 tetgen.NoMerge = 0 tetgen.OutputSurfaceElements = 0 tetgen.Execute() self.DelaunayTessellation = tetgen.Mesh else: delaunayTessellator = vtk.vtkDelaunay3D() delaunayTessellator.CreateDefaultLocator() delaunayTessellator.SetInput(surfaceNormals.GetOutput()) delaunayTessellator.Update() self.DelaunayTessellation = delaunayTessellator.GetOutput() normalsArray = surfaceNormals.GetOutput().GetPointData().GetNormals() self.DelaunayTessellation.GetPointData().AddArray(normalsArray) internalTetrahedraExtractor = vtkvmtk.vtkvmtkInternalTetrahedraExtractor() internalTetrahedraExtractor.SetInput(self.DelaunayTessellation) internalTetrahedraExtractor.SetOutwardNormalsArrayName(normalsArray.GetName()) if self.RemoveSubresolutionTetrahedra: internalTetrahedraExtractor.RemoveSubresolutionTetrahedraOn() internalTetrahedraExtractor.SetSubresolutionFactor(self.SubresolutionFactor) internalTetrahedraExtractor.SetSurface(inputSurface) if capCenterIds.GetNumberOfIds() > 0: internalTetrahedraExtractor.UseCapsOn() internalTetrahedraExtractor.SetCapCenterIds(capCenterIds) internalTetrahedraExtractor.Update() self.DelaunayTessellation = internalTetrahedraExtractor.GetOutput() voronoiDiagramFilter = vtkvmtk.vtkvmtkVoronoiDiagram3D() voronoiDiagramFilter.SetInput(self.DelaunayTessellation) voronoiDiagramFilter.SetRadiusArrayName(self.RadiusArrayName) voronoiDiagramFilter.Update() self.PoleIds = voronoiDiagramFilter.GetPoleIds() self.VoronoiDiagram = voronoiDiagramFilter.GetOutput() if self.SimplifyVoronoi: voronoiDiagramSimplifier = vtkvmtk.vtkvmtkSimplifyVoronoiDiagram() voronoiDiagramSimplifier.SetInput(voronoiDiagramFilter.GetOutput()) voronoiDiagramSimplifier.SetUnremovablePointIds(voronoiDiagramFilter.GetPoleIds()) voronoiDiagramSimplifier.Update() self.VoronoiDiagram = voronoiDiagramSimplifier.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacemodeller.py0000664000175000017500000000450511757446472020134 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacemodeller.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacemodeller = 'vmtkSurfaceModeller' class vmtkSurfaceModeller(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Image = None self.SampleSpacing = -1.0 self.NegativeInside = 1 self.SetScriptName('vmtksurfacemodeller') self.SetScriptDoc('converts a surface to an image containing the signed distance transform from the surface points') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['SampleSpacing','samplespacing','float',1,'(0.0,)','spacing of the output image (isotropic)'], ['NegativeInside','negativeinside','bool',1,'','toggle sign of distance transform negative inside the surface'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter']]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') surfaceModellerFilter = vtk.vtkSurfaceReconstructionFilter() surfaceModellerFilter.SetInput(self.Surface) surfaceModellerFilter.SetSampleSpacing(self.SampleSpacing) surfaceModellerFilter.Update() self.Image = surfaceModellerFilter.GetOutput() if self.NegativeInside: negate = vtk.vtkImageMathematics() negate.SetInput(self.Image) negate.SetConstantK(-1.0) negate.SetOperationToMultiplyByK() negate.Update() self.Image = negate.GetOutput() if self.Image.GetSource(): self.Image.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/CMakeLists.txt0000664000175000017500000001115211757446472016240 0ustar lucalucaPROJECT(VMTK_SCRIPTS) SET(SCRIPTS_SRCS vmtkmeshcompare.py vmtkimagecompare.py vmtksurfacecompare.py vmtkactivetubes.py vmtkbifurcationprofiles.py vmtkbifurcationreferencesystems.py vmtkbifurcationsections.py vmtkbifurcationvectors.py vmtkboundarylayer.py vmtkboundaryreferencesystems.py vmtkbranchclipper.py vmtkbranchextractor.py vmtkbranchgeometry.py vmtkbranchmapping.py vmtkbranchmetrics.py vmtkbranchpatching.py vmtkbranchsections.py vmtkcenterlineattributes.py vmtkcenterlinegeometry.py vmtkcenterlinelabeler.py vmtkcenterlinemeshsections.py vmtkcenterlinemerge.py vmtkcenterlinemodeller.py vmtkcenterlineoffsetattributes.py vmtkcenterlineresampling.py vmtkcenterlines.py vmtkcenterlinesections.py vmtkcenterlinesmoothing.py vmtkcenterlineviewer.py vmtkdelaunayvoronoi.py vmtkdistancetocenterlines.py vmtkendpointextractor.py vmtkflowextensions.py vmtkicpregistration.py vmtkimagecast.py vmtkimagecompose.py vmtkimagecurvedmpr.py vmtkimagefeaturecorrection.py vmtkimagefeatures.py vmtkimageinitialization.py vmtkimagelinetracer.py vmtkimagemipviewer.py vmtkimageobjectenhancement.py vmtkimagereader.py vmtkimagereslice.py vmtkimageseeder.py vmtkimageshiftscale.py vmtkimagesmoothing.py vmtkimagevesselenhancement.py vmtkimageviewer.py vmtkimagevoipainter.py vmtkimagevoiselector.py vmtkimagewriter.py vmtklevelsetsegmentation.py vmtklineartoquadratic.py vmtklineresampling.py vmtklocalgeometry.py vmtkmarchingcubes.py vmtkmeshboundaryinspector.py vmtkmeshbranchclipper.py vmtkmeshclipper.py vmtkmeshdatareader.py vmtkmeshlambda2.py vmtkmeshlinearize.py vmtkmeshgenerator.py vmtkmeshprojection.py vmtkmeshreader.py vmtkmeshscaling.py vmtkmeshtetrahedralize.py vmtkmeshtosurface.py vmtkmeshtransform.py vmtkmeshtransformtoras.py vmtkmeshvectorfromcomponents.py vmtkmeshviewer.py vmtkmeshvorticityhelicity.py vmtkmeshwallshearrate.py vmtkmeshwriter.py vmtknetworkextraction.py vmtknetworkeditor.py vmtknetworkwriter.py vmtkpointsplitextractor.py vmtkpointtransform.py vmtkpolyballmodeller.py vmtkpotentialfit.py vmtkpythonscript.py vmtkrenderer.py vmtkrendertoimage.py vmtkrbfinterpolation.py vmtksurfaceappend.py vmtksurfacecapper.py vmtksurfacecelldatatopointdata.py vmtksurfacecenterlineprojection.py vmtksurfaceclipper.py vmtksurfaceconnectivity.py vmtksurfacedecimation.py vmtksurfacedistance.py vmtksurfacekiteremoval.py vmtksurfacemodeller.py vmtksurfacenormals.py vmtksurfacepointdatatocelldata.py vmtksurfaceprojection.py vmtksurfacereader.py vmtksurfacereferencesystemtransform.py vmtksurfaceremeshing.py vmtksurfacescaling.py vmtksurfacesmoothing.py vmtksurfacesubdivision.py vmtksurfacetransform.py vmtksurfacetransforminteractive.py vmtksurfacetransformtoras.py vmtksurfacetriangle.py vmtksurfacetomesh.py vmtksurfaceviewer.py vmtksurfacewriter.py vmtksurfmesh.py vmtktetgen.py vmtktetringenerator.py ) SET(MODULE_SRCS vmtkscripts.py ) OPTION(VMTK_CONTRIB_SCRIPTS "Install modules from the vmtkScripts/contrib directory." OFF) IF (VMTK_CONTRIB_SCRIPTS) SUBDIRS(contrib) ENDIF (VMTK_CONTRIB_SCRIPTS) IF(NOT VMTK_SCRIPTS_INSTALL_BIN_DIR) #SET(VMTK_SCRIPTS_INSTALL_BIN_DIR ${VMTK_SCRIPTS_INSTALL_ROOT}/bin) SET(VMTK_SCRIPTS_INSTALL_BIN_DIR bin) ENDIF(NOT VMTK_SCRIPTS_INSTALL_BIN_DIR) IF(NOT VMTK_SCRIPTS_INSTALL_LIB_DIR) #SET(VMTK_SCRIPTS_INSTALL_LIB_DIR ${VMTK_SCRIPTS_INSTALL_ROOT}/lib/vmtk/vmtk) SET(VMTK_SCRIPTS_INSTALL_LIB_DIR lib/vmtk/vmtk) ENDIF(NOT VMTK_SCRIPTS_INSTALL_LIB_DIR) FOREACH (SCRIPT_FILE ${SCRIPTS_SRCS}) CONFIGURE_FILE(${VMTK_SCRIPTS_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_SCRIPTS_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) ENDFOREACH (SCRIPT_FILE) #INSTALL_FILES(${VMTK_SCRIPTS_INSTALL_LIB_DIR} .py ${SCRIPTS_SRCS} ${MODULE_SRCS}) INSTALL(FILES ${SCRIPTS_SRCS} ${MODULE_SRCS} DESTINATION ${VMTK_SCRIPTS_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries) IF (NOT WIN32 AND NOT VMTK_MINIMAL_INSTALL) SET (STRIPPED_SCRIPTS_SRCS ) FOREACH (SCRIPT_FILE ${SCRIPTS_SRCS}) STRING(REGEX REPLACE ".py$" "" STRIPPED_SCRIPT_FILE ${SCRIPT_FILE}) CONFIGURE_FILE(${PYPES_SOURCE_DIR}/pyperun.py ${VMTK_SCRIPTS_BINARY_DIR}/${STRIPPED_SCRIPT_FILE} COPYONLY) SET (STRIPPED_SCRIPTS_SRCS ${STRIPPED_SCRIPTS_SRCS} ${VMTK_SCRIPTS_BINARY_DIR}/${STRIPPED_SCRIPT_FILE}) ENDFOREACH (SCRIPT_FILE) #INSTALL_PROGRAMS(${VMTK_SCRIPTS_INSTALL_BIN_DIR} FILES ${STRIPPED_SCRIPTS_SRCS}) INSTALL(PROGRAMS ${STRIPPED_SCRIPTS_SRCS} DESTINATION ${VMTK_SCRIPTS_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables) ENDIF (NOT WIN32 AND NOT VMTK_MINIMAL_INSTALL) vmtk-1.0.1/vmtkScripts/vmtkbranchmapping.py0000664000175000017500000001302011757446472017561 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchmapping.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.11 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbranchmapping = 'vmtkBranchMapping' class vmtkBranchMapping(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.ReferenceSystems = None self.AbscissasArrayName = '' self.NormalsArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.ReferenceSystemsNormalArrayName = '' self.RadiusArrayName = '' self.BlankingArrayName = '' self.AngularMetricArrayName = '' self.AbscissaMetricArrayName = '' self.HarmonicMappingArrayName = 'HarmonicMapping' self.BoundaryMetricArrayName = 'BoundaryMetric' self.StretchedMappingArrayName = 'StretchedMapping' self.SetScriptName('vmtkbranchmapping') self.SetScriptDoc('') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['ReferenceSystems','referencesystems','vtkPolyData',1,'','','vmtksurfacereader'], ['AbscissasArrayName','abscissasarray','str',1], ['NormalsArrayName','normalsarray','str',1], ['GroupIdsArrayName','groupidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['ReferenceSystemsNormalArrayName','referencesystemsnormalarray','str',1], ['RadiusArrayName','radiusarray','str',1], ['BlankingArrayName','blankingarray','str',1], ['AngularMetricArrayName','angularmetricarray','str',1], ['HarmonicMappingArrayName','harmonicmappingarray','str',1], ['AbscissaMetricArrayName','abscissametricarray','str',1], ['BoundaryMetricArrayName','boundarymetricarray','str',1], ['StretchedMappingArrayName','stretchedmappingarray','str',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['HarmonicMappingArrayName','harmonicmappingarray','str',1], ['BoundaryMetricArrayName','boundarymetricarray','str',1], ['StretchedMappingArrayName','stretchedmappingarray','str',1] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') if self.ReferenceSystems == None: self.PrintError('Error: No input reference systems.') self.PrintLog('Computing boundary metric') boundaryMetricFilter = vtkvmtk.vtkvmtkPolyDataReferenceSystemBoundaryMetricFilter() boundaryMetricFilter.SetInput(self.Surface) boundaryMetricFilter.SetBoundaryMetricArrayName(self.BoundaryMetricArrayName) boundaryMetricFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) boundaryMetricFilter.SetCenterlines(self.Centerlines) boundaryMetricFilter.SetCenterlineAbscissasArrayName(self.AbscissasArrayName) boundaryMetricFilter.SetCenterlineRadiusArrayName(self.RadiusArrayName) boundaryMetricFilter.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) boundaryMetricFilter.SetCenterlineTractIdsArrayName(self.TractIdsArrayName) boundaryMetricFilter.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) boundaryMetricFilter.SetReferenceSystems(self.ReferenceSystems) boundaryMetricFilter.SetReferenceSystemGroupIdsArrayName(self.GroupIdsArrayName) boundaryMetricFilter.Update() self.PrintLog('Computing harmonic mapping') harmonicMappingFilter = vtkvmtk.vtkvmtkPolyDataMultipleCylinderHarmonicMappingFilter() harmonicMappingFilter.SetInput(boundaryMetricFilter.GetOutput()) harmonicMappingFilter.SetHarmonicMappingArrayName(self.HarmonicMappingArrayName) harmonicMappingFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) harmonicMappingFilter.Update() self.PrintLog('Stretching harmonic mapping') stretchFilter = vtkvmtk.vtkvmtkPolyDataStretchMappingFilter() stretchFilter.SetInput(harmonicMappingFilter.GetOutput()) stretchFilter.SetStretchedMappingArrayName(self.StretchedMappingArrayName) stretchFilter.SetHarmonicMappingArrayName(self.HarmonicMappingArrayName) stretchFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) stretchFilter.SetMetricArrayName(self.AbscissaMetricArrayName) stretchFilter.SetBoundaryMetricArrayName(self.BoundaryMetricArrayName) stretchFilter.UseBoundaryMetricOn() stretchFilter.Update() self.Surface = stretchFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtklineartoquadratic.py0000664000175000017500000001135711757446472020476 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtklineartoquadratic.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtklineartoquadratic = 'vmtkLinearToQuadratic' class vmtkLinearToQuadratic(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.Surface = None self.Mode = 'volume' self.SubdivisionMethod = 'linear' self.UseBiquadraticWedge = True self.CapSurface = False self.CellEntityIdsArrayName = None self.ProjectedCellEntityId = 1 self.JacobianRelaxation = 0.0 self.NegativeJacobianTolerance = 0.0 self.QuadratureOrder = 10 self.SetScriptName('vmtklineartoquadratic') self.SetScriptDoc('convert the elements of a mesh from linear to quadratic') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['Surface','r','vtkPolyData',1,'','the reference surface to project nodes onto','vmtksurfacereader'], ['Mode','mode','str',1,'["volume","surface"]','kind of elements to work with'], ['UseBiquadraticWedge','biquadraticwedge','bool',1,'','if on, convert linear wedges to 18-noded biquadratic quadratic wedges, otherwise use 15-noded quadratic wedges'], ['CapSurface','capsurface','bool',1,'','if on, cap the reference surface before projecting'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where entity ids relative to cells are stored'], ['JacobianRelaxation','jacobianrelaxation','bool',1,'','if on, relax projected nodes until Jacobians are all positive'], ['ProjectedCellEntityId','projectedid','int',1,'','id of the entity that is to be projected onto the reference surface'], ['QuadratureOrder','quadratureorder','int',1,'','quadrature order for checking negative Jacobians'], ['NegativeJacobianTolerance','jacobiantolerance','float',1,'','tolerance for the evaluation of negative Jacobians'], ['SubdivisionMethod','subdivisionmethod','str',1,'["linear","butterfly"]','subdivision method for surface elements'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter']]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') linearToQuadraticFilter = None if self.Mode == 'volume': surface = self.Surface if self.Surface and self.CapSurface: capper = vtkvmtk.vtkvmtkSimpleCapPolyData() capper.SetInput(self.Surface) capper.SetCellEntityIdsArrayName('foo') capper.Update() surface = capper.GetOutput() linearToQuadraticFilter = vtkvmtk.vtkvmtkLinearToQuadraticMeshFilter() linearToQuadraticFilter.SetReferenceSurface(surface) linearToQuadraticFilter.SetUseBiquadraticWedge(self.UseBiquadraticWedge) linearToQuadraticFilter.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) linearToQuadraticFilter.SetJacobianRelaxation(self.JacobianRelaxation) linearToQuadraticFilter.SetProjectedCellEntityId(self.ProjectedCellEntityId) linearToQuadraticFilter.SetQuadratureOrder(self.QuadratureOrder) linearToQuadraticFilter.SetNegativeJacobianTolerance(self.NegativeJacobianTolerance) elif self.Mode == 'surface': linearToQuadraticFilter = vtkvmtk.vtkvmtkLinearToQuadraticSurfaceMeshFilter() if self.SubdivisionMethod == 'linear': linearToQuadraticFilter.SetSubdivisionMethodToLinear() elif self.SubdivisionMethod == 'butterfly': linearToQuadraticFilter.SetSubdivisionMethodToButterfly() else: self.PrintError('Unsupported subdivision method.') else: self.PrintError('Unsupported mode.') linearToQuadraticFilter.SetInput(self.Mesh) linearToQuadraticFilter.Update() self.Mesh = linearToQuadraticFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinesmoothing.py0000664000175000017500000000412111757446472021032 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinesmoothing.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:52:56 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkcenterlinesmoothing = 'vmtkCenterlineSmoothing' class vmtkCenterlineSmoothing(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.NumberOfSmoothingIterations = 100 self.SmoothingFactor = 0.1 self.SetScriptName('vmtkcenterlinesmoothing') self.SetScriptDoc('smooth centerlines with a moving average filter') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['NumberOfSmoothingIterations','iterations','int',1,'(0,)'], ['SmoothingFactor','factor','float',1,'(0.0,)'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') centerlineSmoothing = vtkvmtk.vtkvmtkCenterlineSmoothing() centerlineSmoothing.SetInput(self.Centerlines) centerlineSmoothing.SetNumberOfSmoothingIterations(self.NumberOfSmoothingIterations) centerlineSmoothing.SetSmoothingFactor(self.SmoothingFactor) centerlineSmoothing.Update() self.Centerlines = centerlineSmoothing.GetOutput() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagecast.py0000664000175000017500000000564011757446472016716 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagereslice.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkimagecast = 'vmtkImageCast' class vmtkImageCast(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.OutputType = 'float' self.ShiftScale = 1 self.WindowLevel = [0.0,0.0] self.SetScriptName('vmtkimagecast') self.SetScriptDoc('cast an image to a specified type') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['OutputType','type','str',1,'["float","double","uchar","short"]','the output image type'], ['ShiftScale','shiftscale','int',1,'','shift scale values to fit windowlevel'], ['WindowLevel','windowlevel','float',2,'','window and level for value mapping'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.OutputType == 'uchar' and self.ShiftScale: shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(self.Image) if self.WindowLevel[0] == 0.0: scalarRange = self.Image.GetScalarRange() shiftScale.SetShift(-scalarRange[0]) shiftScale.SetScale(255.0/(scalarRange[1]-scalarRange[0])) else: shiftScale.SetShift(-(self.WindowLevel[1]-self.WindowLevel[0]/2.0)) shiftScale.SetScale(255.0/self.WindowLevel[0]) shiftScale.SetOutputScalarTypeToUnsignedChar() shiftScale.ClampOverflowOn() shiftScale.Update() self.Image = shiftScale.GetOutput() else: cast = vtk.vtkImageCast() cast.SetInput(self.Image) if self.OutputType == 'float': cast.SetOutputScalarTypeToFloat() elif self.OutputType == 'double': cast.SetOutputScalarTypeToDouble() elif self.OutputType == 'uchar': cast.SetOutputScalarTypeToUnsignedChar() elif self.OutputType == 'short': cast.SetOutputScalarTypeToShort() cast.Update() self.Image = cast.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinelabeler.py0000664000175000017500000001210611757446472020433 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinelabeler.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:34:45 $ ## Version: $Revision: 1.2 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes import vmtkcenterlineviewer vmtkcenterlinelabeler = 'vmtkCenterlineLabeler' class vmtkCenterlineLabeler(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.GroupIdsArrayName = '' self.LabelIdsArrayName = 'LabelIds' self.Labeling = [] self.vmtkRenderer = None self.OwnRenderer = 0 self.SetScriptName('vmtkcenterlinelabeler') self.SetScriptDoc('') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['GroupIdsArrayName','groupidsarray','str',1,''], ['LabelIdsArrayName','labelidsarray','str',1,''], ['Labeling','labeling','int',-1,''], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer']]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'], ['LabelIdsArrayName','labelidsarray','str',1,'']]) def LabelValidator(self,text): import string if not text: return 0 if not text.split(): return 0 for char in text: if char not in string.digits + " ": return 0 return 1 def Execute(self): if not self.Centerlines: self.PrintError('Error: No input centerlines.') if not self.GroupIdsArrayName: self.PrintError('Error: GroupIdsArrayName not specified.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) groupIdsArray = self.Centerlines.GetCellData().GetArray(self.GroupIdsArrayName) groupIds = [] for i in range(groupIdsArray.GetNumberOfTuples()): groupIds.append(int(groupIdsArray.GetComponent(i,0))) groupIds.sort() uniqueGroupIds = [] for groupId in groupIds: if groupId not in uniqueGroupIds: uniqueGroupIds.append(groupId) labelMap = {} if not self.Labeling: viewer = vmtkcenterlineviewer.vmtkCenterlineViewer() viewer.Centerlines = self.Centerlines viewer.CellDataArrayName = self.GroupIdsArrayName viewer.vmtkRenderer = self.vmtkRenderer viewer.InputStream = self.InputStream viewer.OutputStream = self.OutputStream #viewer.InputText = self.InputText #viewer.OutputText = self.OutputText #viewer.PrintError = self.PrintError #viewer.PringLog = self.PrintLog viewer.Execute() ok = False while not ok: labelString = self.InputText("Please input labels for the following groupIds:\n%s\n" % " ".join([str(groupId) for groupId in uniqueGroupIds]),self.LabelValidator) labels = [int(label) for label in labelString.split()] if len(labels) == len(uniqueGroupIds): ok = True for groupId in uniqueGroupIds: labelMap[groupId] = labels[uniqueGroupIds.index(groupId)] else: if len(self.Labeling) != 2 * len(uniqueGroupIds): self.PrintError('Error: incorrect labeling specified') for i in range(len(self.Labeling)/2): groupId = self.Labeling[2*i] labelId = self.Labeling[2*i+1] if not groupId in uniqueGroupIds: self.PrintError('Error: groupId %d does not exist' % groupId) labelMap[groupId] = labelId labelIdsArray = vtk.vtkIntArray() labelIdsArray.SetName(self.LabelIdsArrayName) labelIdsArray.SetNumberOfComponents(1) labelIdsArray.SetNumberOfTuples(self.Centerlines.GetNumberOfCells()) groupIdsArray = self.Centerlines.GetCellData().GetArray(self.GroupIdsArrayName) for i in range(groupIdsArray.GetNumberOfTuples()): groupId = int(groupIdsArray.GetComponent(i,0)) labelIdsArray.SetComponent(i,0,labelMap[groupId]) self.Centerlines.GetCellData().AddArray(labelIdsArray) self.Centerlines.Update() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacecenterlineprojection.py0000664000175000017500000000415211757446472022554 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacecenterlineprojection.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.5 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfacecenterlineprojection = 'vmtkSurfaceCenterlineProjection' class vmtkSurfaceCenterlineProjection(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.UseRadiusInformation = 0 self.RadiusArrayName = '' self.SetScriptName('vmtksurfacecenterlineprojection') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['UseRadiusInformation','useradius','bool',1], ['RadiusArrayName','radiusarray','str',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') projectionFilter = vtkvmtk.vtkvmtkPolyDataCenterlineProjection() projectionFilter.SetInput(self.Surface) projectionFilter.SetCenterlines(self.Centerlines) projectionFilter.SetUseRadiusInformation(self.UseRadiusInformation) projectionFilter.SetCenterlineRadiusArrayName(self.RadiusArrayName) projectionFilter.Update() self.Surface = projectionFilter.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshcompare.py0000775000175000017500000001262611757446472017271 0ustar lucaluca#!/usr/bin/env python import sys import vtk import vtkvmtk import pypes vmtkmeshcompare = 'vmtkMeshCompare' class vmtkMeshCompare(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.ReferenceMesh = None self.Method = '' self.ArrayName = '' self.Tolerance = 1E-8 self.Result = '' self.ResultLog = '' self.ResultData = None self.SetScriptName('vmtkmeshcompare') self.SetScriptDoc('compares a mesh against a reference') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['ReferenceMesh','r','vtkUnstructuredGrid',1,'','the reference mesh to compare against','vmtkmeshreader'], ['Method','method','str',1,'["quality","pointarray","cellarray"]','method of the test'], ['ArrayName','array','str',1,'','name of the array'], ['Tolerance','tolerance','float',1,'','tolerance for numerical comparisons'], ]) self.SetOutputMembers([ ['Result','result','bool',1,'','Output boolean stating if meshes are equal or not'], ['ResultData','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['ResultLog','log','str',1,'','Result Log'] ]) def arrayCompare(self): calculator = vtk.vtkArrayCalculator() attributeData = None referenceAttributeData = None if self.Method == 'pointarray': attributeData = self.Mesh.GetPointData() referenceAttributeData = self.ReferenceMesh.GetPointData() calculator.SetAttributeModeToUsePointData() elif self.Method == 'cellarray': attributeData = self.Mesh.GetCellData() referenceAttributeData = self.ReferenceMesh.GetCellData() calculator.SetAttributeModeToUseCellData() if not self.ArrayName: self.PrintError('Error: No ArrayName.') if not referenceAttributeData.GetArray(self.ArrayName): self.PrintError('Error: Invalid ArrayName.') if not attributeData.GetArray(self.ArrayName): self.PrintError('Error: Invalid ArrayName.') referenceArrayName = 'Ref' + self.ArrayName meshPoints = self.Mesh.GetNumberOfPoints() referencePoints = self.ReferenceMesh.GetNumberOfPoints() pointsDifference = meshPoints - referencePoints self.PrintLog("Mesh points: "+ str(meshPoints)) self.PrintLog("Reference Points: " +str(referencePoints)) if abs(pointsDifference) > 0: self.ResultLog = 'Uneven NumberOfPoints' return False refArray = referenceAttributeData.GetArray(self.ArrayName) refArray.SetName(referenceArrayName) attributeData.AddArray(refArray) calculator.SetInput(self.Mesh) calculator.AddScalarVariable('a',self.ArrayName,0) calculator.AddScalarVariable('b',referenceArrayName,0) calculator.SetFunction("a - b") calculator.SetResultArrayName('ResultArray') calculator.Update() self.ResultData = calculator.GetOutput() if self.Method == 'pointarray': resultRange = self.ResultData.GetPointData().GetArray('ResultArray').GetRange() elif self.Method == 'cellarray': resultRange = self.ResultData.GetCellData().GetArray('ResultArray').GetRange() self.PrintLog('Result Range: ' + str(resultRange)) if max([abs(r) for r in resultRange]) < self.Tolerance: return True return False def qualityCompare(self): meshQuality = vtk.vtkMeshQuality() meshQuality.SetInput(self.Mesh) meshQuality.RatioOn() meshQuality.Update() meshQualityOutput = meshQuality.GetOutput() referenceQuality = vtk.vtkMeshQuality() referenceQuality.SetInput(self.ReferenceMesh) referenceQuality.RatioOn() referenceQuality.Update() referenceQualityOutput = referenceQuality.GetOutput() self.PrintLog("Mesh points: "+ str(meshQualityOutput.GetNumberOfPoints())) self.PrintLog("Reference Points: " +str(referenceQualityOutput.GetNumberOfPoints())) meshQualityRange = meshQualityOutput.GetCellData().GetArray("Quality").GetRange() referenceQualityRange = referenceQualityOutput.GetCellData().GetArray("Quality").GetRange() qualityRangeDifference = (meshQualityRange[0] - referenceQualityRange[0],meshQualityRange[1] - referenceQualityRange[1]) self.PrintLog("Mesh Quality Range: "+ str(meshQualityRange)) self.PrintLog("Reference Quality Range: "+ str(referenceQualityRange)) self.PrintLog("Quality Range Difference: "+ str(qualityRangeDifference)) if max(abs(d) for d in qualityRangeDifference) < self.Tolerance: return True return False def Execute(self): if not self.Mesh: self.PrintError('Error: No mesh.') if not self.ReferenceMesh: self.PrintError('Error: No reference.') if not self.Method: self.PrintError('Error: No method.') if self.Method == 'quality': self.Result = self.qualityCompare() elif self.Method in ['pointarray','cellarray']: self.Result = self.arrayCompare() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagewriter.py0000664000175000017500000002605611757446472017304 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagewriter.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.18 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkimagewriter = 'vmtkImageWriter' class vmtkImageWriter(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.UseITKIO = 1 self.ApplyTransform = 0 self.OutputFileName = '' self.OutputRawFileName = '' self.OutputDirectoryName = '' self.PixelRepresentation = '' self.Image = None self.Input = None self.WindowLevel = [1.0, 0.0] self.RasToIjkMatrixCoefficients = [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] self.SetScriptName('vmtkimagewriter') self.SetScriptDoc('write an image to disk') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['Format','f','str',1,'["vtkxml","vtk","meta","tiff","png","pointdata"]','file format'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['UseITKIO','useitk','bool',1,'','use ITKIO mechanism'], ['ApplyTransform','transform','bool',1,'','apply transform on writing - ITKIO only'], ['OutputFileName','ofile','str',1,'','output file name'], ['OutputFileName','o','str',1,'','output file name (deprecated: use -ofile)'], ['OutputRawFileName','rawfile','str',1,'','name of the output raw file - meta image only'], ['OutputDirectoryName','d','str',1,'','output directory name - png, tiff'], ['PixelRepresentation','r','str',1,'["double","float","short"]','output scalar type'], ['WindowLevel','windowlevel','float',2,'','window and level for mapping graylevels to 0-255 before writing - png, tiff'], ['RasToIjkMatrixCoefficients','matrix','float',16] ]) self.SetOutputMembers([]) def WriteVTKImageFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK image file.') writer = vtk.vtkStructuredPointsWriter() writer.SetInput(self.Image) writer.SetFileName(self.OutputFileName) writer.Write() def WriteVTKXMLImageFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK XML image file.') writer = vtk.vtkXMLImageDataWriter() writer.SetInput(self.Image) writer.SetFileName(self.OutputFileName) writer.Write() def WriteMetaImageFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing meta image file.') writer = vtk.vtkMetaImageWriter() writer.SetInput(self.Image) writer.SetFileName(self.OutputFileName) if (self.OutputRawFileName != ''): writer.SetRAWFileName(self.OutputRawFileName) writer.Write() def WritePNGImageFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PNG image file.') outputImage = self.Image if self.Image.GetScalarTypeAsString() != 'unsigned char': shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(self.Image) if self.WindowLevel[0] == 0.0: scalarRange = self.Image.GetScalarRange() shiftScale.SetShift(-scalarRange[0]) shiftScale.SetScale(255.0/(scalarRange[1]-scalarRange[0])) else: shiftScale.SetShift(-(self.WindowLevel[1]-self.WindowLevel[0]/2.0)) shiftScale.SetScale(255.0/self.WindowLevel[0]) shiftScale.SetOutputScalarTypeToUnsignedChar() shiftScale.ClampOverflowOn() shiftScale.Update() outputImage = shiftScale.GetOutput() writer = vtk.vtkPNGWriter() writer.SetInput(outputImage) if self.Image.GetDimensions()[2] == 1: writer.SetFileName(self.OutputFileName) else: writer.SetFilePrefix(self.OutputFileName) writer.SetFilePattern("%s%04d.png") writer.Write() def WriteTIFFImageFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing TIFF image file.') outputImage = self.Image if self.Image.GetScalarTypeAsString() != 'unsigned char': shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(self.Image) if self.WindowLevel[0] == 0.0: scalarRange = self.Image.GetScalarRange() shiftScale.SetShift(-scalarRange[0]) shiftScale.SetScale(255.0/(scalarRange[1]-scalarRange[0])) else: shiftScale.SetShift(-(self.WindowLevel[1]-self.WindowLevel[0]/2.0)) shiftScale.SetScale(255.0/self.WindowLevel[0]) shiftScale.SetOutputScalarTypeToUnsignedChar() shiftScale.ClampOverflowOn() shiftScale.Update() outputImage = shiftScale.GetOutput() writer = vtk.vtkTIFFWriter() writer.SetInput(outputImage) if self.Image.GetDimensions()[2] == 1: writer.SetFileName(self.OutputFileName) else: writer.SetFilePrefix(self.OutputFileName) writer.SetFilePattern("%s%04d.tif") writer.Write() def WritePointDataImageFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PointData file.') f=open(self.OutputFileName, 'w') line = "X Y Z" arrayNames = [] if self.Image.GetPointData().GetScalars().GetName() == None: self.Image.GetPointData().GetScalars().SetName('__Scalars') for i in range(self.Image.GetPointData().GetNumberOfArrays()): array = self.Image.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if arrayName[-1]=='_': continue arrayNames.append(arrayName) if array.GetNumberOfComponents() == 1: line = line + ' ' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ' ' + arrayName + str(j) line = line + '\n' f.write(line) for i in range(self.Image.GetNumberOfPoints()): point = self.Image.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Image.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) def WriteITKIO(self): if self.OutputFileName == '': self.PrintError('Error: no OutputFileName.') writer = vtkvmtk.vtkvmtkITKImageWriter() writer.SetInput(self.Image) writer.SetFileName(self.OutputFileName) writer.SetUseCompression(1) if self.ApplyTransform and self.RasToIjkMatrixCoefficients: matrix = vtk.vtkMatrix4x4() matrix.DeepCopy(self.RasToIjkMatrixCoefficients) writer.SetRasToIJKMatrix(matrix) writer.Write() def Execute(self): if self.Image == None: if self.Input == None: self.PrintError('Error: no Image.') self.Image = self.Input extensionFormats = {'vti':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'mhd':'meta', 'mha':'meta', 'tif':'tiff', 'png':'png', 'dat':'pointdata'} if self.OutputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.OutputFileName = tkFileDialog.asksaveasfilename(title="Output image",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.OutputFileName) if not self.OutputFileName: self.PrintError('Error: no OutputFileName.') if self.OutputDirectoryName == 'BROWSER': import tkFileDialog initialDir = pypes.pypeScript.lastVisitedPath self.OutputDirectoryName = tkFileDialog.askdirectory(title="Output directory",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = self.OutputDirectoryName if not self.OutputDirectoryName: self.PrintError('Error: no OutputDirectoryName.') if self.GuessFormat and self.OutputFileName and not self.Format: import os.path extension = os.path.splitext(self.OutputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if self.PixelRepresentation != '': cast = vtk.vtkImageCast() cast.SetInput(self.Image) if self.PixelRepresentation == 'double': cast.SetOutputScalarTypeToDouble() elif self.PixelRepresentation == 'float': cast.SetOutputScalarTypeToFloat() elif self.PixelRepresentation == 'short': cast.SetOutputScalarTypeToShort() else: self.PrintError('Error: unsupported pixel representation '+ self.PixelRepresentation + '.') cast.Update() self.Image = cast.GetOutput() if self.UseITKIO and self.Format not in ['vtkxml','vtk','tiff','png','dat']: self.WriteITKIO() else: if (self.Format == 'vtkxml'): self.WriteVTKXMLImageFile() elif (self.Format == 'vtk'): self.WriteVTKImageFile() elif (self.Format == 'meta'): self.WriteMetaImageFile() elif (self.Format == 'png'): self.WritePNGImageFile() elif (self.Format == 'tiff'): self.WriteTIFFImageFile() elif (self.Format == 'pointdata'): self.WritePointDataImageFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlineresampling.py0000664000175000017500000000340511757446472021170 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtklineresampling.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vmtklineresampling vmtkcenterlineresampling = 'vmtkCenterlineResampling' class vmtkCenterlineResampling(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.Length = 0.0; self.SetScriptName('vmtkcenterlineresampling') self.SetScriptDoc('resample input centerlines with a spline filter') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['Length','length','float',1,'(0.0,)','length of the resampling interval'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') lineResampling = vmtklineresampling.vmtkLineResampling() lineResampling.Surface = self.Centerlines lineResampling.Length = self.Length lineResampling.Execute() self.Centerlines = lineResampling.Surface if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinegeometry.py0000664000175000017500000001125011757446472020657 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinegeometry.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:52:56 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkcenterlinegeometry = 'vmtkCenterlineGeometry' class vmtkCenterlineGeometry(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.LengthArrayName = 'Length' self.CurvatureArrayName = 'Curvature' self.TorsionArrayName = 'Torsion' self.TortuosityArrayName = 'Tortuosity' self.FrenetTangentArrayName = 'FrenetTangent' self.FrenetNormalArrayName = 'FrenetNormal' self.FrenetBinormalArrayName = 'FrenetBinormal' self.LineSmoothing = 0 self.OutputSmoothedLines = 0 self.NumberOfSmoothingIterations = 100 self.SmoothingFactor = 0.1 self.SetScriptName('vmtkcenterlinegeometry') self.SetScriptDoc('compute the local geometry of centerlines in terms of curvature and torsion') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['LengthArrayName','lengtharray','str',1,'','name of the array where length values have to be stored'], ['CurvatureArrayName','curvaturearray','str',1,'','name of the array where curvature values have to be stored'], ['TorsionArrayName','torsionarray','str',1,'','name of the array where torsion values have to be stored'], ['TortuosityArrayName','tortuosityarray','str',1,'','name of the array where tortuosity values have to be stored'], ['FrenetTangentArrayName','frenettangentarray','str',1,'','name of the array where tangent vectors of the Frenet reference system have to be stored'], ['FrenetNormalArrayName','frenetnormalarray','str',1,'','name of the array where normal vectors of the Frenet reference system have to be stored'], ['FrenetBinormalArrayName','frenetbinormalarray','str',1,'','name of the array where binormal vectors of the Frenet reference system have to be stored'], ['LineSmoothing','smoothing','bool',1,''], ['OutputSmoothedLines','outputsmoothed','bool',1,''], ['NumberOfSmoothingIterations','iterations','int',1,'(0,)'], ['SmoothingFactor','factor','float',1,'(0.0,)'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'], ['LengthArrayName','lengtharray','str',1,'','name of the array where length values are stored'], ['CurvatureArrayName','curvaturearray','str',1,'','name of the array where curvature values are stored'], ['TorsionArrayName','torsionarray','str',1,'','name of the array where torsion values are stored'], ['TortuosityArrayName','tortuosityarray','str',1,'','name of the array where tortuosity values are stored'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') centerlineGeometry = vtkvmtk.vtkvmtkCenterlineGeometry() centerlineGeometry.SetInput(self.Centerlines) centerlineGeometry.SetLengthArrayName(self.LengthArrayName) centerlineGeometry.SetCurvatureArrayName(self.CurvatureArrayName) centerlineGeometry.SetTorsionArrayName(self.TorsionArrayName) centerlineGeometry.SetTortuosityArrayName(self.TortuosityArrayName) centerlineGeometry.SetFrenetTangentArrayName(self.FrenetTangentArrayName) centerlineGeometry.SetFrenetNormalArrayName(self.FrenetNormalArrayName) centerlineGeometry.SetFrenetBinormalArrayName(self.FrenetBinormalArrayName) centerlineGeometry.SetLineSmoothing(self.LineSmoothing) centerlineGeometry.SetOutputSmoothedLines(self.OutputSmoothedLines) centerlineGeometry.SetNumberOfSmoothingIterations(self.NumberOfSmoothingIterations) centerlineGeometry.SetSmoothingFactor(self.SmoothingFactor) centerlineGeometry.Update() self.Centerlines = centerlineGeometry.GetOutput() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbranchgeometry.py0000664000175000017500000001142311757446472017766 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchgeometry.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkbranchgeometry = 'vmtkBranchGeometry' class vmtkBranchGeometry(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.GeometryData = None self.RadiusArrayName = '' self.GroupIdsArrayName = '' self.BlankingArrayName = '' self.LengthArrayName = 'Length' self.CurvatureArrayName = 'Curvature' self.TorsionArrayName = 'Torsion' self.TortuosityArrayName = 'Tortuosity' self.LineSmoothing = 0 self.NumberOfSmoothingIterations = 100 self.SmoothingFactor = 0.1 self.SetScriptName('vmtkbranchgeometry') self.SetScriptDoc('compute geometric parameters for each branch of a tree. The script takes in input the centerlines already split into branches.') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input split centerlines','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where centerline radius values are stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['BlankingArrayName','blankingarray','str',1,'','name of the array where blanking information about branches is stored'], ['LengthArrayName','lengtharray','str',1,'','name of the array where the average length of each branch has to be stored'], ['CurvatureArrayName','curvaturearray','str',1,'','name of the array where the average curvature of each branch has to be stored'], ['TorsionArrayName','torsionarray','str',1,'','name of the array where the average torsion of each branch has to be stored'], ['TortuosityArrayName','tortuosityarray','str',1,'','name of the array where the average tortuosity of each branch, defined as the length of a line divided by the distance of its endpoints, has to be stored'], ['LineSmoothing','smoothing','bool',1,''], ['NumberOfSmoothingIterations','iterations','int',1,'(0,)'], ['SmoothingFactor','factor','float',1,'(0.0,)'] ]) self.SetOutputMembers([ ['GeometryData','o','vtkPolyData',1,'','the output data set','vmtksurfacewriter'], ['LengthArrayName','lengtharray','str',1,'','name of the array where the average length of each branch is stored'], ['CurvatureArrayName','curvaturearray','str',1,'','name of the array where the average curvature of each branch is stored'], ['TorsionArrayName','torsionarray','str',1,'','name of the array where the average torsion of each branch is stored'], ['TortuosityArrayName','tortuosityarray','str',1,'','name of the array where the average tortuosity of each branch, defined as the length of a line divided by the distance of its endpoints minus one (L/D - 1), is stored'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') centerlineBranchGeometry = vtkvmtk.vtkvmtkCenterlineBranchGeometry() centerlineBranchGeometry.SetInput(self.Centerlines) centerlineBranchGeometry.SetRadiusArrayName(self.RadiusArrayName) centerlineBranchGeometry.SetGroupIdsArrayName(self.GroupIdsArrayName) centerlineBranchGeometry.SetBlankingArrayName(self.BlankingArrayName) centerlineBranchGeometry.SetLengthArrayName(self.LengthArrayName) centerlineBranchGeometry.SetCurvatureArrayName(self.CurvatureArrayName) centerlineBranchGeometry.SetTorsionArrayName(self.TorsionArrayName) centerlineBranchGeometry.SetTortuosityArrayName(self.TortuosityArrayName) centerlineBranchGeometry.SetLineSmoothing(self.LineSmoothing) centerlineBranchGeometry.SetNumberOfSmoothingIterations(self.NumberOfSmoothingIterations) centerlineBranchGeometry.SetSmoothingFactor(self.SmoothingFactor) centerlineBranchGeometry.Update() self.GeometryData = centerlineBranchGeometry.GetOutput() if self.GeometryData.GetSource(): self.GeometryData.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkboundarylayer.py0000664000175000017500000001074011757446472017636 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkboundarylayer.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkboundarylayer = 'vmtkBoundaryLayer' class vmtkBoundaryLayer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.InnerSurfaceMesh = None self.WarpVectorsArrayName = '' self.ThicknessArrayName = '' self.Thickness = 1.0 self.ThicknessRatio = 0.1 self.MaximumThickness = 1E10 self.NumberOfSubLayers = 1 self.SubLayerRatio = 1.0 self.UseWarpVectorMagnitudeAsThickness = 0; self.ConstantThickness = 0; self.IncludeSurfaceCells = 1 self.NegateWarpVectors = 0 self.SetScriptName('vmtkboundarylayer') self.SetScriptDoc('create a prismatic boundary layer from a surface mesh and a set of vectors defined on the nodes') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['WarpVectorsArrayName','warpvectorsarray','str',1,'','name of the array where warp vectors are stored'], ['ThicknessArrayName','thicknessarray','str',1,'','name of the array where scalars defining boundary layer thickness are stored'], ['Thickness','thickness','float',1,'','value of constant boundary layer thickness'], ['ThicknessRatio','thicknessratio','float',1,'(0.0,)','multiplying factor for boundary layer thickness'], ['MaximumThickness','maximumthickness','float',1,'','maximum allowed value for boundary layer thickness'], ['NumberOfSubLayers','numberofsublayers','int',1,'(0,)','number of sublayers which the boundary layer has to be made of'], ['SubLayerRatio','sublayerratio','float',1,'(0.0,)','ratio between the thickness of two successive boundary layers'], ['UseWarpVectorMagnitudeAsThickness','warpvectormagnitudeasthickness','bool',1,'','compute boundary layer thickness as the norm of warp vectors'], ['ConstantThickness','constantthickness','bool',1,'','toggle constant boundary layer thickness'], ['IncludeSurfaceCells','includesurfacecells','bool',1,'','include surface cells in output mesh'], ['NegateWarpVectors','negatewarpvectors','bool',1,'','flip the orientation of warp vectors'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['InnerSurfaceMesh','oinner','vtkUnstructuredGrid',1,'','the output inner surface mesh','vmtkmeshwriter'] ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') boundaryLayerGenerator = vtkvmtk.vtkvmtkBoundaryLayerGenerator() boundaryLayerGenerator.SetInput(self.Mesh) boundaryLayerGenerator.SetWarpVectorsArrayName(self.WarpVectorsArrayName) boundaryLayerGenerator.SetLayerThickness(self.Thickness) boundaryLayerGenerator.SetLayerThicknessArrayName(self.ThicknessArrayName) boundaryLayerGenerator.SetLayerThicknessRatio(self.ThicknessRatio) boundaryLayerGenerator.SetMaximumLayerThickness(self.MaximumThickness) boundaryLayerGenerator.SetNumberOfSubLayers(self.NumberOfSubLayers) boundaryLayerGenerator.SetSubLayerRatio(self.SubLayerRatio) boundaryLayerGenerator.SetConstantThickness(self.ConstantThickness) boundaryLayerGenerator.SetUseWarpVectorMagnitudeAsThickness(self.UseWarpVectorMagnitudeAsThickness) boundaryLayerGenerator.SetIncludeSurfaceCells(self.IncludeSurfaceCells) boundaryLayerGenerator.SetNegateWarpVectors(self.NegateWarpVectors) boundaryLayerGenerator.Update() self.Mesh = boundaryLayerGenerator.GetOutput() self.InnerSurfaceMesh = boundaryLayerGenerator.GetInnerSurface() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfaceappend.py0000664000175000017500000000335311757446472017600 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceappend.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfaceappend = 'vmtkSurfaceAppend' class vmtkSurfaceAppend(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Surface2 = None self.SetScriptName('vmtksurfaceappend') self.SetScriptDoc('scale a surface by an isotropic factor') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Surface2','i2','vtkPolyData',1,'','the second input surface','vmtksurfacereader'], ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if (self.Surface == None): self.PrintError('Error: no Surface.') appendFilter = vtk.vtkAppendPolyData() appendFilter.AddInput(self.Surface) appendFilter.AddInput(self.Surface2) appendFilter.Update() self.Surface = appendFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfmesh.py0000664000175000017500000000336311757446472016615 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfmesh.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfmesh = 'vmtkSurfMesh' class vmtkSurfMesh(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.NodeSpacing = 1.0 self.SetScriptName('vmtksurfmesh') self.SetScriptDoc('wrapper around surfmesh surface mesh generator by Gordan Stuhne') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['NodeSpacing','nodespacing','float',1,'(0.0,)','desired node spacing'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') surfmesh = vtkvmtk.vtkvmtkSurfMeshWrapper() surfmesh.SetInput(self.Surface) surfmesh.SetNodeSpacing(self.NodeSpacing) surfmesh.Update() self.Surface = surfmesh.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinemerge.py0000664000175000017500000000611311757446472020125 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinemerge.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkcenterlinemerge = 'vmtkCenterlineMerge' class vmtkCenterlineMerge(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.RadiusArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.TractIdsArrayName = '' self.BlankingArrayName = '' self.Length = 0.0 self.MergeBlanked = 1 self.SetScriptName('vmtkcenterlinemerge') self.SetScriptDoc('merge centerline tracts belonging to the same groups') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where centerline radius is stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['CenterlineIdsArrayName','centerlineidsarray','str',1,'','name of the array where centerline ids are stored'], ['TractIdsArrayName','tractidsarray','str',1,'','name of the array where centerline tract ids are stored'], ['BlankingArrayName','blankingarray','str',1,'','name of the array where centerline blanking information about branches is stored'], ['Length','length','float',1,'(0.0,)','length of the resampling interval'], ['MergeBlanked','mergeblanked','bool',1,'','toggle generation of segments for blanked groups'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') mergeCenterlines = vtkvmtk.vtkvmtkMergeCenterlines() mergeCenterlines.SetInput(self.Centerlines) mergeCenterlines.SetRadiusArrayName(self.RadiusArrayName) mergeCenterlines.SetGroupIdsArrayName(self.GroupIdsArrayName) mergeCenterlines.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) mergeCenterlines.SetTractIdsArrayName(self.TractIdsArrayName) mergeCenterlines.SetBlankingArrayName(self.BlankingArrayName) mergeCenterlines.SetResamplingStepLength(self.Length) mergeCenterlines.SetMergeBlanked(self.MergeBlanked) mergeCenterlines.Update() self.Centerlines = mergeCenterlines.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacetriangle.py0000664000175000017500000000333611757446472020137 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacetriangle.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import vtk import pypes vmtksurfacetriangle = 'vmtkSurfaceTriangle' class vmtkSurfaceTriangle(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.SetScriptName('vmtksurfacetriangle') self.SetScriptDoc('convert all cells in a surface to linear triangles.') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(self.Surface) cleaner.Update() triangleFilter = vtk.vtkTriangleFilter() triangleFilter.SetInput(cleaner.GetOutput()) triangleFilter.Update() self.Surface = triangleFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkendpointextractor.py0000664000175000017500000000610011757446472020525 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkendpointextractor.py,v $ ## Language: Python ## Date: $Date: 2006/03/01 11:54:16 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkendpointextractor = 'vmtkEndpointExtractor' class vmtkEndpointExtractor(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.RadiusArrayName = '' self.GroupIdsArrayName = 'GroupIds' self.CenterlineIdsArrayName = 'CenterlineIds' self.BlankingArrayName = 'Blanking' self.TractIdsArrayName = 'TractIds' self.NumberOfEndpointSpheres = 2 self.NumberOfGapSpheres = 1 self.SetScriptName('vmtkendpointextractor') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','','vmtksurfacereader'], ['GroupIdsArrayName','groupidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['RadiusArrayName','radiusarray','str',1], ['BlankingArrayName','blankingarray','str',1], ['NumberOfEndpointSpheres','numberofendpointspheres','int',1,'(0.0,)'], ['NumberOfGapSpheres','numberofgapspheres','int',1,'(0.0,)'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['GroupIdsArrayName','groupidsarray','str',1], ['TractIdsArrayName','tractidsarray','str',1], ['CenterlineIdsArrayName','centerlineidsarray','str',1], ['BlankingArrayName','blankingarray','str',1] ]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') endpointExtractor = vtkvmtk.vtkvmtkCenterlineEndpointExtractor() endpointExtractor.SetInput(self.Centerlines) endpointExtractor.SetRadiusArrayName(self.RadiusArrayName) endpointExtractor.SetGroupIdsArrayName(self.GroupIdsArrayName) endpointExtractor.SetTractIdsArrayName(self.TractIdsArrayName) endpointExtractor.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) endpointExtractor.SetBlankingArrayName(self.BlankingArrayName) endpointExtractor.SetNumberOfEndpointSpheres(self.NumberOfEndpointSpheres) endpointExtractor.SetNumberOfGapSpheres(self.NumberOfGapSpheres) endpointExtractor.Update() self.Centerlines = endpointExtractor.GetOutput() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacesmoothing.py0000664000175000017500000000665411757446472020347 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacesmoothing.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vmtkscripts vmtksurfacesmoothing = 'vmtkSurfaceSmoothing' class vmtkSurfaceSmoothing(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.NumberOfIterations = 1 self.PassBand = 1.0 self.RelaxationFactor = 0.01 self.BoundarySmoothing = 1 self.NormalizeCoordinates = 1 self.Method = 'taubin' self.SetScriptName('vmtksurfacesmoothing') self.SetScriptDoc('smooth a surface using Taubin\'s algorithm') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['NumberOfIterations','iterations','int',1,'(0,)','number of iterations (e.g. 25)'], ['Method','method','str',1,'["taubin","laplace"]','smoothing method'], ['PassBand','passband','float',1,'','pass band (e.g. 0.1) - taubin only'], ['RelaxationFactor','relaxation','float',1,'(0.0,)','relaxation factor (e.g. 0.01) - laplace only'], ['BoundarySmoothing','boundarysmoothing','bool',1,'','toggle allow change of position of boundary points'], ['NormalizeCoordinates','normalize','bool',1,'','toggle normalization of coordinates prior to filtering to minimize spurious translation effects - taubin only'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') smoothingFilter = None if self.Method is 'taubin': smoothingFilter = vtk.vtkWindowedSincPolyDataFilter() smoothingFilter.SetInput(self.Surface) smoothingFilter.SetNumberOfIterations(self.NumberOfIterations) smoothingFilter.SetPassBand(self.PassBand) smoothingFilter.SetBoundarySmoothing(self.BoundarySmoothing) smoothingFilter.SetNormalizeCoordinates(self.NormalizeCoordinates) smoothingFilter.Update() elif self.Method is 'laplace': smoothingFilter = vtk.vtkSmoothPolyDataFilter() smoothingFilter.SetInput(self.Surface) smoothingFilter.SetNumberOfIterations(self.NumberOfIterations) smoothingFilter.SetRelaxationFactor(self.RelaxationFactor) smoothingFilter.Update() else: self.PrintError('Error: smoothing method not supported.') self.Surface = smoothingFilter.GetOutput() normals = vmtkscripts.vmtkSurfaceNormals() normals.Surface = self.Surface normals.Execute() self.Surface = normals.Surface if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshlambda2.py0000664000175000017500000000452011757446472017134 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshlambda2.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtkvmtk import vtk import sys import pypes vmtkmeshlambda2 = 'vmtkMeshLambda2' class vmtkMeshLambda2(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.VelocityArrayName = None self.Lambda2ArrayName = 'Lambda2' self.ConvergenceTolerance = 1E-6 self.QuadratureOrder = 3 self.SetScriptName('vmtkmeshlambda2') self.SetScriptDoc('compute lambda2 from a velocity field') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['VelocityArrayName','velocityarray','str',1,'',''], ['Lambda2ArrayName','lambda2array','str',1,'',''], ['ConvergenceTolerance','tolerance','float',1,'',''], ['QuadratureOrder','quadratureorder','int',1,'',''] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') lambda2Filter = vtkvmtk.vtkvmtkMeshLambda2() lambda2Filter.SetInput(self.Mesh) lambda2Filter.SetVelocityArrayName(self.VelocityArrayName) lambda2Filter.SetLambda2ArrayName(self.Lambda2ArrayName) lambda2Filter.SetConvergenceTolerance(self.ConvergenceTolerance) lambda2Filter.SetQuadratureOrder(self.QuadratureOrder) lambda2Filter.ComputeIndividualPartialDerivativesOn() lambda2Filter.ForceBoundaryToNegativeOn() lambda2Filter.Update() self.Mesh = lambda2Filter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshlinearize.py0000664000175000017500000000340511757446472017615 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshlinearize.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkmeshlinearize = 'vmtkMeshLinearize' class vmtkMeshLinearize(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.CleanOutput = 1 self.SetScriptName('vmtkmeshlinearize') self.SetScriptDoc('convert the elements of a mesh to linear') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['CleanOutput','cleanoutput','bool',1,'','toggle cleaning the unused points'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter']]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') linearizeFilter = vtkvmtk.vtkvmtkLinearizeMeshFilter() linearizeFilter.SetInput(self.Mesh) linearizeFilter.SetCleanOutput(self.CleanOutput) linearizeFilter.Update() self.Mesh = linearizeFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfaceconnectivity.py0000664000175000017500000000533711757446472021053 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceconnectivity.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfaceconnectivity = 'vmtkSurfaceConnectivity' class vmtkSurfaceConnectivity(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.GroupId = -1 self.GroupIdsArrayName = '' self.CleanOutput = 0 self.SetScriptName('vmtksurfaceconnectivity') self.SetScriptDoc('extract the largest connected region or the scalar-connected region from a surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['CleanOutput','cleanoutput','bool',1,'','clean the unused points in the output'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array containing the connectivity scalar'], ['GroupId','groupid','int',1,'','value of the connectivity scalar'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if (self.GroupId != -1) & (self.GroupIdsArrayName!=''): self.Surface.GetPointData().SetActiveScalars(self.GroupIdsArrayName) connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInput(self.Surface) connectivityFilter.ColorRegionsOff() connectivityFilter.SetExtractionModeToLargestRegion() if self.GroupId != -1: connectivityFilter.ScalarConnectivityOn() scalarRange = [self.GroupId,self .GroupId] connectivityFilter.SetScalarRange(scalarRange) connectivityFilter.Update() self.Surface = connectivityFilter.GetOutput() if self.CleanOutput == 1: cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(connectivityFilter.GetOutput()) cleaner.Update() self.Surface = cleaner.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacecapper.py0000664000175000017500000001766511757446472017616 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacecapper.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import vtk import vtkvmtk import pypes vmtksurfacecapper = 'vmtkSurfaceCapper' class vmtkSurfaceCapper(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.TriangleOutput = 1 self.CellEntityIdsArrayName = 'CellEntityIds' self.CellEntityIdOffset = 1 self.Interactive = 1 self.Method = 'simple' self.ConstraintFactor = 1.0 self.NumberOfRings = 8 self.vmtkRenderer = None self.OwnRenderer = 0 self.SetScriptName('vmtksurfacecapper') self.SetScriptDoc('add caps to the holes of a surface, assigning an id to each cap for easy specification of boundary conditions ("simple" method only).') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Method','method','str',1,'["simple","centerpoint","smooth","annular"]','capping method'], ['TriangleOutput','triangle','bool',1,'','toggle triangulation of the output'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where the id of the caps have to be stored'], ['CellEntityIdOffset','entityidoffset','int',1,'(0,)','offset for entity ids ("simple" method only")'], ['ConstraintFactor','constraint','float',1,'','amount of influence of the shape of the surface near the boundary on the shape of the cap ("smooth" method only)'], ['NumberOfRings','rings','int',1,'(0,)','number of rings composing the cap ("smooth" method only)'], ['Interactive','interactive','bool',1], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where the id of the caps are stored'] ]) def LabelValidator(self,text): import string if not text: return 0 if not text.split(): return 0 for char in text: if char not in string.digits + " ": return 0 return 1 def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') # cleaner = vtk.vtkCleanPolyData() # cleaner.SetInput(self.Surface) # cleaner.Update() # # triangleFilter = vtk.vtkTriangleFilter() # triangleFilter.SetInput(cleaner.GetOutput()) # triangleFilter.Update() # # self.Surface = triangleFilter.GetOutput() boundaryIds = vtk.vtkIdList() if self.Interactive: if not self.vmtkRenderer: import vmtkrenderer self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) boundaryExtractor = vtkvmtk.vtkvmtkPolyDataBoundaryExtractor() boundaryExtractor.SetInput(self.Surface) boundaryExtractor.Update() boundaries = boundaryExtractor.GetOutput() numberOfBoundaries = boundaries.GetNumberOfCells() seedPoints = vtk.vtkPoints() for i in range(numberOfBoundaries): barycenter = [0.0, 0.0, 0.0] vtkvmtk.vtkvmtkBoundaryReferenceSystems.ComputeBoundaryBarycenter(boundaries.GetCell(i).GetPoints(),barycenter) seedPoints.InsertNextPoint(barycenter) seedPolyData = vtk.vtkPolyData() seedPolyData.SetPoints(seedPoints) seedPolyData.Update() labelsMapper = vtk.vtkLabeledDataMapper(); labelsMapper.SetInput(seedPolyData) labelsMapper.SetLabelModeToLabelIds() labelsActor = vtk.vtkActor2D() labelsActor.SetMapper(labelsMapper) self.vmtkRenderer.Renderer.AddActor(labelsActor) surfaceMapper = vtk.vtkPolyDataMapper() surfaceMapper.SetInput(self.Surface) surfaceMapper.ScalarVisibilityOff() surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(surfaceMapper) surfaceActor.GetProperty().SetOpacity(0.25) self.vmtkRenderer.Renderer.AddActor(surfaceActor) #self.vmtkRenderer.Render() #self.vmtkRenderer.Renderer.RemoveActor(labelsActor) #self.vmtkRenderer.Renderer.RemoveActor(surfaceActor) ok = False while not ok: labelString = self.InputText("Please input boundary ids: ",self.LabelValidator) labels = [int(label) for label in labelString.split()] ok = True for label in labels: if label not in range(numberOfBoundaries): ok = False for label in labels: boundaryIds.InsertNextId(label) if self.Method == 'simple': capper = vtkvmtk.vtkvmtkSimpleCapPolyData() capper.SetInput(self.Surface) if self.Interactive: capper.SetBoundaryIds(boundaryIds) capper.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) capper.SetCellEntityIdOffset(self.CellEntityIdOffset) capper.Update() self.Surface = capper.GetOutput() elif self.Method == 'centerpoint': capper = vtkvmtk.vtkvmtkCapPolyData() capper.SetInput(self.Surface) if self.Interactive: capper.SetBoundaryIds(boundaryIds) capper.SetDisplacement(0.0) capper.SetInPlaneDisplacement(0.0) capper.Update() self.Surface = capper.GetOutput() elif self.Method == 'smooth': triangle = vtk.vtkTriangleFilter() triangle.SetInput(self.Surface) triangle.PassLinesOff() triangle.PassVertsOff() triangle.Update() capper = vtkvmtk.vtkvmtkSmoothCapPolyData() capper.SetInput(triangle.GetOutput()) capper.SetConstraintFactor(self.ConstraintFactor) capper.SetNumberOfRings(self.NumberOfRings) if self.Interactive: capper.SetBoundaryIds(boundaryIds) capper.Update() self.Surface = capper.GetOutput() elif self.Method == 'annular': capper = vtkvmtk.vtkvmtkAnnularCapPolyData() capper.SetInput(self.Surface) capper.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) capper.SetCellEntityIdOffset(self.CellEntityIdOffset) capper.Update() self.Surface = capper.GetOutput() if self.TriangleOutput == 1: triangle = vtk.vtkTriangleFilter() triangle.SetInput(self.Surface) triangle.PassLinesOff() triangle.PassVertsOff() triangle.Update() self.Surface = triangle.GetOutput() normals = vtk.vtkPolyDataNormals() normals.SetInput(self.Surface) normals.AutoOrientNormalsOn() normals.SplittingOff() normals.ConsistencyOn() normals.Update() self.Surface = normals.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlineviewer.py0000664000175000017500000001105711757446472020332 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlineviewer.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.3 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import vmtkrenderer import pypes vmtkcenterlineviewer = 'vmtkCenterlineViewer' class vmtkCenterlineViewer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.PointDataArrayName = '' self.CellDataArrayName = '' self.Display = 1 self.Legend = 1 self.vmtkRenderer = None self.OwnRenderer = 0 self.SetScriptName('vmtkcenterlineviewer') self.SetScriptDoc('') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['PointDataArrayName','pointarray','str',1,''], ['CellDataArrayName','cellarray','str',1,''], ['Legend','legend','bool',1,''], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer']]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter']]) def Execute(self): if not self.Centerlines: self.PrintError('Error: No input centerlines.') return if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if self.CellDataArrayName: cellCenters = vtk.vtkCellCenters() cellCenters.SetInput(self.Centerlines) cellCenters.Update() cellCenters.GetOutput().GetPointData().SetActiveScalars(self.CellDataArrayName) labelsMapper = vtk.vtkLabeledDataMapper(); labelsMapper.SetInput(cellCenters.GetOutput()) labelsMapper.SetLabelModeToLabelScalars() labelsActor = vtk.vtkActor2D() labelsActor.SetMapper(labelsMapper) self.vmtkRenderer.Renderer.AddActor(labelsActor) centerlineMapper = vtk.vtkPolyDataMapper() centerlineMapper.SetInput(self.Centerlines) if self.CellDataArrayName and not self.PointDataArrayName: centerlineMapper.ScalarVisibilityOn() centerlineMapper.SetScalarModeToUseCellData() self.Centerlines.GetCellData().SetActiveScalars(self.CellDataArrayName) centerlineMapper.SetScalarRange(self.Centerlines.GetCellData().GetScalars().GetRange(0)) elif self.PointDataArrayName: centerlineMapper.ScalarVisibilityOn() centerlineMapper.SetScalarModeToUsePointData() self.Centerlines.GetPointData().SetActiveScalars(self.PointDataArrayName) centerlineMapper.SetScalarRange(self.Centerlines.GetPointData().GetScalars().GetRange(0)) else: centerlineMapper.ScalarVisibilityOff() centerlineActor = vtk.vtkActor() centerlineActor.SetMapper(centerlineMapper) self.vmtkRenderer.Renderer.AddActor(centerlineActor) scalarBarActor = None if self.Legend and centerlineActor and self.PointDataArrayName: scalarBarActor = vtk.vtkScalarBarActor() scalarBarActor.SetLookupTable(centerlineActor.GetMapper().GetLookupTable()) scalarBarActor.GetLabelTextProperty().ItalicOff() scalarBarActor.GetLabelTextProperty().BoldOff() scalarBarActor.GetLabelTextProperty().ShadowOff() scalarBarActor.SetLabelFormat('%.2f') scalarBarActor.SetTitle(self.PointDataArrayName) self.vmtkRenderer.Renderer.AddActor(scalarBarActor) if self.Display: self.vmtkRenderer.Render() if self.OwnRenderer: self.vmtkRenderer.Deallocate() # if self.CellDataArrayName: # self.vmtkRenderer.Renderer.RemoveActor(labelsActor) # # if self.Legend and centerlineActor: # self.vmtkRenderer.Renderer.RemoveActor(scalarBarActor) # # self.vmtkRenderer.Renderer.RemoveActor(centerlineActor) if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkrenderer.py0000664000175000017500000003074111757446472016567 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkrenderer.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import os import pypes import vtkvmtk vmtkrenderer = 'vmtkRenderer' class vmtkRendererInputStream(object): def __init__(self,renderer): self.renderer = renderer def readline(self): self.renderer.EnterTextInputMode() return self.renderer.CurrentTextInput def prompt(self,text): self.renderer.TextInputQuery = text self.renderer.CurrentTextInput = None self.renderer.UpdateTextInput() class vmtkRenderer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.vmtkRenderer = self self.Renderer = None self.RenderWindow = None self.RenderWindowInteractor = None self.Camera = None self.WindowSize = [800, 600] self.Background = [0.1, 0.1, 0.2] self.PointSmoothing = 1 self.LineSmoothing = 1 self.PolygonSmoothing = 0 self.TextInputMode = 0 self.ExitAfterTextInputMode = True self.ExitTextInputCallback = None self.TextInputActor = None self.TextInputQuery = None self.CurrentTextInput = None self.InputPosition = [0.25, 0.1] self.TextActor = None self.Position = [0.001, 0.05] self.KeyBindings = {} self.ScreenshotMagnification = 4 self.UseRendererInputStream = True self.SetScriptName('vmtkrenderer') self.SetScriptDoc('renderer used to make several viewers use the same rendering window') self.SetInputMembers([ ['WindowSize','size','int',2,'','size of the rendering window'], ['PointSmoothing','pointsmoothing','bool',1,'','toggle rendering smooth points'], ['LineSmoothing','linesmoothing','bool',1,'','toggle rendering smooth lines'], ['PolygonSmoothing','polygonsmoothing','bool',1,'','toggle rendering smooth polygons'], ['Background','background','float',3,'','background color of the rendering window'], ['ScreenshotMagnification','magnification','int',1,'','magnification to apply to the rendering window when taking a screenshot']]) self.SetOutputMembers([ ['vmtkRenderer','o','vmtkRenderer',1,'','the renderer']]) def ResetCameraCallback(self,obj): self.Renderer.ResetCamera() def ScreenshotCallback(self, obj): filePrefix = 'vmtk-screenshot' fileNumber = 0 fileName = "%s-%d.png" % (filePrefix,fileNumber) homeDir = os.getenv("HOME") existingFiles = os.listdir(homeDir) while fileName in existingFiles: fileNumber += 1 fileName = "%s-%d.png" % (filePrefix,fileNumber) self.PrintLog('Saving screenshot to ' + fileName) windowToImage = vtk.vtkWindowToImageFilter() windowToImage.SetInput(self.RenderWindow) windowToImage.SetMagnification(self.ScreenshotMagnification) windowToImage.Update() self.RenderWindow.Render() writer = vtk.vtkPNGWriter() writer.SetInput(windowToImage.GetOutput()) writer.SetFileName(os.path.join(homeDir,fileName)) writer.Write() def QuitRendererCallback(self, obj): self.PrintLog('Quit renderer') self.Renderer.RemoveActor(self.TextActor) self.RenderWindowInteractor.ExitCallback() def ResetCameraCallback(self, obj): self.Renderer.ResetCamera() self.RenderWindow.Render() def UpdateTextInput(self): if self.TextInputQuery: if self.CurrentTextInput or self.CurrentTextInput == '': self.TextInputActor.SetInput(self.TextInputQuery+self.CurrentTextInput+'_') else: self.TextInputActor.SetInput(self.TextInputQuery) self.Renderer.AddActor(self.TextInputActor) else: self.Renderer.RemoveActor(self.TextInputActor) self.RenderWindow.Render() def KeyPressCallback(self, obj, event): return def CharCallback(self, obj, event): key = self.RenderWindowInteractor.GetKeySym() if self.TextInputMode: if key in ['Return','Enter']: self.ExitTextInputMode() return if key.startswith('KP_'): key = key[3:] if key == 'space': key = ' ' elif key in ['minus','Subtract']: key = '-' elif key in ['period','Decimal']: key = '.' elif len(key) > 1 and key not in ['Backspace','BackSpace']: key = None if key in ['Backspace','BackSpace']: textInput = self.CurrentTextInput if len(textInput) > 0: self.CurrentTextInput = textInput[:-1] elif key: self.CurrentTextInput += key self.UpdateTextInput() return if key in self.KeyBindings and self.KeyBindings[key]['callback'] != None: self.KeyBindings[key]['callback'](obj) else: if key == 'plus': key = '+' if key == 'minus': key = '-' if key == 'equal': key = '=' if key in self.KeyBindings and self.KeyBindings[key]['callback'] != None: self.KeyBindings[key]['callback'](obj) def AddKeyBinding(self, key, text, callback=None, group='1'): self.KeyBindings[key] = {'text': text, 'callback': callback, 'group': group} def RemoveKeyBinding(self, key): if key in self.KeyBindings: del self.KeyBindings[key] def PromptAsync(self, queryText, callback): self.TextInputQuery = queryText self.CurrentTextInput = None self.ExitTextInputCallback = callback self.UpdateTextInput() self.EnterTextInputMode(interactive=0) def EnterTextInputMode(self,interactive=1): self.CurrentTextInput = '' self.Renderer.AddActor(self.TextInputActor) self.Renderer.RemoveActor(self.TextActor) self.UpdateTextInput() self.TextInputMode = 1 self.Render(interactive) def ExitTextInputMode(self): self.Renderer.RemoveActor(self.TextInputActor) self.Renderer.AddActor(self.TextActor) self.RenderWindow.Render() self.TextInputMode = 0 if self.ExitTextInputCallback: self.ExitTextInputCallback(self.CurrentTextInput) self.ExitTextInputCallback = None if self.ExitAfterTextInputMode: self.RenderWindowInteractor.ExitCallback() def Render(self,interactive=1): if interactive: self.RenderWindowInteractor.Initialize() self.RenderWindow.SetWindowName("vmtk - the Vascular Modeling Toolkit") #sortedKeysStd = self.KeyBindingsStd.keys() #sortedKeysStd.sort() #textActorInputsStd = ['%s: %s' % (key, self.KeyBindingsStd[key]['text']) for key in sortedKeysStd] #self.TextActorStd.SetInput('\n'.join(textActorInputsStd)) #self.Renderer.AddActor(self.TextActorStd) groups = list(set([self.KeyBindings[el]['group'] for el in self.KeyBindings])) groups.sort(reverse=True) textActorInputsList = [] for group in groups: sortedKeys = [key for key in self.KeyBindings.keys() if self.KeyBindings[key]['group'] == group] sortedKeys.sort() textActorInputs = ['%s: %s' % (key, self.KeyBindings[key]['text']) for key in sortedKeys] textActorInputsList.append('\n'.join(textActorInputs)) self.TextActor.SetInput('\n\n'.join(textActorInputsList)) self.Renderer.AddActor(self.TextActor) #if len(self.KeyBindingsOpmode.keys()) != 0: # sortedKeysOpmode = self.KeyBindingsOpmode.keys() # sortedKeysOpmode.sort() # textActorInputsOpmode = ['%s: %s' % (key, self.KeyBindingsOpmode[key]['text']) for key in sortedKeysOpmode] # self.TextActorOpmode.SetInput('\n'.join(textActorInputsOpmode)) # self.TextActorOpmode.GetProperty().SetColor(1.0, 0.75, 0.32) # self.Renderer.AddActor(self.TextActorOpmode) #else: # self.TextActorOpmode.SetInput('.') # self.Renderer.AddActor(self.TextActorOpmode) self.RenderWindow.Render() if interactive: self.RenderWindowInteractor.Start() def Initialize(self): if not self.Renderer: self.Renderer = vtk.vtkRenderer() self.Renderer.SetBackground(self.Background) self.RenderWindow = vtk.vtkRenderWindow() self.RenderWindow.AddRenderer(self.Renderer) self.RenderWindow.SetSize(self.WindowSize[0],self.WindowSize[1]) self.RenderWindow.SetPointSmoothing(self.PointSmoothing) self.RenderWindow.SetLineSmoothing(self.LineSmoothing) self.RenderWindow.SetPolygonSmoothing(self.PolygonSmoothing) self.RenderWindowInteractor = vtk.vtkRenderWindowInteractor() if 'vtkCocoaRenderWindowInteractor' in dir(vtk) and vtk.vtkCocoaRenderWindowInteractor.SafeDownCast(self.RenderWindowInteractor): self.RenderWindowInteractor = vtkvmtk.vtkvmtkCocoaRenderWindowInteractor() self.RenderWindow.SetInteractor(self.RenderWindowInteractor) self.RenderWindowInteractor.SetInteractorStyle(vtkvmtk.vtkvmtkInteractorStyleTrackballCamera()) self.RenderWindowInteractor.GetInteractorStyle().AddObserver("CharEvent",self.CharCallback) self.RenderWindowInteractor.GetInteractorStyle().AddObserver("KeyPressEvent",self.KeyPressCallback) self.AddKeyBinding('x','Take screenshot.',self.ScreenshotCallback,'0') self.AddKeyBinding('r','Reset camera.',self.ResetCameraCallback,'0') #self.AddKeyBinding('w','Show wireframe.',None,'0') #self.AddKeyBinding('r','Reset camera.',self.ResetCameraCallback, '0') #self.AddKeyBinding('s','Show surface.', None,'0') #self.AddKeyBinding('e','Quit renderer.',self.QuitRendererCallback,'0') self.AddKeyBinding('q','Quit renderer/proceed.',self.QuitRendererCallback,'0') #self.AddKeyBinding('3','3D.', None,'0') #self.TextActorStd = vtk.vtkTextActor() #self.TextActorStd.SetPosition(self.PositionStd) #self.Renderer.AddActor(self.TextActorStd) self.TextActor = vtk.vtkTextActor() self.TextActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() self.TextActor.GetPosition2Coordinate().SetCoordinateSystemToNormalizedViewport() self.TextActor.SetPosition(self.Position) self.Renderer.AddActor(self.TextActor) #self.TextActorOpmode = vtk.vtkTextActor() #self.TextActorOpmode.SetPosition(self.PositionOpmode) #self.Renderer.AddActor(self.TextActorOpmode) self.TextInputActor = vtk.vtkTextActor() self.TextInputActor.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() self.TextInputActor.GetPosition2Coordinate().SetCoordinateSystemToNormalizedViewport() self.TextInputActor.SetPosition(self.InputPosition) if self.UseRendererInputStream: self.InputStream = vmtkRendererInputStream(self) def RegisterScript(self, script): if self.UseRendererInputStream: script.InputStream = vmtkRendererInputStream(self) def Execute(self): self.Initialize() def Close(self,event,clientData): self.RenderWindowInteractor.Close() def Deallocate(self): if 'vtkCocoaRenderWindowInteractor' in dir(vtk) and vtkvmtk.vtkvmtkCocoaRenderWindowInteractor.SafeDownCast(self.RenderWindowInteractor): self.RenderWindowInteractor.AddObserver("TimerEvent", self.Close) self.RenderWindowInteractor.CreateOneShotTimer(1) self.RenderWindowInteractor.Start() self.RenderWindowInteractor = None self.RenderWindow = None self.Renderer = None if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshscaling.py0000664000175000017500000000350011757446472017247 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshscaling.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkmeshscaling = 'vmtkMeshScaling' class vmtkMeshScaling(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.ScaleFactor = None self.SetScriptName('vmtkmeshscaling') self.SetScriptDoc('scale a mesh by an isotropic factor') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['ScaleFactor','scale','float',1,'(0.0,)','isotropic scaling factor'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') transform = vtk.vtkTransform() transform.Scale(self.ScaleFactor,self.ScaleFactor,self.ScaleFactor) transformFilter = vtk.vtkTransformFilter() transformFilter.SetInput(self.Mesh) transformFilter.SetTransform(transform) transformFilter.Update() self.Mesh = transformFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagecompose.py0000664000175000017500000000537411757446472017435 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagecompose.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkimagecompose = 'vmtkImageCompose' class vmtkImageCompose(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.Image2 = None self.Operation = 'min' self.NegateImage2 = False self.SetScriptName('vmtkimagecompose') self.SetScriptDoc('compose an image based on user-specified parameters or on a reference image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['Image2','i2','vtkImageData',1,'','the second input image','vmtkimagereader'], ['Operation','operation','str',1,'["min","max","multiply","subtract"]','the operation used to compose images'], ['NegateImage2','negatei2','bool',1,'','negate the second input before composing'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.Image2 == None: self.PrintError('Error: No input image2.') if self.NegateImage2: negateFilter = vtk.vtkImageMathematics() negateFilter.SetInput(self.Image2) negateFilter.SetOperationToMultiplyByK() negateFilter.SetConstantK(-1.0) negateFilter.Update() self.Image2 = negateFilter.GetOutput() composeFilter = vtk.vtkImageMathematics() composeFilter.SetInput1(self.Image) composeFilter.SetInput2(self.Image2) if self.Operation == 'min': composeFilter.SetOperationToMin() elif self.Operation == 'max': composeFilter.SetOperationToMax() elif self.Operation == 'multiply': composeFilter.SetOperationToMultiply() elif self.Operation == 'subtract': composeFilter.SetOperationToSubtract() else: self.PrintError('Error: Unsupported operation') composeFilter.Update() self.Image = composeFilter.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacedecimation.py0000664000175000017500000000500111757446472020435 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacedecimation.py,v $ ## Language: Python ## Date: $Date: 2006/02/23 09:27:52 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtksurfacedecimation = 'vmtkSurfaceDecimation' class vmtkSurfaceDecimation(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.TargetReduction = 0.5 self.BoundaryVertexDeletion = 0 self.SetScriptName('vmtksurfacedecimation') self.SetScriptDoc('reduce the number of triangles in a surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['TargetReduction','reduction','float',1,'(0.0,1.0)','desired number of triangles relative to input number of triangles'], ['BoundaryVertexDeletion','boundarydeletion','bool',1,'','toggle allow boundary point deletion'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') triangleFilter = vtk.vtkTriangleFilter() triangleFilter.SetInput(self.Surface) triangleFilter.Update() decimationFilter = vtk.vtkDecimatePro() decimationFilter.SetInput(triangleFilter.GetOutput()) decimationFilter.SetTargetReduction(self.TargetReduction) decimationFilter.SetBoundaryVertexDeletion(self.BoundaryVertexDeletion) decimationFilter.PreserveTopologyOn() decimationFilter.Update() cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(decimationFilter.GetOutput()) cleaner.Update() triangleFilter = vtk.vtkTriangleFilter() triangleFilter.SetInput(cleaner.GetOutput()) triangleFilter.Update() self.Surface = triangleFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkpolyballmodeller.py0000664000175000017500000000553311757446472020324 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkpolyballmodeller.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import pypes vmtkpolyballmodeller = 'vmtkPolyBallModeller' class vmtkPolyBallModeller(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ReferenceImage = None self.RadiusArrayName = None self.Image = None self.ModelBounds = None self.SampleDimensions = [64,64,64] self.NegateFunction = 0 self.SetScriptName('vmtkpolyballmodeller') self.SetScriptDoc('converts a polyball to an image containing the tube function') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where radius values are stored'], ['Image','image','vtkImageData',1,'','the input image to use as a reference','vmtkimagereader'], ['SampleDimensions','dimensions','int',3,'(0,)','dimensions of the output image'], ['ModelBounds','bounds','float',6,'(0.0,)','model bounds in physical coordinates (if None, they are computed automatically)'], ['NegateFunction','negate','bool',1,'','produce a function that is negative inside the polyball'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter']]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.RadiusArrayName == None: self.PrintError('Error: No radius array name.') modeller = vtkvmtk.vtkvmtkPolyBallModeller() modeller.SetInput(self.Surface) modeller.SetRadiusArrayName(self.RadiusArrayName) modeller.UsePolyBallLineOff() if self.Image: modeller.SetReferenceImage(self.Image) else: modeller.SetSampleDimensions(self.SampleDimensions) if self.ModelBounds: modeller.SetModelBounds(self.ModelBounds) modeller.SetNegateFunction(self.NegateFunction) modeller.Update() self.Image = modeller.GetOutput() if self.Image.GetSource(): self.Image.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfaceprojection.py0000664000175000017500000000372011757446472020503 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceprojection.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfaceprojection = 'vmtkSurfaceProjection' class vmtkSurfaceProjection(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.ReferenceSurface = None self.Surface = None self.SetScriptName('vmtksurfaceprojection') self.SetScriptDoc('interpolates the point data of a reference surface onto the input surface based on minimum distance criterion') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ReferenceSurface','r','vtkPolyData',1,'','the reference surface','vmtksurfacereader'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') if self.ReferenceSurface == None: self.PrintError('Error: No ReferenceSurface.') self.InputInfo('Computing projection.') surfaceProjection = vtkvmtk.vtkvmtkSurfaceProjection() surfaceProjection.SetInput(self.Surface) surfaceProjection.SetReferenceSurface(self.ReferenceSurface) surfaceProjection.Update() self.Surface = surfaceProjection.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkdistancetocenterlines.py0000664000175000017500000000610011757446472021342 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkdistancetocenterlines.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.5 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkdistancetocenterlines = 'vmtkDistanceToCenterlines' class vmtkDistanceToCenterlines(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.UseRadiusInformation = 0 self.EvaluateTubeFunction = 0 self.EvaluateCenterlineRadius = 0 self.ProjectPointArrays = 0 self.DistanceToCenterlinesArrayName = 'DistanceToCenterlines' self.RadiusArrayName = '' self.SetScriptName('vmtkdistancetocenterlines') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['UseRadiusInformation','useradius','bool',1], ['EvaluateTubeFunction','tubefunction','bool',1], ['EvaluateCenterlineRadius','centerlineradius','bool',1], ['ProjectPointArrays','projectarrays','bool',1], ['DistanceToCenterlinesArrayName','distancetocenterlinesarray','str',1], ['RadiusArrayName','radiusarray','str',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') distanceToCenterlinesFilter = vtkvmtk.vtkvmtkPolyDataDistanceToCenterlines() distanceToCenterlinesFilter.SetInput(self.Surface) distanceToCenterlinesFilter.SetCenterlines(self.Centerlines) distanceToCenterlinesFilter.SetUseRadiusInformation(self.UseRadiusInformation) distanceToCenterlinesFilter.SetEvaluateTubeFunction(self.EvaluateTubeFunction) distanceToCenterlinesFilter.SetEvaluateCenterlineRadius(self.EvaluateCenterlineRadius) distanceToCenterlinesFilter.SetProjectPointArrays(self.ProjectPointArrays) distanceToCenterlinesFilter.SetDistanceToCenterlinesArrayName(self.DistanceToCenterlinesArrayName) distanceToCenterlinesFilter.SetCenterlineRadiusArrayName(self.RadiusArrayName) distanceToCenterlinesFilter.Update() self.Surface = distanceToCenterlinesFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlineoffsetattributes.py0000664000175000017500000001566111757446472022433 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlineoffsetattributes.py,v $ ## Language: Python ## Date: $Date: 2006/04/06 16:46:43 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes import vmtkrenderer import vmtkcenterlineviewer vmtkcenterlineoffsetattributes = 'vmtkCenterlineOffsetAttributes' class vmtkCenterlineOffsetAttributes(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.ReferenceSystems = None self.ReferenceGroupId = -1 self.AbscissasArrayName = '' self.NormalsArrayName = '' self.GroupIdsArrayName = '' self.CenterlineIdsArrayName = '' self.ReferenceSystemsNormalArrayName = '' self.ReplaceAttributes = 1 self.OffsetAbscissasArrayName = 'OffsetAbscissas' self.OffsetNormalsArrayName = 'OffsetNormals' self.vmtkRenderer = None self.OwnRenderer = 0 self.Interactive = 0 self.SetScriptName('vmtkcenterlineoffsetattributes') self.SetScriptDoc('offset centerline attributes relative to a bifurcation reference system, in such a way that the abscissa of the closest point the the origin is zero, and the centerline normal at that point coincides with the bifurcation reference system normal') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input split centerlines','vmtksurfacereader'], ['ReferenceSystems','referencesystems','vtkPolyData',1,'','bifurcation reference systems','vmtksurfacereader'], ['ReferenceGroupId','referencegroupid','int',1,'','group id of the reference system to which attributes have to be offset'], ['ReplaceAttributes','replaceattributes','bool',1,'','overwrite the existing attributes'], ['AbscissasArrayName','abscissasarray','str',1,'','name of the array where centerline abscissas are stored'], ['NormalsArrayName','normalsarray','str',1,'','name of the array where centerline normals are stored'], ['GroupIdsArrayName','groupidsarray','str',1,'','name of the array where centerline group ids are stored'], ['CenterlineIdsArrayName','centerlineidsarray','str',1,'','name of the array where centerline ids are stored'], ['ReferenceSystemsNormalArrayName','referencesystemsnormalarray','str',1,'','name of the array where reference system normals are stored'], ['OffsetAbscissasArrayName','offsetabscissasarray','str',1,'','name of the array where offset centerline abscissas have to be stored if ReplaceAttributes is off'], ['OffsetNormalsArrayName','offsetnormalsarray','str',1,'','name of the array where offset centerline normals have to be stored if ReplaceAttributes is off'], ['Interactive','interactive','bool',1], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Centerlines','o','vtkPolyData',1,'','the output centerlines','vmtksurfacewriter'], ['ReferenceGroupId','referencegroupid','int',1,'','group id of the reference system to which attributes are offset'], ['OffsetAbscissasArrayName','offsetabscissasarray','str',1,'','name of the array where offset centerline abscissas are stored if ReplaceAttributes is off'], ['OffsetNormalsArrayName','offsetnormalsarray','str',1,'','name of the array where offset centerline normals are stored if ReplaceAttributes is off'], ['AbscissasArrayName','abscissasarray','str',1,'','name of the array where centerline abscissas are stored'], ['NormalsArrayName','normalsarray','str',1,'','name of the array where centerline normals are stored'] ]) def GroupIdValidator(self,text): import string if not text: return 0 for char in text: if char not in string.digits: return 0 return 1 def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') if self.ReferenceSystems == None: self.PrintError('Error: No input reference systems.') if self.Interactive and not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 if self.Interactive: self.vmtkRenderer.RegisterScript(self) viewer = vmtkcenterlineviewer.vmtkCenterlineViewer() viewer.Centerlines = self.Centerlines viewer.CellDataArrayName = self.GroupIdsArrayName viewer.vmtkRenderer = self.vmtkRenderer viewer.InputText = self.InputText viewer.OutputText = self.OutputText viewer.PrintError = self.PrintError viewer.PringLog = self.PrintLog viewer.Display = 0 viewer.Execute() groupIdString = self.InputText("Please input the reference groupId:\n",self.GroupIdValidator) self.ReferenceGroupId = int(groupIdString) offsetFilter = vtkvmtk.vtkvmtkCenterlineReferenceSystemAttributesOffset() offsetFilter.SetInput(self.Centerlines) offsetFilter.SetReferenceSystems(self.ReferenceSystems) offsetFilter.SetAbscissasArrayName(self.AbscissasArrayName) offsetFilter.SetNormalsArrayName(self.NormalsArrayName) if not self.ReplaceAttributes: offsetFilter.SetOffsetAbscissasArrayName(self.OffsetAbscissasArrayName) offsetFilter.SetOffsetNormalsArrayName(self.OffsetNormalsArrayName) else: offsetFilter.SetOffsetAbscissasArrayName(self.AbscissasArrayName) offsetFilter.SetOffsetNormalsArrayName(self.NormalsArrayName) offsetFilter.SetGroupIdsArrayName(self.GroupIdsArrayName) offsetFilter.SetCenterlineIdsArrayName(self.CenterlineIdsArrayName) offsetFilter.SetReferenceSystemsNormalArrayName(self.ReferenceSystemsNormalArrayName) offsetFilter.SetReferenceSystemsGroupIdsArrayName(self.GroupIdsArrayName) offsetFilter.SetReferenceGroupId(self.ReferenceGroupId) offsetFilter.Update() self.Centerlines = offsetFilter.GetOutput() if self.ReferenceGroupId == -1: self.ReferenceGroupId = offsetFilter.GetReferenceGroupId() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimageinitialization.py0000664000175000017500000004113211757446472021007 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimageinitialization.py,v $ ## Language: Python ## Date: $Date: 2006/05/31 10:51:21 $ ## Version: $Revision: 1.19 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import math import string import vtk import vtkvmtk import vmtkscripts import pypes vmtkimageinitialization = 'vmtkImageInitialization' class vmtkImageInitialization(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.vmtkRenderer = None self.OwnRenderer = 0 self.InitialLevelSets = None self.Surface = None self.MergedInitialLevelSets = None self.UpperThreshold = 0.0 self.LowerThreshold = 0.0 self.NegateImage = 0 self.IsoSurfaceValue = 0.0 self.ImageSeeder = None self.SurfaceViewer = None self.SetScriptName('vmtkimageinitialization') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','','vmtkimagereader'], ['NegateImage','negate','bool',1,'','negate image values before initializing'], ['vmtkRenderer','renderer','vmtkRenderer',1] ]) self.SetOutputMembers([ ['IsoSurfaceValue','isosurfacevalue','float',1], ['InitialLevelSets','olevelsets','vtkImageData',1,'','','vmtkimagewriter'], ['Surface','osurface','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def SeedInput(self,queryString,numberOfSeeds): invalid = 1 while invalid == 1: invalid = 0 self.InputInfo(queryString+' (click on the image while pressing Ctrl).\n') self.ImageSeeder.InitializeSeeds() self.vmtkRenderer.Render() if numberOfSeeds > 0: if self.ImageSeeder.Seeds.GetNumberOfPoints() != numberOfSeeds: self.InputInfo('Invalid selection. Please place exactly '+str(numberOfSeeds)+' seeds.\n') invalid = 1 continue seeds = vtk.vtkPolyData() seeds.DeepCopy(self.ImageSeeder.Seeds) seeds.Update() return seeds def ThresholdValidator(self,text): if text == 'n': return 1 if text == 'i': self.vmtkRenderer.Render() return 0 try: float(text) except ValueError: return 0 return 1 def ThresholdInput(self,queryString): thresholdString = self.InputText(queryString,self.ThresholdValidator) threshold = None if thresholdString != 'n': threshold = float(thresholdString) return threshold def IsosurfaceInitialize(self): self.PrintLog('Isosurface initialization.') queryString = "Please input isosurface level (\'n\' for none): " self.IsoSurfaceValue = self.ThresholdInput(queryString) imageMathematics = vtk.vtkImageMathematics() imageMathematics.SetInput(self.Image) imageMathematics.SetConstantK(-1.0) imageMathematics.SetOperationToMultiplyByK() imageMathematics.Update() subtract = vtk.vtkImageMathematics() subtract.SetInput(imageMathematics.GetOutput()) subtract.SetOperationToAddConstant() subtract.SetConstantC(self.IsoSurfaceValue) subtract.Update() self.InitialLevelSets = vtk.vtkImageData() self.InitialLevelSets.DeepCopy(subtract.GetOutput()) self.InitialLevelSets.Update() self.IsoSurfaceValue = 0.0 def ThresholdInitialize(self): self.PrintLog('Threshold initialization.') queryString = "Please input lower threshold (\'n\' for none): " self.LowerThreshold = self.ThresholdInput(queryString) queryString = "Please input upper threshold (\'n\' for none): " self.UpperThreshold = self.ThresholdInput(queryString) scalarRange = self.Image.GetScalarRange() thresholdedImage = self.Image if self.LowerThreshold != None or self.UpperThreshold != None: threshold = vtk.vtkImageThreshold() threshold.SetInput(self.Image) if self.LowerThreshold != None and self.UpperThreshold != None: threshold.ThresholdBetween(self.LowerThreshold,self.UpperThreshold) elif self.LowerThreshold != None: threshold.ThresholdByUpper(self.LowerThreshold) elif self.UpperThreshold != None: threshold.ThresholdByLower(self.UpperThreshold) threshold.ReplaceInOn() threshold.ReplaceOutOn() threshold.SetInValue(-1.0) threshold.SetOutValue(1.0) threshold.Update() thresholdedImage = threshold.GetOutput() self.InitialLevelSets = vtk.vtkImageData() self.InitialLevelSets.DeepCopy(thresholdedImage) self.InitialLevelSets.Update() self.IsoSurfaceValue = 0.0 def FastMarchingInitialize(self): self.PrintLog('Fast marching initialization.') queryString = "Please input lower threshold (\'n\' for none): " self.LowerThreshold = self.ThresholdInput(queryString) queryString = "Please input upper threshold (\'n\' for none): " self.UpperThreshold = self.ThresholdInput(queryString) queryString = 'Please place source seeds' sourceSeeds = self.SeedInput(queryString,0) queryString = 'Please place target seeds' targetSeeds = self.SeedInput(queryString,0) sourceSeedIds = vtk.vtkIdList() for i in range(sourceSeeds.GetNumberOfPoints()): sourceSeedIds.InsertNextId(self.Image.FindPoint(sourceSeeds.GetPoint(i))) targetSeedIds = vtk.vtkIdList() for i in range(targetSeeds.GetNumberOfPoints()): targetSeedIds.InsertNextId(self.Image.FindPoint(targetSeeds.GetPoint(i))) scalarRange = self.Image.GetScalarRange() thresholdedImage = self.Image if (self.LowerThreshold is not None) | (self.UpperThreshold is not None): threshold = vtk.vtkImageThreshold() threshold.SetInput(self.Image) if (self.LowerThreshold is not None) & (self.UpperThreshold is not None): threshold.ThresholdBetween(self.LowerThreshold,self.UpperThreshold) elif (self.LowerThreshold is not None): threshold.ThresholdByUpper(self.LowerThreshold) elif (self.UpperThreshold is not None): threshold.ThresholdByLower(self.UpperThreshold) threshold.ReplaceInOff() threshold.ReplaceOutOn() threshold.SetOutValue(scalarRange[0] - scalarRange[1]) threshold.Update() scalarRange = threshold.GetOutput().GetScalarRange() thresholdedImage = threshold.GetOutput() shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(thresholdedImage) shiftScale.SetShift(-scalarRange[0]) shiftScale.SetScale(1/(scalarRange[1]-scalarRange[0])) shiftScale.SetOutputScalarTypeToFloat() shiftScale.Update() speedImage = shiftScale.GetOutput() fastMarching = vtkvmtk.vtkvmtkFastMarchingUpwindGradientImageFilter() fastMarching.SetInput(speedImage) fastMarching.SetSeeds(sourceSeedIds) fastMarching.GenerateGradientImageOff() fastMarching.SetTargetOffset(100.0) fastMarching.SetTargets(targetSeedIds) if targetSeedIds.GetNumberOfIds() > 0: fastMarching.SetTargetReachedModeToOneTarget() else: fastMarching.SetTargetReachedModeToNoTargets() fastMarching.Update() subtract = vtk.vtkImageMathematics() subtract.SetInput(fastMarching.GetOutput()) subtract.SetOperationToAddConstant() subtract.SetConstantC(-fastMarching.GetTargetValue()) subtract.Update() self.InitialLevelSets = vtk.vtkImageData() self.InitialLevelSets.DeepCopy(subtract.GetOutput()) self.InitialLevelSets.Update() self.IsoSurfaceValue = 0.0 def CollidingFrontsInitialize(self): self.PrintLog('Colliding fronts initialization.') queryString = "Please input lower threshold (\'n\' for none): " self.LowerThreshold = self.ThresholdInput(queryString) queryString = "Please input upper threshold (\'n\' for none): " self.UpperThreshold = self.ThresholdInput(queryString) queryString = 'Please place two seeds' seeds = self.SeedInput(queryString,2) seedIds1 = vtk.vtkIdList() seedIds2 = vtk.vtkIdList() seedIds1.InsertNextId(self.Image.FindPoint(seeds.GetPoint(0))) seedIds2.InsertNextId(self.Image.FindPoint(seeds.GetPoint(1))) scalarRange = self.Image.GetScalarRange() thresholdedImage = self.Image if (self.LowerThreshold is not None) | (self.UpperThreshold is not None): threshold = vtk.vtkImageThreshold() threshold.SetInput(self.Image) if (self.LowerThreshold is not None) & (self.UpperThreshold is not None): threshold.ThresholdBetween(self.LowerThreshold,self.UpperThreshold) elif (self.LowerThreshold is not None): threshold.ThresholdByUpper(self.LowerThreshold) elif (self.UpperThreshold is not None): threshold.ThresholdByLower(self.UpperThreshold) threshold.ReplaceInOff() threshold.ReplaceOutOn() threshold.SetOutValue(scalarRange[0] - scalarRange[1]) threshold.Update() scalarRange = threshold.GetOutput().GetScalarRange() thresholdedImage = threshold.GetOutput() shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(thresholdedImage) shiftScale.SetShift(-scalarRange[0]) shiftScale.SetScale(1/(scalarRange[1]-scalarRange[0])) shiftScale.SetOutputScalarTypeToFloat() shiftScale.Update() speedImage = shiftScale.GetOutput() collidingFronts = vtkvmtk.vtkvmtkCollidingFrontsImageFilter() collidingFronts.SetInput(speedImage) collidingFronts.SetSeeds1(seedIds1) collidingFronts.SetSeeds2(seedIds2) collidingFronts.ApplyConnectivityOn() collidingFronts.StopOnTargetsOn() collidingFronts.Update() subtract = vtk.vtkImageMathematics() subtract.SetInput(collidingFronts.GetOutput()) subtract.SetOperationToAddConstant() subtract.SetConstantC(-10.0 * collidingFronts.GetNegativeEpsilon()) subtract.Update() self.InitialLevelSets = vtk.vtkImageData() self.InitialLevelSets.DeepCopy(subtract.GetOutput()) self.InitialLevelSets.Update() self.IsoSurfaceValue = 0.0 def SeedInitialize(self): self.PrintLog('Seed initialization.') queryString = 'Please place seeds' seeds = self.SeedInput(queryString,0) self.InitialLevelSets = vtk.vtkImageData() self.InitialLevelSets.DeepCopy(self.Image) self.InitialLevelSets.Update() levelSetsInputScalars = self.InitialLevelSets.GetPointData().GetScalars() levelSetsInputScalars.FillComponent(0,1.0) dimensions = self.Image.GetDimensions() for i in range(seeds.GetNumberOfPoints()): id = self.Image.FindPoint(seeds.GetPoint(i)) levelSetsInputScalars.SetComponent(id,0,-1.0) dilateErode = vtk.vtkImageDilateErode3D() dilateErode.SetInput(self.InitialLevelSets) dilateErode.SetDilateValue(-1.0) dilateErode.SetErodeValue(1.0) dilateErode.SetKernelSize(3,3,3) dilateErode.Update() self.InitialLevelSets.DeepCopy(dilateErode.GetOutput()) self.IsoSurfaceValue = 0.0 def DisplayLevelSetSurface(self,levelSets): value = 0.0 marchingCubes = vtk.vtkMarchingCubes() marchingCubes.SetInput(levelSets) marchingCubes.SetValue(0,value) marchingCubes.Update() self.Surface = marchingCubes.GetOutput() self.OutputText('Displaying.\n') self.SurfaceViewer.Surface = marchingCubes.GetOutput() if self.SurfaceViewer.Surface.GetSource(): self.SurfaceViewer.Surface.GetSource().UnRegisterAllOutputs() self.SurfaceViewer.Display = 0 self.SurfaceViewer.Opacity = 0.5 self.SurfaceViewer.BuildView() def InitializationTypeValidator(self,text): if text in ['0','1','2','3','4']: return 1 return 0 def YesNoValidator(self,text): if text in ['n','y']: return 1 return 0 def MergeLevelSets(self): if self.MergedInitialLevelSets == None: self.MergedInitialLevelSets = vtk.vtkImageData() self.MergedInitialLevelSets.DeepCopy(self.InitialLevelSets) else: minFilter = vtk.vtkImageMathematics() minFilter.SetOperationToMin() minFilter.SetInput1(self.MergedInitialLevelSets) minFilter.SetInput2(self.InitialLevelSets) minFilter.Update() self.MergedInitialLevelSets = minFilter.GetOutput() def Execute(self): if self.Image == None: self.PrintError('Error: no Image.') cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() self.Image = cast.GetOutput() if self.NegateImage: scalarRange = self.Image.GetScalarRange() negate = vtk.vtkImageMathematics() negate.SetInput(self.Image) negate.SetOperationToMultiplyByK() negate.SetConstantK(-1.0) negate.Update() shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(negate.GetOutput()) shiftScale.SetShift(scalarRange[1]+scalarRange[0]) shiftScale.SetOutputScalarTypeToFloat() shiftScale.Update() self.Image = shiftScale.GetOutput() if not self.vmtkRenderer: self.vmtkRenderer = vmtkscripts.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if not self.ImageSeeder: self.ImageSeeder = vmtkscripts.vmtkImageSeeder() self.ImageSeeder.vmtkRenderer = self.vmtkRenderer self.ImageSeeder.Image = self.Image self.ImageSeeder.Display = 0 self.ImageSeeder.Execute() ##self.ImageSeeder.Display = 1 self.ImageSeeder.BuildView() if not self.SurfaceViewer: self.SurfaceViewer = vmtkscripts.vmtkSurfaceViewer() self.SurfaceViewer.vmtkRenderer = self.vmtkRenderer initializationMethods = { '0': self.CollidingFrontsInitialize, '1': self.FastMarchingInitialize, '2': self.ThresholdInitialize, '3': self.IsosurfaceInitialize, '4': self.SeedInitialize } endInitialization = False while not endInitialization: queryString = 'Please choose initialization type: \n 0: colliding fronts;\n 1: fast marching;\n 2: threshold;\n 3: isosurface;\n 4: seed\n ' initializationType = self.InputText(queryString,self.InitializationTypeValidator) initializationMethods[initializationType]() self.DisplayLevelSetSurface(self.InitialLevelSets) queryString = 'Accept initialization? (y/n): ' inputString = self.InputText(queryString,self.YesNoValidator) if inputString == 'y': self.MergeLevelSets() self.DisplayLevelSetSurface(self.MergedInitialLevelSets) queryString = 'Initialize another branch? (y/n): ' inputString = self.InputText(queryString,self.YesNoValidator) if inputString == 'y': endInitialization = False elif inputString == 'n': endInitialization = True self.InitialLevelSets = self.MergedInitialLevelSets self.MergedInitialLevelSets = None if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshtransformtoras.py0000664000175000017500000000411411757446472020715 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshtransformtoras.py,v $ ## Language: Python ## Date: $Date: Sun Feb 21 17:02:37 CET 2010$ ## Version: $Revision: 1.0 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkmeshtransformtoras = 'vmtkMeshTransformToRAS' class vmtkMeshTransformToRAS(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.XyzToRasMatrixCoefficients = None self.SetScriptName('vmtkmeshtransformtoras') self.SetScriptDoc('transform a mesh generated in XYZ image space into RAS space') self.SetInputMembers([ ['Mesh','i','vtkPolyData',1,'','the input mesh','vmtkmeshreader'], ['XyzToRasMatrixCoefficients','matrix','float',16,'','coefficients of XYZToRAS transform matrix'] ]) self.SetOutputMembers([ ['Mesh','o','vtkPolyData',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: no Mesh.') if self.XyzToRasMatrixCoefficients == None: self.PrintError('Error: no XyzToRasMatrixCoefficients.') matrix = vtk.vtkMatrix4x4() matrix.DeepCopy(self.XyzToRasMatrixCoefficients) transform = vtk.vtkTransform() transform.SetMatrix(matrix) transformFilter = vtk.vtkTransformFilter() transformFilter.SetInput(self.Mesh) transformFilter.SetTransform(transform) transformFilter.Update() self.Mesh = transformFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtknetworkwriter.py0000664000175000017500000002547511757446472017717 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtknetworkwriter.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. ## Developed with support from the EC FP7/2007-2013: ARCH, Project n. 224390 import vtk import sys import pypes vmtknetworkwriter = 'vmtkNetworkWriter' class vmtkNetworkWriter(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.OutputFileName = '' self.Network = None self.Input = None self.InputUnits = 'mm' self.RadiusArrayName = 'Radius' self.LabelsArrayName = 'Labels' self.SetScriptName('vmtknetworkwriter') self.SetScriptDoc('write network to disk') self.SetInputMembers([ ['Network','i','vtkPolyData',1,'','the input network','vmtksurfacereader'], ['Format','f','str',1,'["vtkxml","vtk","arch"]','file format'], ['InputUnits','u','str',1,'["mm","cm","m"]','units in which the input network is represented'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['RadiusArrayName','radiusarray','str',1,'','name of the point data array where radius is stored (arch format)'], ['LabelsArrayName','labelsarray','str',1,'','name of the cell data array where labels are stored (arch format)'], ['OutputFileName','ofile','str',1,'','output file name'], ['OutputFileName','o','str',1,'','output file name (deprecated: use -ofile)'] ]) self.SetOutputMembers([]) def WriteVTKNetworkFile(self): if self.OutputFileName == '': self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK network file.') writer = vtk.vtkPolyDataWriter() writer.SetInput(self.Network) writer.SetFileName(self.OutputFileName) writer.Write() def WriteVTKXMLNetworkFile(self): if self.OutputFileName == '': self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK XML network file.') writer = vtk.vtkXMLPolyDataWriter() writer.SetInput(self.Network) writer.SetFileName(self.OutputFileName) #writer.SetDataModeToAscii() writer.Write() def WriteARCHNetworkFile(self): if self.OutputFileName == '': self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing ARCH network file.') factor = 1.0 if self.InputUnits == 'cm': factor = 0.01 elif self.InputUnits == 'mm': factor = 0.001 radiusArray = None if self.RadiusArrayName: radiusArray = self.Network.GetPointData().GetArray(self.RadiusArrayName) labelsArray = None if self.LabelsArrayName != '': labelsArray = vtk.vtkStringArray.SafeDownCast(self.Network.GetCellData().GetAbstractArray(self.LabelsArrayName)) from xml.dom import minidom xmlDocument = minidom.Document() xmlNetworkGraph = xmlDocument.appendChild(xmlDocument.createElement('NetworkGraph')) xmlNetworkGraph.setAttribute('id','1') xmlNetworkGraph.setAttribute('version','3.0') xmlNetworkGraph.setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance') xmlNetworkGraph.setAttribute('xsi:noNamespaceSchemaLocation','vascular_network_v2.3.xsd') xmlCase = xmlNetworkGraph.appendChild(xmlDocument.createElement('case')) xmlPatientId = xmlCase.appendChild(xmlDocument.createElement('patient_id')) xmlPatientId.appendChild(xmlDocument.createTextNode('00000')) xmlVisit = xmlCase.appendChild(xmlDocument.createElement('visit')) xmlVisit.appendChild(xmlDocument.createTextNode('other')) nodeMap = {} edgeCellIds = [] edges = [] for i in range(self.Network.GetNumberOfCells()): cell = self.Network.GetCell(i) if not (cell.GetCellType() in (3,4)): continue pointId0 = cell.GetPointId(0) pointId1 = cell.GetPointId(cell.GetNumberOfPoints()-1) if not nodeMap.has_key(pointId0): nodeId = len(nodeMap) nodeMap[pointId0] = nodeId if not nodeMap.has_key(pointId1): nodeId = len(nodeMap) nodeMap[pointId1] = nodeId edgeId = len(edges) edgeCellIds.append(edgeId) edges.append((nodeMap[pointId0],nodeMap[pointId1])) nodes = nodeMap.values()[:] nodes.sort() xmlNodes = xmlNetworkGraph.appendChild(xmlDocument.createElement('nodes')) for node in nodes: xmlNode = xmlNodes.appendChild(xmlDocument.createElement('node')) xmlNode.setAttribute('id','%d' % node) #xmlNodeClassification = xmlNode.appendChild(xmlDocument.createElement('node_classification')) xmlEdges = xmlNetworkGraph.appendChild(xmlDocument.createElement('edges')) for i in range(len(edges)): edge = edges[i] xmlEdge = xmlEdges.appendChild(xmlDocument.createElement('edge')) xmlEdge.setAttribute('id','%d' % i) xmlEdge.setAttribute('node1_id','%d' % edge[0]) xmlEdge.setAttribute('node2_id','%d' % edge[1]) if labelsArray: label = labelsArray.GetValue(edgeCellIds[i]) if 'aorta' in label or 'artery' in label or 'art' in label or 'a.' in label: xmlEdge.setAttribute('side','arterial') if 'vena' in label or 'vein' in label or 'v.' in label: xmlEdge.setAttribute('side','venous') xmlEdge.setAttribute('name',label) else: xmlEdge.setAttribute('side','arterial') xmlEdge.setAttribute('name','edge%d' % i) #xmlEdgeClassification = xmlEdge.appendChild(xmlDocument.createElement('edge_classification')) #if labelsArray: # label = labelsArray.GetValue(edgeCellIds[i]) # if 'aorta' in label or 'artery' in label or 'art' in label or 'a.' in label: # xmlEdgeClassification.setAttribute('side','arterial') # if 'vena' in label or 'vein' in label or 'v.' in label: # xmlEdgeClassification.setAttribute('side','venous') # xmlEdgeClassification.appendChild(xmlDocument.createTextNode(label)) xmlGeometry = xmlEdge.appendChild(xmlDocument.createElement('geometry')) length = 0.0 cell = self.Network.GetCell(edgeCellIds[i]) cellPoints = cell.GetPoints() prevPoint = cellPoints.GetPoint(0) abscissas = [0.0] coordinates = [[factor*el for el in prevPoint]] for j in range(1,cell.GetNumberOfPoints()): point = cellPoints.GetPoint(j) length += factor * vtk.vtkMath.Distance2BetweenPoints(prevPoint,point)**0.5 abscissas.append(length) coordinates.append([factor*el for el in point]) prevPoint = point xmlLength = xmlGeometry.appendChild(xmlDocument.createElement('length')) xmlLength.setAttribute('unit','m') xmlScalar = xmlLength.appendChild(xmlDocument.createElement('scalar')) xmlScalar.appendChild(xmlDocument.createTextNode('%f' % length)) xmlCoordinatesArray = xmlGeometry.appendChild(xmlDocument.createElement('coordinates_array')) for j in range(len(abscissas)): xmlCoordinates = xmlCoordinatesArray.appendChild(xmlDocument.createElement('coordinates')) #TODO: check for length == 0 xmlCoordinates.setAttribute('s','%f' % (abscissas[j]/length)) xmlCoordinates.setAttribute('x','%f' % coordinates[j][0]) xmlCoordinates.setAttribute('y','%f' % coordinates[j][1]) xmlCoordinates.setAttribute('z','%f' % coordinates[j][2]) xmlProperties = xmlEdge.appendChild(xmlDocument.createElement('properties')) if radiusArray: xmlRadiusArray = xmlProperties.appendChild(xmlDocument.createElement('radius_array')) xmlRadiusArray.setAttribute('unit','m') for j in range(cell.GetNumberOfPoints()): pointId = cell.GetPointId(j) radius = factor * radiusArray.GetTuple1(pointId) xmlValue = xmlRadiusArray.appendChild(xmlDocument.createElement('value')) xmlValue.setAttribute('s','%f' % (abscissas[j]/length)) xmlScalar = xmlValue.appendChild(xmlDocument.createElement('scalar')) xmlScalar.appendChild(xmlDocument.createTextNode('%f' % radius)) #xmlTransformations = xmlNetworkGraph.appendChild(xmlDocument.createElement('transformations')) xmlFile = open(self.OutputFileName,'w') xmlFile.write(xmlDocument.toprettyxml()) xmlFile.close() def Execute(self): if self.Network == None: if self.Input == None: self.PrintError('Error: no Network.') self.Network = self.Input extensionFormats = {'vtp':'vtkxml', 'vtkxml':'vtkxml', 'xml':'arch'} if self.OutputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.OutputFileName = tkFileDialog.asksaveasfilename(title="Output network",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.OutputFileName) if not self.OutputFileName: self.PrintError('Error: no OutputFileName.') if self.GuessFormat and self.OutputFileName and not self.Format: import os.path extension = os.path.splitext(self.OutputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.WriteVTKNetworkFile() elif (self.Format == 'vtkxml'): self.WriteVTKXMLNetworkFile() elif (self.Format == 'arch'): self.WriteARCHNetworkFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshdatareader.py0000664000175000017500000003304711757446472017734 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshdatareader.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import os import gzip import vtk import vtkvmtk import pypes vmtkmeshdatareader = 'vmtkMeshDataReader' class vmtkMeshDataReader(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.TetrInFileName = '' self.Mesh = 0 self.DataFileDirectory = '.' self.DataFilePrefix = '' self.DataFileType = 'tetr.vel' self.DataFileName = '' self.ArrayNamePrefix = '' self.Compressed = 1 self.UnNormalize = 1 self.MinVariableId = -1 self.MaxVariableId = -1 self.Radius = 1.0 self.Viscosity = 1.0 self.Density = 1.0 self.ReD = 0.0 self.Alpha = 0.0 self.SetScriptName('vmtkmeshdatareader') self.SetScriptDoc('read data associated with a mesh') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['DataFileDirectory','directory','str',1,'','directory where the data files reside'], ['DataFilePrefix','prefix','str',1,'','data file name prefix (e.g. foo_)'], ['DataFileName','datafile','str',1,'','data file name (e.g. foo.dat) excluding directory - overrides prefix'], ['DataFileType','filetype','str',1,'','data file name type (tetr.out, tetr.vel, tetr.wss, tetr.pres, tetr.ini, pointdata)'], ['ArrayNamePrefix','arrayprefix','str',1,'','prefix to prepend to array names in output'], ['TetrInFileName','tetrinfile','str',1,'','name of the tetr.in file'], ['Compressed','compressed','bool',1,'','toggle reading gzip compressed file'], ['UnNormalize','unnormalize','bool',1,'','unnormalize quantities - tetr.* only'], ['MinVariableId','minvarid','int',1,'(0,)','read variables starting from the nth column - pointdata only'], ['MaxVariableId','maxvarid','int',1,'(0,)','read variables up to the nth column - pointdata only'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def ReadTetrInDimensionalParameters(self): tetrinf=open(self.TetrInFileName, 'r') tetrinline = '' while tetrinline.strip() != '$radius': tetrinline = tetrinf.readline() if tetrinline == '': break if tetrinline.strip() == '$radius': tetrinline = tetrinf.readline() self.Radius = float(tetrinline.strip()) tetrinf.seek(0) tetrinline = '' while tetrinline.strip() != '$viscosity': tetrinline = tetrinf.readline() if tetrinline == '': break if tetrinline.strip() == '$viscosity': tetrinline = tetrinf.readline() self.Viscosity = float(tetrinline.strip()) tetrinf.seek(0) tetrinline = '' while tetrinline.strip() != '$density': tetrinline = tetrinf.readline() if tetrinline == '': break if tetrinline.strip() == '$density': tetrinline = tetrinf.readline() self.Density = float(tetrinline.strip()) tetrinf.seek(0) tetrinline = '' while tetrinline.strip() != '$red': tetrinline = tetrinf.readline() if tetrinline == '': break if tetrinline.strip() == '$red': tetrinline = tetrinf.readline() self.ReD = float(tetrinline.strip()) else: tetrinf.seek(0) while tetrinline.strip() != '$rer': tetrinline = tetrinf.readline() if tetrinline == '': break if tetrinline.strip() == '$rer': tetrinline = tetrinf.readline() self.ReD = float(tetrinline.strip())*2.0 tetrinf.seek(0) tetrinline = '' while tetrinline.strip() != '$alpha': tetrinline = tetrinf.readline() if tetrinline == '': break if tetrinline.strip() == '$alpha': tetrinline = tetrinf.readline() self.Alpha = float(tetrinline.strip()) def ReadTetrOutFile(self,filename,arrayname): self.PrintLog('Reading '+filename+'.') if self.UnNormalize == 1: self.ReadTetrInDimensionalParameters() f = None if (self.Compressed == 1): f=gzip.open(filename, 'r') else: f=open(filename, 'r') line = f.readline() while (line!='$output'): line = f.readline() line = f.readline() splitline = line.split(' ') numberOfTuples = int(splitline[0]) outputArray = vtk.vtkDoubleArray() outputArray.SetName(arrayname) outputArray.SetNumberOfComponents(3) outputArray.SetNumberOfTuples(numberOfTuples) velocityUnNormalizationFactor = self.ReD / (2.0 * self.Radius) * self.Viscosity / self.Density for i in range(numberOfTuples): line = f.readline() splitline = line.split(' ') value0 = float(splitline[5]) value1 = float(splitline[6]) value2 = float(splitline[7]) if self.UnNormalize ==1: value0 *= velocityUnNormalizationFactor value1 *= velocityUnNormalizationFactor value2 *= velocityUnNormalizationFactor outputArray.SetComponent(i,0,value0) outputArray.SetComponent(i,1,value1) outputArray.SetComponent(i,2,value2) self.Mesh.GetPointData().AddArray(outputArray) def ReadTetrVelFile(self,filename,arrayname): self.PrintLog('Reading '+filename+'.') if self.UnNormalize == 1: self.ReadTetrInDimensionalParameters() if (self.Compressed == 1): f=gzip.open(filename, 'r') else: f=open(filename, 'r') lines = f.readlines() line = lines[0] lineoffset = 1 splitline = line.split(' ') numberOfTuples = int(splitline[0]) iteration = float(splitline[1]) outputArray = vtk.vtkDoubleArray() outputArray.SetName(arrayname) outputArray.SetNumberOfComponents(3) outputArray.SetNumberOfTuples(numberOfTuples) velocityUnNormalizationFactor = self.ReD / (2.0 * self.Radius) * self.Viscosity / self.Density for i in range(numberOfTuples): line = lines[i+lineoffset] splitline = line.split(' ') value0 = float(splitline[0]) value1 = float(splitline[1]) value2 = float(splitline[2]) if self.UnNormalize ==1: value0 *= velocityUnNormalizationFactor value1 *= velocityUnNormalizationFactor value2 *= velocityUnNormalizationFactor outputArray.SetComponent(i,0,value0) outputArray.SetComponent(i,1,value1) outputArray.SetComponent(i,2,value2) self.Mesh.GetPointData().AddArray(outputArray) def ReadTetrWSSFile(self,filename,arrayname): self.PrintLog('Reading '+filename+'.') if self.UnNormalize == 1: self.ReadTetrInDimensionalParameters() if (self.Compressed == 1): f=gzip.open(filename, 'r') else: f=open(filename, 'r') lines = f.readlines() line = lines[1] lineoffset = 2 numberOfTuples = int(line) numberOfPoints = self.Mesh.GetNumberOfPoints() outputArray = vtk.vtkDoubleArray() outputArray.SetName(arrayname) outputArray.SetNumberOfComponents(3) outputArray.SetNumberOfTuples(numberOfPoints) outputArray.FillComponent(0,0.0) outputArray.FillComponent(1,0.0) outputArray.FillComponent(2,0.0) tetrinf=open(self.TetrInFileName, 'r') tetrinline = '' while tetrinline.strip() != '$wnode': tetrinline = tetrinf.readline() tetrinline = tetrinf.readline() wssUnNormalizationFactor = 4.0 * self.Viscosity * (self.ReD / (2.0 * self.Radius) * self.Viscosity / self.Density) / self.Radius for i in range(numberOfTuples): line = lines[i+lineoffset] splitline = line.split(' ') value0 = float(splitline[0]) value1 = float(splitline[1]) value2 = float(splitline[2]) if self.UnNormalize ==1: value0 *= wssUnNormalizationFactor value1 *= wssUnNormalizationFactor value2 *= wssUnNormalizationFactor tetrinline = tetrinf.readline() pointId = int(tetrinline.strip().split(' ')[1]) - 1 outputArray.SetComponent(pointId,0,value0) outputArray.SetComponent(pointId,1,value1) outputArray.SetComponent(pointId,2,value2) self.Mesh.GetPointData().AddArray(outputArray) def ReadTetrIniFile(self,filename,arrayname): self.PrintLog('Reading '+filename+'.') if (self.Compressed == 1): f=gzip.open(filename, 'r') else: f=open(filename, 'r') line = f.readline() while (line!='$vel_old1'): line = f.readline() line = f.readline() line = f.readline() numberOfTuples = int(line) outputArray = vtk.vtkDoubleArray() outputArray.SetName(arrayname) outputArray.SetNumberOfComponents(3) outputArray.SetNumberOfTuples(numberOfTuples) for i in range(numberOfTuples): line = f.readline() splitline = line.split(' ') value0 = float(splitline[0]) value1 = float(splitline[1]) value2 = float(splitline[2]) outputArray.SetComponent(i,0,value0) outputArray.SetComponent(i,1,value1) outputArray.SetComponent(i,2,value2) self.Mesh.GetPointData().AddArray(outputArray) def ReadPointDataFile(self,filename): self.PrintLog('Reading '+filename+'.') if (self.Compressed == 1): f=gzip.open(filename, 'r') else: f=open(filename, 'r') lines = f.readlines() line = lines[0] splitline = line.strip().split(' ') numberOfVariables = len(splitline) numberOfPoints = self.Mesh.GetNumberOfPoints() arrayNames = [] for i in range(numberOfVariables): arrayNames.append(filename+'_'+splitline[i]) if (self.MinVariableId != -1) & (i < self.MinVariableId): continue if (self.MaxVariableId != -1) & (i > self.MaxVariableId): continue outputArray = vtk.vtkDoubleArray() outputArray.SetName(arrayNames[i]) outputArray.SetNumberOfComponents(1) outputArray.SetNumberOfTuples(numberOfPoints) self.Mesh.GetPointData().AddArray(outputArray) pointId = 0 for i in range(1,len(lines)): line = lines[i] splitline = line.strip().split(' ') if len(splitline) != numberOfVariables: self.PrintError('Error: pointdata file corrupted.'); for j in range(numberOfVariables): if (self.MinVariableId != -1) & (i < self.MinVariableId): continue if (self.MaxVariableId != -1) & (i > self.MaxVariableId): continue self.Mesh.GetPointData().GetArray(arrayNames[j]).SetComponent(pointId,0,float(splitline[j])) pointId += 1 def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') dataFilenames = [] if not self.DataFileName: if self.DataFilePrefix == '': self.DataFilePrefix = self.DataFileType filenames = os.listdir(self.DataFileDirectory) for filename in filenames: if filename.find(self.DataFilePrefix) != -1: dataFilenames.append(filename) dataFilenames.sort() else: dataFilenames.append(self.DataFileName) for name in dataFilenames: filename = self.DataFileDirectory + '/' + name arrayname = self.ArrayNamePrefix + name if (self.DataFileType == 'tetr.out'): self.ReadTetrOutFile(filename,arrayname) elif (self.DataFileType == 'tetr.vel'): self.ReadTetrVelFile(filename,arrayname) elif (self.DataFileType == 'tetr.wss'): self.ReadTetrWSSFile(filename,arrayname) elif (self.DataFileType == 'tetr.ini'): self.ReadTetrIniFile(filename,arrayname) elif (self.DataFileType == 'pointdata'): if self.UnNormalize == 1: self.PrintError('Error: UnNormalize not supported for pointdata DataFileType.') self.ReadPointDataFile(filename) else: self.PrintError('Unsupported DataFileType.') if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtknetworkeditor.py0000664000175000017500000011343711757446472017665 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtknetworkeditor.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.3 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. ## Developed with support from the EC FP7/2007-2013: ARCH, Project n. 224390 import vtk import sys import vtkvmtk import vmtkrenderer import vmtkimageviewer import vmtkimagefeatures import pypes import vmtkactivetubes vmtknetworkeditor = 'vmtkNetworkEditor' class vmtkNetworkEditor(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Network = None self.RadiusArrayName = 'Radius' self.LabelsArrayName = 'Labels' self.SplineInterpolation = 1 self.UseActiveTubes = 0 self.NumberOfIterations = 100 self.PotentialWeight = 1.0 self.StiffnessWeight = 0.0 self.NetworkTube = None self.Selection = None self.SelectionPoints = None self.SelectionRadiusArray = None self.SelectionActor = None self.SelectedCellId = -1 self.SelectedSubId = -1 self.SelectedPCoords = 0.0 self.ActiveSegment = None self.ActiveSegmentPoints = None self.ActiveSegmentCellArray = None self.ActiveSegmentRadiusArray = None self.ActiveSegmentActor = None self.ActiveSegmentSeeds = None self.ActiveSegmentSeedsPoints = None self.ActiveSegmentSeedsRadiusArray = None self.ActiveSegmentSeedsActor = None self.AttachedCellIds = [-1,-1] self.AttachedSubIds = [-1,-1] self.AttachedPCoords = [0.0,0.0] self.PlaneWidgetX = None self.PlaneWidgetY = None self.PlaneWidgetZ = None self.Image = None self.FeatureImage = None self.CurrentRadius = 0.0 self.NetworkRadiusArray = None self.NetworkLabelsArray = None self.CellPicker = None self.CellIdsToMerge = [] self.OperationMode = None self.PickMode = 'image' self.vmtkRenderer = None self.OwnRenderer = 0 self.SetScriptName('vmtknetworkeditor') self.SetScriptDoc('') self.SetInputMembers([ ['Network','i','vtkPolyData',1,'','the input network','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,''], ['LabelsArrayName','labelsarray','str',1,''], ['SplineInterpolation','spline','bool',1,''], ['UseActiveTubes','activetubes','bool',1,''], ['NumberOfIterations','iterations','int',1,'(0,)'], ['PotentialWeight','potentialweight','float',1,'(0.0,)'], ['StiffnessWeight','stiffnessweight','float',1,'(0.0,)'], ['PlaneWidgetX','xplane','vtkImagePlaneWidget',1,'','the X image plane widget'], ['PlaneWidgetY','yplane','vtkImagePlaneWidget',1,'','the Y image plane widget'], ['PlaneWidgetZ','zplane','vtkImagePlaneWidget',1,'','the Z image plane widget'], ['Image','image','vtkImageData',1,'','','vmtkimagereader'], ['FeatureImage','featureimage','vtkImageData',1,'','','vmtkimagereader'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer']]) self.SetOutputMembers([ ['Network','o','vtkPolyData',1,'','the output network','vmtknetworkwriter'], ['RadiusArrayName','oradiusarray','str',1,''], ['Surface','osurface','vtkPolyData',1,'','the output surface','vmtksurfacewriter']]) def TogglePickMode(self): if self.PickMode == 'image': self.PickMode = 'network' else: self.PickMode = 'image' def TogglePlaneWidget(self,planeWidget): if not planeWidget: return interaction = planeWidget.GetInteraction() if interaction: planeWidget.InteractionOff() else: planeWidget.InteractionOn() def UpdateLabels(self): self.CellCenters.Modified() self.CellCenters.Update() self.Render() def ToggleLabels(self): if self.LabelsActor.GetVisibility() == 1: self.LabelsActor.VisibilityOff() else: self.LabelsActor.VisibilityOn() self.Render() def SetPickMode(self,pickMode): if pickMode == 'image': self.PickMode = 'image' if self.PlaneWidgetX: self.PlaneWidgetX.InteractionOn() if self.PlaneWidgetY: self.PlaneWidgetY.InteractionOn() if self.PlaneWidgetZ: self.PlaneWidgetZ.InteractionOn() elif pickMode == 'network': self.PickMode = 'network' if self.PlaneWidgetX: self.PlaneWidgetX.InteractionOff() if self.PlaneWidgetY: self.PlaneWidgetY.InteractionOff() if self.PlaneWidgetZ: self.PlaneWidgetZ.InteractionOff() def KeyReleaseCallback(self,obj,event): pass #key = object.GetKeySym() #if self.OperationMode == 'add': # if key == 'Shift_L' or key == 'Shift_R': # if self.PickMode == 'network': # self.SetPickMode('image') def CheckMenu(self): self.vmtkRenderer.RemoveKeyBinding('space') self.vmtkRenderer.RemoveKeyBinding('c') self.vmtkRenderer.RemoveKeyBinding('u') self.vmtkRenderer.RemoveKeyBinding('+') self.vmtkRenderer.RemoveKeyBinding('-') self.vmtkRenderer.RemoveKeyBinding('=') self.vmtkRenderer.RemoveKeyBinding('Return') def ShowLabelCallback(self, obj): self.ToggleLabels() def AddCallback(self, obj): self.InputInfo('Switched to add mode.\nCtrl + left click to add tubes.') #self.PrintLog('Add mode') self.OperationMode = 'add' self.InitializeActiveSegment() self.vmtkRenderer.AddKeyBinding('space','Toggle image/tube interaction',self.SpaceCallback, '2') self.vmtkRenderer.AddKeyBinding('c','Cancel',self.CancelCallback,'2') self.vmtkRenderer.AddKeyBinding('u','Undo',self.UndoCallback,'2') self.vmtkRenderer.AddKeyBinding('+','Increase radius',self.PlusCallback,'2') self.vmtkRenderer.AddKeyBinding('=','Increase radius',self.PlusCallback,'2') self.vmtkRenderer.AddKeyBinding('-','Decrease radius',self.MinusCallback,'2') self.vmtkRenderer.AddKeyBinding('Return','Accept tube',self.ReturnAddCallback,'2') self.UpdateAndRender() def DeleteCallback(self, obj): self.InputInfo('Switched to delete mode.\nCtrl + left click to delete tubes.') #self.PrintLog('Delete mode') self.OperationMode = 'delete' self.InitializeActiveSegment() self.CheckMenu() if self.PickMode == 'image': self.SetPickMode('network') self.InitializeActiveSegment() self.UpdateAndRender() def SplitCallback(self, obj): self.InputInfo('Switched to split mode.\nCtrl + left click to split tubes.') #self.PrintLog('Split mode') self.OperationMode = 'split' self.InitializeActiveSegment() self.CheckMenu() if self.PickMode == 'image': self.SetPickMode('network') self.InitializeActiveSegment() self.UpdateAndRender() def LabelCallback(self, obj): #self.PrintLog('Label mode') self.InputInfo('Switched to label mode.\nCtrl + left click to add label.') self.OperationMode = 'label' self.InitializeActiveSegment() self.CheckMenu() if self.PickMode == 'image': self.SetPickMode('network') self.InitializeActiveSegment() self.UpdateAndRender() def MergeCallback(self, obj): self.InputInfo('Switched to merge mode.\nCtrl + left click to select two tubes to merge.') #self.PrintLog('Merge mode') self.OperationMode = 'merge' self.InitializeActiveSegment() self.CheckMenu() if self.PickMode == 'image': self.SetPickMode('network') self.InitializeActiveSegment() self.CellIdsToMerge = [] self.vmtkRenderer.AddKeyBinding('Return','Accept merge',self.ReturnCallback,'2') self.UpdateAndRender() def SpaceCallback(self, obj): self.TogglePickMode() self.TogglePlaneWidget(self.PlaneWidgetX) self.TogglePlaneWidget(self.PlaneWidgetY) self.TogglePlaneWidget(self.PlaneWidgetZ) self.InputInfo('Ctrl + left click to add seeds.') def CancelCallback(self, obj): self.InitializeActiveSegment() def UndoCallback(self, obj): numberOfSeeds = self.ActiveSegmentSeedsPoints.GetNumberOfPoints() if numberOfSeeds > 0: self.ActiveSegmentSeedsPoints.SetNumberOfPoints(numberOfSeeds-1) self.ActiveSegmentSeedsRadiusArray.SetNumberOfValues(numberOfSeeds-1) self.ActiveSegmentSeeds.Modified() self.AttachedCellIds[1] = -1 self.AttachedSubIds[1] = -1 self.AttachedPCoords[1] = 0.0 else: self.AttachedCellIds[0] = -1 self.AttachedSubIds[0] = -1 self.AttachedPCoords[0] = 0.0 numberOfPoints = self.ActiveSegmentPoints.GetNumberOfPoints() if numberOfPoints > 2: self.ActiveSegmentPoints.SetNumberOfPoints(numberOfPoints-1) self.ActiveSegmentRadiusArray.SetNumberOfValues(numberOfPoints-1) self.ActiveSegmentCellArray.Initialize() self.ActiveSegmentCellArray.InsertNextCell(numberOfPoints-1) for i in range(numberOfPoints-1): self.ActiveSegmentCellArray.InsertCellPoint(i) self.ActiveSegment.Modified() else: self.ActiveSegmentPoints.SetNumberOfPoints(0) self.ActiveSegmentCellArray.Initialize() self.ActiveSegmentRadiusArray.SetNumberOfValues(0) self.ActiveSegment.Modified() self.UpdateAndRender() def PlusCallback(self, obj): numberOfSeeds = self.ActiveSegmentSeedsPoints.GetNumberOfPoints() if numberOfSeeds > 0: radius = self.ActiveSegmentSeedsRadiusArray.GetValue(numberOfSeeds-1) radius += 0.1 self.ActiveSegmentSeedsRadiusArray.SetValue(numberOfSeeds-1,radius) self.CurrentRadius = radius self.ActiveSegmentSeeds.Modified() numberOfPoints = self.ActiveSegmentPoints.GetNumberOfPoints() if numberOfPoints > 0: radius = self.ActiveSegmentRadiusArray.GetValue(numberOfPoints-1) radius += 0.1 self.ActiveSegmentRadiusArray.SetValue(numberOfPoints-1,radius) self.ActiveSegment.Modified() self.UpdateAndRender() def MinusCallback(self, obj): numberOfSeeds = self.ActiveSegmentSeedsPoints.GetNumberOfPoints() if numberOfSeeds > 0: radius = self.ActiveSegmentSeedsRadiusArray.GetValue(numberOfSeeds-1) radius -= 0.1 if radius > 0.0: self.ActiveSegmentSeedsRadiusArray.SetValue(numberOfSeeds-1,radius) self.CurrentRadius = radius self.ActiveSegmentSeeds.Modified() numberOfPoints = self.ActiveSegmentPoints.GetNumberOfPoints() if numberOfPoints > 0: radius = self.ActiveSegmentRadiusArray.GetValue(numberOfPoints-1) radius -= 0.1 if radius > 0.0: self.ActiveSegmentRadiusArray.SetValue(numberOfPoints-1,radius) self.ActiveSegment.Modified() self.UpdateAndRender() def ReturnAddCallback(self, obj): attachedPointId0 = -1 attachedPointId1 = -1 cellIdsToRemove = [] if self.AttachedCellIds[0] != -1: attachedPointId0, hasSplit = self.SplitCellNoRemove(self.AttachedCellIds[0],self.AttachedSubIds[0],self.AttachedPCoords[0]) if hasSplit: cellIdsToRemove.append(self.AttachedCellIds[0]) if self.AttachedCellIds[1] != -1: attachedPointId1, hasSplit = self.SplitCellNoRemove(self.AttachedCellIds[1],self.AttachedSubIds[1],self.AttachedPCoords[1]) if hasSplit: cellIdsToRemove.append(self.AttachedCellIds[1]) if cellIdsToRemove: self.RemoveCells(cellIdsToRemove) segment = self.ActiveSegmentActor.GetMapper().GetInput() if self.UseActiveTubes: self.RunActiveTube(segment) segmentRadiusArray = segment.GetPointData().GetArray(self.RadiusArrayName) numberOfSegmentPoints = segment.GetNumberOfPoints() networkPoints = self.Network.GetPoints() networkCellArray = self.Network.GetLines() cellId = networkCellArray.InsertNextCell(numberOfSegmentPoints) for i in range(numberOfSegmentPoints): id = -1 if i == 0 and attachedPointId0 != -1: id = attachedPointId0 elif i == numberOfSegmentPoints-1 and attachedPointId1 != -1: id = attachedPointId1 else: id = networkPoints.InsertNextPoint(segment.GetPoint(i)) self.NetworkRadiusArray.InsertTuple1(id,segmentRadiusArray.GetTuple1(i)) networkCellArray.InsertCellPoint(id) self.NetworkLabelsArray.InsertValue(cellId,'') self.Network.BuildCells() self.Network.Modified() self.NetworkTube.Modified() self.UpdateLabels() #if self.Image and self.PickMode == 'network': # self.SetPickMode('image') self.InitializeSelection() self.InitializeActiveSegment() def ReturnCallback(self, obj): numberOfActiveCells = self.ActiveSegment.GetNumberOfCells() if numberOfActiveCells != 2 or len(self.CellIdsToMerge) != 2: return cell0ToMerge = self.Network.GetCell(self.CellIdsToMerge[0]) cell0PointIds = vtk.vtkIdList() cell0PointIds.DeepCopy(cell0ToMerge.GetPointIds()) numberOfCell0Points = cell0PointIds.GetNumberOfIds() cell1ToMerge = self.Network.GetCell(self.CellIdsToMerge[1]) cell1PointIds = vtk.vtkIdList() cell1PointIds.DeepCopy(cell1ToMerge.GetPointIds()) numberOfCell1Points = cell1PointIds.GetNumberOfIds() reverse = [False,False] if cell0PointIds.GetId(numberOfCell0Points-1) == cell1PointIds.GetId(0): reverse = [False,False] elif cell0PointIds.GetId(numberOfCell0Points-1) == cell1PointIds.GetId(numberOfCell1Points-1): reverse = [False,True] elif cell0PointIds.GetId(0) == cell1PointIds.GetId(numberOfCell1Points-1): reverse = [True,True] elif cell0PointIds.GetId(0) == cell1PointIds.GetId(0): reverse = [True,False] else: self.PrintLog('Error: trying to merge non-adjacent segments.') return mergedLabel = self.NetworkLabelsArray.GetValue(self.CellIdsToMerge[0]) self.RemoveCells(self.CellIdsToMerge) networkCellArray = self.Network.GetLines() cellId = networkCellArray.InsertNextCell(numberOfCell0Points+numberOfCell1Points-1) for i in range(numberOfCell0Points): loc = i if reverse[0]: loc = numberOfCell0Points - 1 - i networkCellArray.InsertCellPoint(cell0PointIds.GetId(loc)) for i in range(1,numberOfCell1Points): loc = i if reverse[1]: loc = numberOfCell1Points - 1 - i networkCellArray.InsertCellPoint(cell1PointIds.GetId(loc)) self.NetworkLabelsArray.InsertValue(cellId,mergedLabel) self.Network.SetLines(networkCellArray) self.Network.BuildCells() self.Network.Modified() self.NetworkTube.Modified() self.UpdateLabels() self.InitializeActiveSegment() self.CellIdsToMerge = [] def RemoveCell(self,cellId): self.RemoveCells([cellId]) def RemoveCells(self,cellIds): networkCellArray = vtk.vtkCellArray() networkLabelsArray = vtk.vtkStringArray() numberOfCells = self.Network.GetNumberOfCells() for i in range(numberOfCells): if i in cellIds: continue networkCellArray.InsertNextCell(self.Network.GetCell(i)) networkLabelsArray.InsertNextValue(self.NetworkLabelsArray.GetValue(i)) self.Network.SetLines(networkCellArray) self.NetworkLabelsArray.DeepCopy(networkLabelsArray) self.Network.BuildCells() self.Network.Modified() def SplitCell(self,cellId,subId,pcoord): splitPointId, hasSplit = self.SplitCellNoRemove(cellId,subId,pcoord) if hasSplit: self.RemoveCell(cellId) return splitPointId, hasSplit def SplitCellNoRemove(self,cellId,subId,pcoord): splitId = subId if pcoord > 0.5: splitId = subId+1 cell = self.Network.GetCell(cellId) label = self.NetworkLabelsArray.GetValue(cellId) numberOfCellPoints = cell.GetNumberOfPoints() cellPointIds = cell.GetPointIds() splitPointId = cellPointIds.GetId(splitId) if splitId == 0 or splitId == numberOfCellPoints-1: return splitPointId, False lines = self.Network.GetLines() newCellId1 = lines.InsertNextCell(splitId+1) for i in range(splitId+1): lines.InsertCellPoint(cellPointIds.GetId(i)) newCellId2 = lines.InsertNextCell(numberOfCellPoints-splitId) for i in range(splitId,numberOfCellPoints): lines.InsertCellPoint(cellPointIds.GetId(i)) newLabel1 = '' newLabel2 = '' if label: newLabel1 = label + "1" newLabel2 = label + "2" self.NetworkLabelsArray.InsertValue(newCellId1,newLabel1) self.NetworkLabelsArray.InsertValue(newCellId2,newLabel2) self.Network.BuildCells() return splitPointId, True def LeftButtonPressCallback(self,obj,event): if self.PickMode != 'network': return if self.vmtkRenderer.RenderWindowInteractor.GetControlKey() == 0: return if self.Network.GetNumberOfCells() == 0: return cellId = self.SelectedCellId if cellId == -1: return subId = self.SelectedSubId pcoords = self.SelectedPCoords cell = self.Network.GetCell(cellId) if pcoords < 0.5: pointId = cell.GetPointIds().GetId(subId) else: pointId = cell.GetPointIds().GetId(subId+1) point = self.Network.GetPoint(pointId) radius = self.NetworkRadiusArray.GetValue(pointId) if self.OperationMode == 'add': if radius == 0.0: radius = 1.0 if self.ActiveSegmentSeeds.GetNumberOfPoints() == 0: self.ActiveSegmentSeedsPoints.InsertNextPoint(point) self.ActiveSegmentSeedsRadiusArray.InsertNextValue(radius) self.ActiveSegmentSeeds.Modified() self.AttachedCellIds[0] = cellId self.AttachedSubIds[0] = subId self.AttachedPCoords[0] = pcoords self.Render() return if self.AttachedCellIds[1] != -1: return self.AttachedCellIds[1] = cellId self.AttachedSubIds[1] = subId self.AttachedPCoords[1] = pcoords if self.ActiveSegmentPoints.GetNumberOfPoints() == 0: self.ActiveSegmentPoints.InsertNextPoint(self.ActiveSegmentSeedsPoints.GetPoint(0)) self.ActiveSegmentRadiusArray.InsertNextValue(self.ActiveSegmentSeedsRadiusArray.GetValue(0)) self.ActiveSegmentSeedsPoints.InsertNextPoint(point) self.ActiveSegmentSeedsRadiusArray.InsertNextValue(radius) self.ActiveSegmentSeeds.Modified() self.ActiveSegmentPoints.InsertNextPoint(point) self.ActiveSegmentRadiusArray.InsertNextValue(radius) self.ActiveSegmentCellArray.Initialize() numberOfPoints = self.ActiveSegmentPoints.GetNumberOfPoints() self.ActiveSegmentCellArray.InsertNextCell(numberOfPoints) for i in range(numberOfPoints): self.ActiveSegmentCellArray.InsertCellPoint(i) self.ActiveSegment.Modified() self.Render() elif self.OperationMode == 'delete': self.InitializeSelection() self.RemoveCell(cellId) self.NetworkTube.Modified() self.UpdateLabels() elif self.OperationMode == 'split': numberOfCellPoints = cell.GetNumberOfPoints() self.SplitCell(cellId,subId,pcoords) self.NetworkTube.Modified() self.UpdateLabels() elif self.OperationMode == 'label': self.LabelCellId = cellId label = self.NetworkLabelsArray.GetValue(cellId) if label: self.PrintLog("Current label: %s" % label) self.vmtkRenderer.PromptAsync("Please input new label: ",self.QueryLabelCallback) elif self.OperationMode == 'merge': if self.ActiveSegment.GetNumberOfCells() > 1: self.InitializeActiveSegment() self.CellIdsToMerge = [] self.CellIdsToMerge.append(cellId) numberOfCellPoints = cell.GetNumberOfPoints() activePointIds = [] for i in range(numberOfCellPoints): pointId = cell.GetPointId(i) point = self.Network.GetPoint(pointId) radius = self.NetworkRadiusArray.GetTuple1(pointId) activePointId = self.ActiveSegmentPoints.InsertNextPoint(point) self.ActiveSegmentRadiusArray.InsertNextValue(radius) activePointIds.append(activePointId) self.ActiveSegmentCellArray.InsertNextCell(numberOfCellPoints) for i in range(numberOfCellPoints): self.ActiveSegmentCellArray.InsertCellPoint(activePointIds[i]) self.ActiveSegment.Modified() self.NetworkTube.Modified() self.Render() def QueryLabelCallback(self,newLabel): self.NetworkLabelsArray.SetValue(self.LabelCellId,newLabel) self.LabelCellId = None self.InitializeSelection() self.Network.Modified() self.UpdateLabels() def InitializeSelection(self): self.SelectionPoints.SetNumberOfPoints(0) self.SelectionRadiusArray.SetNumberOfValues(0) self.SelectedCellId = -1 self.SelectedSubId = -1 self.SelectedPCoords = 0.0 self.Selection.Modified() self.Render() def InitializeActiveSegment(self): self.ActiveSegmentSeedsPoints.SetNumberOfPoints(0) self.ActiveSegmentSeedsRadiusArray.SetNumberOfValues(0) self.ActiveSegmentSeeds.Modified() self.ActiveSegmentPoints.SetNumberOfPoints(0) self.ActiveSegmentCellArray.Initialize() self.ActiveSegmentCellArray.SetNumberOfCells(0) self.ActiveSegmentRadiusArray.SetNumberOfValues(0) self.ActiveSegment.Modified() self.AttachedCellIds = [-1,-1] self.AttachedSubIds = [-1,-1] self.AttachedPCoords = [0.0,0.0] self.Render() def MouseMoveCallback(self,obj,event): if self.PickMode != 'network': return if self.vmtkRenderer.RenderWindowInteractor.GetControlKey() == 0: if self.SelectedCellId != -1: self.InitializeSelection() return if self.Network.GetNumberOfCells() == 0: return eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() result = self.CellPicker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: return cellId = self.CellPicker.GetCellId() cell = self.Network.GetCell(cellId) subId = self.CellPicker.GetSubId() pcoords = self.CellPicker.GetPCoords()[0] if pcoords < 0.5: pointId = cell.GetPointIds().GetId(subId) else: pointId = cell.GetPointIds().GetId(subId+1) if self.vmtkRenderer.RenderWindowInteractor.GetShiftKey() == 1: if subId < cell.GetNumberOfPoints()/2: pointId = cell.GetPointIds().GetId(0) else: pointId = cell.GetPointIds().GetId(cell.GetNumberOfPoints()-1) point = self.Network.GetPoint(pointId) radius = self.NetworkRadiusArray.GetValue(pointId) if radius == 0.0: radius = 1.0 self.SelectionPoints.InsertPoint(0,point) self.SelectionRadiusArray.InsertValue(0,radius) self.SelectedCellId = cellId self.SelectedSubId = subId self.SelectedPCoords = pcoords self.Selection.Modified() self.Render() def PlaneStartInteractionCallback(self,obj,event): if self.PickMode != 'image': return if self.OperationMode != 'add': return if self.vmtkRenderer.RenderWindowInteractor.GetControlKey() == 0: return point = obj.GetCurrentCursorPosition() radius = self.CurrentRadius if self.ActiveSegmentSeeds.GetNumberOfPoints() == 0: self.ActiveSegmentSeedsPoints.InsertNextPoint(point) self.ActiveSegmentSeedsRadiusArray.InsertNextValue(radius) self.ActiveSegmentSeeds.Modified() self.Render() return if self.AttachedCellIds[1] != -1: return if self.ActiveSegmentPoints.GetNumberOfPoints() == 0: self.ActiveSegmentPoints.InsertNextPoint(self.ActiveSegmentSeedsPoints.GetPoint(0)) self.ActiveSegmentRadiusArray.InsertNextValue(self.ActiveSegmentSeedsRadiusArray.GetValue(0)) self.ActiveSegmentSeedsPoints.InsertNextPoint(point) self.ActiveSegmentSeedsRadiusArray.InsertNextValue(radius) self.ActiveSegmentSeeds.Modified() self.ActiveSegmentPoints.InsertNextPoint(point) self.ActiveSegmentRadiusArray.InsertNextValue(radius) self.ActiveSegmentCellArray.Initialize() numberOfPoints = self.ActiveSegmentPoints.GetNumberOfPoints() self.ActiveSegmentCellArray.InsertNextCell(numberOfPoints) for i in range(numberOfPoints): self.ActiveSegmentCellArray.InsertCellPoint(i) self.ActiveSegment.Modified() self.Render() def FirstRender(self): self.vmtkRenderer.Render() def Render(self): self.vmtkRenderer.RenderWindow.Render() def UpdateAndRender(self): self.vmtkRenderer.Render(interactive=0) def RunActiveTube(self,segment): activeTubes = vmtkactivetubes.vmtkActiveTubes() activeTubes.Centerline = segment activeTubes.Image = self.FeatureImage activeTubes.NumberOfIterations = self.NumberOfIterations activeTubes.PotentialWeight = self.PotentialWeight activeTubes.StiffnessWeight = self.StiffnessWeight activeTubes.RadiusArrayName = self.RadiusArrayName activeTubes.Execute() segment.DeepCopy(activeTubes.Centerline) def Execute(self): if not self.Network: self.Network = vtk.vtkPolyData() networkPoints = vtk.vtkPoints() networkLines = vtk.vtkCellArray() radiusArray = vtk.vtkDoubleArray() radiusArray.SetName(self.RadiusArrayName) self.Network.SetPoints(networkPoints) self.Network.SetLines(networkLines) self.Network.GetPointData().AddArray(radiusArray) if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.ExitAfterTextInputMode = False self.vmtkRenderer.RegisterScript(self) if self.Image and (not self.PlaneWidgetX or not self.PlaneWidgetY or not self.PlaneWidgetZ): imageViewer = vmtkimageviewer.vmtkImageViewer() imageViewer.Image = self.Image imageViewer.vmtkRenderer = self.vmtkRenderer imageViewer.Display = 0 imageViewer.Execute() self.PlaneWidgetX = imageViewer.PlaneWidgetX self.PlaneWidgetY = imageViewer.PlaneWidgetY self.PlaneWidgetZ = imageViewer.PlaneWidgetZ if self.Image: spacing = self.Image.GetSpacing() self.CurrentRadius = min(spacing) if self.UseActiveTubes and not self.FeatureImage: imageFeatures = vmtkimagefeatures.vmtkImageFeatures() imageFeatures.Image = self.Image imageFeatures.FeatureImageType = 'vtkgradient' imageFeatures.Execute() self.FeatureImage = imageFeatures.FeatureImage self.NetworkRadiusArray = self.Network.GetPointData().GetArray(self.RadiusArrayName) self.Network.GetPointData().SetActiveScalars(self.RadiusArrayName) networkMapper = vtk.vtkPolyDataMapper() networkMapper.SetInput(self.Network) networkMapper.SetScalarModeToUseCellData() self.NetworkActor = vtk.vtkActor() self.NetworkActor.SetMapper(networkMapper) self.vmtkRenderer.Renderer.AddActor(self.NetworkActor) self.NetworkTube = vtk.vtkTubeFilter() self.NetworkTube.SetInput(self.Network) self.NetworkTube.SetVaryRadiusToVaryRadiusByAbsoluteScalar() self.NetworkTube.SetNumberOfSides(20) networkTubeMapper = vtk.vtkPolyDataMapper() networkTubeMapper.SetInput(self.NetworkTube.GetOutput()) networkTubeMapper.ScalarVisibilityOff() networkTubeActor = vtk.vtkActor() networkTubeActor.SetMapper(networkTubeMapper) networkTubeActor.PickableOff() networkTubeActor.GetProperty().SetOpacity(0.2) self.vmtkRenderer.Renderer.AddActor(networkTubeActor) self.Selection = vtk.vtkPolyData() self.SelectionPoints = vtk.vtkPoints() self.SelectionRadiusArray = vtk.vtkDoubleArray() self.SelectionRadiusArray.SetName(self.RadiusArrayName) self.Selection.SetPoints(self.SelectionPoints) self.Selection.GetPointData().AddArray(self.SelectionRadiusArray) self.Selection.GetPointData().SetActiveScalars(self.RadiusArrayName) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphSource.SetRadius(1.0) glyphSource.SetThetaResolution(20) glyphSource.SetPhiResolution(20) glyphs.SetInput(self.Selection) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToScaleByScalar() glyphs.SetScaleFactor(1.0) selectionMapper = vtk.vtkPolyDataMapper() selectionMapper.SetInput(glyphs.GetOutput()) self.SelectionActor = vtk.vtkActor() self.SelectionActor.SetMapper(selectionMapper) self.SelectionActor.GetProperty().SetColor(1.0,0.0,0.0) self.SelectionActor.GetProperty().SetOpacity(0.5) self.SelectionActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.SelectionActor) self.ActiveSegmentSeeds = vtk.vtkPolyData() self.ActiveSegmentSeedsPoints = vtk.vtkPoints() self.ActiveSegmentSeedsRadiusArray = vtk.vtkDoubleArray() self.ActiveSegmentSeedsRadiusArray.SetName(self.RadiusArrayName) self.ActiveSegmentSeeds.SetPoints(self.ActiveSegmentSeedsPoints) self.ActiveSegmentSeeds.GetPointData().AddArray(self.ActiveSegmentSeedsRadiusArray) self.ActiveSegmentSeeds.GetPointData().SetActiveScalars(self.RadiusArrayName) activeSegmentSeedsGlyphs = vtk.vtkGlyph3D() activeSegmentSeedsGlyphSource = vtk.vtkSphereSource() activeSegmentSeedsGlyphSource.SetRadius(1.0) activeSegmentSeedsGlyphSource.SetThetaResolution(20) activeSegmentSeedsGlyphSource.SetPhiResolution(20) activeSegmentSeedsGlyphs.SetInput(self.ActiveSegmentSeeds) activeSegmentSeedsGlyphs.SetSource(activeSegmentSeedsGlyphSource.GetOutput()) activeSegmentSeedsGlyphs.SetScaleModeToScaleByScalar() activeSegmentSeedsGlyphs.SetScaleFactor(1.0) activeSegmentSeedsMapper = vtk.vtkPolyDataMapper() activeSegmentSeedsMapper.SetInput(activeSegmentSeedsGlyphs.GetOutput()) activeSegmentSeedsMapper.ScalarVisibilityOff() self.ActiveSegmentSeedsActor = vtk.vtkActor() self.ActiveSegmentSeedsActor.SetMapper(activeSegmentSeedsMapper) self.ActiveSegmentSeedsActor.GetProperty().SetColor(1.0,0.0,0.0) self.ActiveSegmentSeedsActor.GetProperty().SetOpacity(0.5) self.ActiveSegmentSeedsActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.ActiveSegmentSeedsActor) self.ActiveSegment = vtk.vtkPolyData() self.ActiveSegmentPoints = vtk.vtkPoints() self.ActiveSegmentCellArray = vtk.vtkCellArray() self.ActiveSegmentRadiusArray = vtk.vtkDoubleArray() self.ActiveSegmentRadiusArray.SetName(self.RadiusArrayName) self.ActiveSegment.SetPoints(self.ActiveSegmentPoints) self.ActiveSegment.SetLines(self.ActiveSegmentCellArray) self.ActiveSegment.GetPointData().AddArray(self.ActiveSegmentRadiusArray) self.ActiveSegment.GetPointData().SetActiveScalars(self.RadiusArrayName) activeSegmentMapper = vtk.vtkPolyDataMapper() activeSegmentMapper.ScalarVisibilityOff() if self.SplineInterpolation and self.Image != None: splineFilter = vtk.vtkSplineFilter() splineFilter.SetInput(self.ActiveSegment) splineFilter.SetSubdivideToLength() splineFilter.SetLength(2.0*min(self.Image.GetSpacing())) activeSegmentMapper.SetInput(splineFilter.GetOutput()) else: activeSegmentMapper.SetInput(self.ActiveSegment) self.ActiveSegmentActor = vtk.vtkActor() self.ActiveSegmentActor.SetMapper(activeSegmentMapper) self.ActiveSegmentActor.GetProperty().SetColor(1.0,1.0,1.0) self.ActiveSegmentActor.GetProperty().SetLineWidth(3.0) self.ActiveSegmentActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.ActiveSegmentActor) activeTube = vtk.vtkTubeFilter() activeTube.SetInput(activeSegmentMapper.GetInput()) activeTube.SetVaryRadiusToVaryRadiusByAbsoluteScalar() activeTube.SetNumberOfSides(20) activeTubeMapper = vtk.vtkPolyDataMapper() activeTubeMapper.SetInput(activeTube.GetOutput()) activeTubeMapper.ScalarVisibilityOff() activeTubeActor = vtk.vtkActor() activeTubeActor.SetMapper(activeTubeMapper) activeTubeActor.PickableOff() activeTubeActor.GetProperty().SetOpacity(0.6) self.vmtkRenderer.Renderer.AddActor(activeTubeActor) self.NetworkLabelsArray = vtk.vtkStringArray.SafeDownCast(self.Network.GetCellData().GetAbstractArray(self.LabelsArrayName)) if not self.NetworkLabelsArray: self.NetworkLabelsArray = vtk.vtkStringArray() self.NetworkLabelsArray.SetName(self.LabelsArrayName) self.NetworkLabelsArray.SetNumberOfValues(self.Network.GetNumberOfCells()) for i in range(self.Network.GetNumberOfCells()): self.NetworkLabelsArray.SetValue(i,'') self.Network.GetCellData().AddArray(self.NetworkLabelsArray) self.CellCenters = vtk.vtkCellCenters() self.CellCenters.SetInput(self.Network) self.CellCenters.VertexCellsOff() self.CellCenters.Update() labeledMapper = vtk.vtkLabeledDataMapper() labeledMapper.SetInput(self.CellCenters.GetOutput()) labeledMapper.SetLabelModeToLabelFieldData() labeledMapper.SetFieldDataName(self.LabelsArrayName) labeledMapper.GetLabelTextProperty().SetFontFamilyToArial() labeledMapper.GetLabelTextProperty().BoldOff() labeledMapper.GetLabelTextProperty().ItalicOff() labeledMapper.GetLabelTextProperty().ShadowOff() self.LabelsActor = vtk.vtkActor2D() self.LabelsActor.SetMapper(labeledMapper) self.LabelsActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.LabelsActor) self.CellPicker = vtk.vtkCellPicker() self.CellPicker.SetTolerance(1E-2) self.CellPicker.InitializePickList() self.CellPicker.AddPickList(self.NetworkActor) self.CellPicker.PickFromListOn() self.vmtkRenderer.AddKeyBinding('a','Add mode.',self.AddCallback) self.vmtkRenderer.AddKeyBinding('d','Delete mode.',self.DeleteCallback) self.vmtkRenderer.AddKeyBinding('m','Merge mode.',self.MergeCallback) self.vmtkRenderer.AddKeyBinding('s','Split mode.',self.SplitCallback) self.vmtkRenderer.AddKeyBinding('l','Label mode.',self.LabelCallback) self.vmtkRenderer.AddKeyBinding('Tab','Show labels.',self.ShowLabelCallback) self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyReleaseEvent", self.KeyReleaseCallback) self.vmtkRenderer.RenderWindowInteractor.AddObserver("LeftButtonPressEvent", self.LeftButtonPressCallback) self.vmtkRenderer.RenderWindowInteractor.AddObserver("MouseMoveEvent", self.MouseMoveCallback) if self.PlaneWidgetX: self.PlaneWidgetX.UseContinuousCursorOn() self.PlaneWidgetX.AddObserver("StartInteractionEvent", self.PlaneStartInteractionCallback) if self.PlaneWidgetY: self.PlaneWidgetY.UseContinuousCursorOn() self.PlaneWidgetY.AddObserver("StartInteractionEvent", self.PlaneStartInteractionCallback) if self.PlaneWidgetZ: self.PlaneWidgetZ.UseContinuousCursorOn() self.PlaneWidgetZ.AddObserver("StartInteractionEvent", self.PlaneStartInteractionCallback) self.FirstRender() self.Surface = self.NetworkTube.GetOutput() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkflowextensions.py0000664000175000017500000001721211757446472020046 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkflowextensions.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:52:56 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import pypes import vmtkrenderer vmtkflowextensions = 'vmtkFlowExtensions' class vmtkFlowExtensions(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.AdaptiveExtensionLength = 0 self.AdaptiveExtensionRadius = 1 self.AdaptiveNumberOfBoundaryPoints = 0 self.ExtensionLength = 1.0 self.ExtensionRatio = 10.0 self.ExtensionRadius = 1.0 self.TransitionRatio = 0.25 self.TargetNumberOfBoundaryPoints = 50 self.CenterlineNormalEstimationDistanceRatio = 1.0 self.ExtensionMode = "centerlinedirection" self.InterpolationMode = "thinplatespline" self.Interactive = 1 self.Sigma = 1.0 self.vmtkRenderer = None self.OwnRenderer = 0 self.SetScriptName('vmtkflowextensions') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['ExtensionMode','extensionmode','str',1,'["centerlinedirection","boundarynormal"]','method for computing the normal for extension'], ['InterpolationMode','interpolationmode','str',1,'["linear","thinplatespline"]','method for computing interpolation from the model section to a circular section'], ['Sigma','sigma','float',1,'(0.0,)','thin plate spline stiffness'], ['AdaptiveExtensionLength','adaptivelength','bool',1], ['AdaptiveExtensionRadius','adaptiveradius','bool',1], ['AdaptiveNumberOfBoundaryPoints','adaptivepoints','bool',1], ['ExtensionLength','extensionlength','float',1,'(0.0,)'], ['ExtensionRatio','extensionratio','float',1,'(0.0,)'], ['ExtensionRadius','extensionradius','float',1,'(0.0,)'], ['TransitionRatio','transitionratio','float',1,'(0.0,)'], ['TargetNumberOfBoundaryPoints','boundarypoints','int',1,'(0,)'], ['Interactive','interactive','bool',1], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['CenterlineNormalEstimationDistanceRatio','normalestimationratio','float',1,'(0.0,)'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['Centerlines','centerlines','vtkPolyData',1] ]) def LabelValidator(self,text): import string if not text: return 0 if not text.split(): return 0 for char in text: if char not in string.digits + " ": return 0 return 1 def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.ExtensionMode == "centerlinedirection" and self.Centerlines == None: self.PrintError('Error: No input centerlines.') boundaryIds = vtk.vtkIdList() if self.Interactive: if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) boundaryExtractor = vtkvmtk.vtkvmtkPolyDataBoundaryExtractor() boundaryExtractor.SetInput(self.Surface) boundaryExtractor.Update() boundaries = boundaryExtractor.GetOutput() numberOfBoundaries = boundaries.GetNumberOfCells() seedPoints = vtk.vtkPoints() for i in range(numberOfBoundaries): barycenter = [0.0, 0.0, 0.0] vtkvmtk.vtkvmtkBoundaryReferenceSystems.ComputeBoundaryBarycenter(boundaries.GetCell(i).GetPoints(),barycenter) seedPoints.InsertNextPoint(barycenter) seedPolyData = vtk.vtkPolyData() seedPolyData.SetPoints(seedPoints) seedPolyData.Update() labelsMapper = vtk.vtkLabeledDataMapper(); labelsMapper.SetInput(seedPolyData) labelsMapper.SetLabelModeToLabelIds() labelsActor = vtk.vtkActor2D() labelsActor.SetMapper(labelsMapper) self.vmtkRenderer.Renderer.AddActor(labelsActor) surfaceMapper = vtk.vtkPolyDataMapper() surfaceMapper.SetInput(self.Surface) surfaceMapper.ScalarVisibilityOff() surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(surfaceMapper) surfaceActor.GetProperty().SetOpacity(0.25) self.vmtkRenderer.Renderer.AddActor(surfaceActor) #self.vmtkRenderer.Render() #self.vmtkRenderer.Renderer.RemoveActor(labelsActor) #self.vmtkRenderer.Renderer.RemoveActor(surfaceActor) ok = False while not ok: labelString = self.InputText("Please input boundary ids: ",self.LabelValidator) labels = [int(label) for label in labelString.split()] ok = True for label in labels: if label not in range(numberOfBoundaries): ok = False for label in labels: boundaryIds.InsertNextId(label) flowExtensionsFilter = vtkvmtk.vtkvmtkPolyDataFlowExtensionsFilter() flowExtensionsFilter.SetInput(self.Surface) flowExtensionsFilter.SetCenterlines(self.Centerlines) flowExtensionsFilter.SetSigma(self.Sigma) flowExtensionsFilter.SetAdaptiveExtensionLength(self.AdaptiveExtensionLength) flowExtensionsFilter.SetAdaptiveExtensionRadius(self.AdaptiveExtensionRadius) flowExtensionsFilter.SetAdaptiveNumberOfBoundaryPoints(self.AdaptiveNumberOfBoundaryPoints) flowExtensionsFilter.SetExtensionLength(self.ExtensionLength) flowExtensionsFilter.SetExtensionRatio(self.ExtensionRatio) flowExtensionsFilter.SetExtensionRadius(self.ExtensionRadius) flowExtensionsFilter.SetTransitionRatio(self.TransitionRatio) flowExtensionsFilter.SetCenterlineNormalEstimationDistanceRatio(self.CenterlineNormalEstimationDistanceRatio) flowExtensionsFilter.SetNumberOfBoundaryPoints(self.TargetNumberOfBoundaryPoints) if self.ExtensionMode == "centerlinedirection": flowExtensionsFilter.SetExtensionModeToUseCenterlineDirection() elif self.ExtensionMode == "boundarynormal": flowExtensionsFilter.SetExtensionModeToUseNormalToBoundary() if self.InterpolationMode == "linear": flowExtensionsFilter.SetInterpolationModeToLinear() elif self.InterpolationMode == "thinplatespline": flowExtensionsFilter.SetInterpolationModeToThinPlateSpline() if self.Interactive: flowExtensionsFilter.SetBoundaryIds(boundaryIds) flowExtensionsFilter.Update() self.Surface = flowExtensionsFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtktetgen.py0000664000175000017500000001574711757446472016260 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtktetgen.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import vtk import vtkvmtk import pypes vmtktetgen = 'vmtkTetGen' class vmtkTetGen(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.GenerateCaps = 0 self.PLC = 1 self.Refine = 0 self.Coarsen = 0 self.NoBoundarySplit = 0 self.Quality = 1 self.MinRatio = 1.414 self.MinDihedral = 10.0 self.MaxDihedral = 165.0 self.VarVolume = 0 self.FixedVolume = 0 self.MaxVolume = 1E-1 self.RemoveSliver = 0 self.RegionAttrib = 0 self.Epsilon = 1E-8 self.NoMerge = 0 self.DetectInter = 0 self.CheckClosure = 0 self.Order = 1 self.DoCheck = 0 self.Verbose = 0 self.UseSizingFunction = 0 self.SizingFunctionArrayName = '' self.CellEntityIdsArrayName = 'CellEntityIds' self.TetrahedronVolumeArrayName = 'TetrahedronVolume' self.OutputSurfaceElements = 1 self.OutputVolumeElements = 1 self.SetScriptName('vmtktetgen') self.SetScriptDoc('wrapper around TetGen tetrahedral mesh generator by Hang Si (http://tetgen.berlios.de/)') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['GenerateCaps','caps','bool',1,'','close surface holes with caps before meshing'], ['PLC','plc','int',1,'','see TetGen documentation'], ['Refine','refine','int',1,'','see TetGen documentation'], ['Coarsen','coarsen','int',1,'','see TetGen documentation'], ['NoBoundarySplit','noboundarysplit','int',1,'','see TetGen documentation'], ['Quality','quality','int',1,'','see TetGen documentation'], ['MinRatio','minratio','float',1,'','see TetGen documentation'], ['MinDihedral','mindihedral','float',1,'','see TetGen documentation'], ['MaxDihedral','maxdihedral','float',1,'','see TetGen documentation'], ['VarVolume','varvolume','int',1,'','see TetGen documentation'], ['FixedVolume','fixedvolume','int',1,'','see TetGen documentation'], ['MaxVolume','maxvolume','float',1,'','see TetGen documentation'], ['RemoveSliver','removesliver','int',1,'','see TetGen documentation'], ['RegionAttrib','regionattrib','int',1,'','see TetGen documentation'], ['Epsilon','epsilon','float',1,'','see TetGen documentation'], ['NoMerge','nomerge','int',1,'','see TetGen documentation'], ['DetectInter','detectinter','int',1,'','see TetGen documentation'], ['CheckClosure','checkclosure','int',1,'','see TetGen documentation'], ['Order','order','int',1,'','see TetGen documentation'], ['DoCheck','docheck','int',1,'','see TetGen documentation'], ['Verbose','verbose','int',1,'','see TetGen documentation'], ['UseSizingFunction','usesizingfunction','int',1,'','see TetGen documentation'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where cell entity ids are stored'], ['TetrahedronVolumeArrayName','tetravolumearray','str',1,'','name of the array where volumes of tetrahedra are stored'], ['SizingFunctionArrayName','sizingfunctionarray','str',1,'','name of the array where sizing function values are stored'], ['OutputSurfaceElements','surfaceelements','int',1,'','toggle output surface elements'], ['OutputVolumeElements','volumeelements','int',1,'','toggle output volume elements'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where cell entity ids are stored'], ['TetrahedronVolumeArrayName','tetravolumearray','str',1,'','name of the array where volumes of tetrahedra are stored'] ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') if self.GenerateCaps == 1: if not ((self.Mesh.IsHomogeneous() == 1) & (self.Mesh.GetCellType(0) == 5)): self.PrintError('Error: In order to generate caps, all input mesh elements must be triangles.') meshToSurfaceFilter = vtk.vtkGeometryFilter() meshToSurfaceFilter.SetInput(self.Mesh) meshToSurfaceFilter.Update() cap = vtkvmtk.vtkvmtkSimpleCapPolyData() cap.SetInput(meshToSurfaceFilter.GetOutput()) cap.SetCellMarkerArrayName(self.FacetMarkerArrayName) cap.Update() surfacetomesh = vtkvmtk.vtkvmtkPolyDataToUnstructuredGridFilter() surfacetomesh.SetInput(cap.GetOutput()) surfacetomesh.Update() self.Mesh = surfacetomesh.GetOutput() tetgen = vtkvmtk.vtkvmtkTetGenWrapper() tetgen.SetInput(self.Mesh) tetgen.SetPLC(self.PLC) tetgen.SetRefine(self.Refine) tetgen.SetCoarsen(self.Coarsen) tetgen.SetNoBoundarySplit(self.NoBoundarySplit) tetgen.SetQuality(self.Quality) tetgen.SetMinRatio(self.MinRatio) tetgen.SetMinDihedral(self.MinDihedral) tetgen.SetMaxDihedral(self.MaxDihedral) tetgen.SetVarVolume(self.VarVolume) tetgen.SetFixedVolume(self.FixedVolume) tetgen.SetMaxVolume(self.MaxVolume) tetgen.SetRemoveSliver(self.RemoveSliver) tetgen.SetRegionAttrib(self.RegionAttrib) tetgen.SetEpsilon(self.Epsilon) tetgen.SetNoMerge(self.NoMerge) tetgen.SetDetectInter(self.DetectInter) tetgen.SetCheckClosure(self.CheckClosure) tetgen.SetOrder(self.Order) tetgen.SetDoCheck(self.DoCheck) tetgen.SetVerbose(self.Verbose) tetgen.SetUseSizingFunction(self.UseSizingFunction) tetgen.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) tetgen.SetTetrahedronVolumeArrayName(self.TetrahedronVolumeArrayName) tetgen.SetSizingFunctionArrayName(self.SizingFunctionArrayName) tetgen.SetOutputSurfaceElements(self.OutputSurfaceElements) tetgen.SetOutputVolumeElements(self.OutputVolumeElements) tetgen.Update() self.Mesh = tetgen.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkbranchclipper.py0000664000175000017500000001222411757446472017571 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkbranchclipper.py,v $ ## Language: Python ## Date: $Date: 2006/02/23 09:31:39 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes import vmtkrenderer import vmtkcenterlineviewer vmtkbranchclipper = 'vmtkBranchClipper' class vmtkBranchClipper(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.RadiusArrayName = '' self.CutoffRadiusFactor = 1E16 self.ClipValue = 0.0 self.BlankingArrayName = '' self.GroupIdsArrayName = '' self.GroupIds = [] self.InsideOut = 0 self.UseRadiusInformation = 1 self.vmtkRenderer = None self.OwnRenderer = 0 self.Interactive = 0 self.SetScriptName('vmtkbranchclipper') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['GroupIdsArrayName','groupidsarray','str',1], ['GroupIds','groupids','int',-1], ['InsideOut','insideout','bool',1], ['UseRadiusInformation','useradius','bool',1], ['RadiusArrayName','radiusarray','str',1], ['BlankingArrayName','blankingarray','str',1], ['CutoffRadiusFactor','cutoffradiusfactor','float',1,'(0.0,)'], ['ClipValue','clipvalue','float',1], ['Interactive','interactive','bool',1], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['Centerlines','ocenterlines','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def GroupIdsValidator(self,text): import string if not text: return 0 if not text.split(): return 0 for char in text: if char not in string.digits + " ": return 0 return 1 def Execute(self): if not self.Surface: self.PrintError('Error: No input surface.') if not self.Centerlines: self.PrintError('Error: No input centerlines.') if self.Interactive and not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 if self.Interactive: self.vmtkRenderer.RegisterScript(self) viewer = vmtkcenterlineviewer.vmtkCenterlineViewer() viewer.Centerlines = self.Centerlines viewer.CellDataArrayName = self.GroupIdsArrayName viewer.vmtkRenderer = self.vmtkRenderer viewer.InputText = self.InputText viewer.OutputText = self.OutputText viewer.PrintError = self.PrintError viewer.PringLog = self.PrintLog viewer.Display = 0 viewer.Execute() groupIdsString = self.InputText("Please input groupIds to clip:\n",self.GroupIdsValidator) self.GroupIds = [int(groupId) for groupId in groupIdsString.split()] clipper = vtkvmtk.vtkvmtkPolyDataCenterlineGroupsClipper() clipper.SetInput(self.Surface) clipper.SetCenterlines(self.Centerlines) clipper.SetCenterlineGroupIdsArrayName(self.GroupIdsArrayName) clipper.SetGroupIdsArrayName(self.GroupIdsArrayName) clipper.SetCenterlineRadiusArrayName(self.RadiusArrayName) clipper.SetBlankingArrayName(self.BlankingArrayName) clipper.SetCutoffRadiusFactor(self.CutoffRadiusFactor) clipper.SetClipValue(self.ClipValue) clipper.SetUseRadiusInformation(self.UseRadiusInformation) if self.GroupIds: groupIds = vtk.vtkIdList() for groupId in self.GroupIds: groupIds.InsertNextId(groupId) clipper.SetCenterlineGroupIds(groupIds) clipper.ClipAllCenterlineGroupIdsOff() else: clipper.ClipAllCenterlineGroupIdsOn() if not self.InsideOut: clipper.GenerateClippedOutputOff() else: clipper.GenerateClippedOutputOn() clipper.Update() if not self.InsideOut: self.Surface = clipper.GetOutput() else: self.Surface = clipper.GetClippedOutput() if self.Surface: if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if self.Centerlines.GetSource(): self.Centerlines.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacecompare.py0000664000175000017500000001221711757446472017756 0ustar lucaluca#!/usr/bin/env python import sys import vtk import vtkvmtk import pypes import vmtkscripts vmtksurfacecompare = 'vmtkSurfaceCompare' class vmtkSurfaceCompare(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ReferenceSurface = None self.Method = '' self.ArrayName = '' self.Tolerance = 1E-8 self.Result = '' self.ResultLog = '' self.ResultData = None self.SetScriptName('vmtksurfacecompare') self.SetScriptDoc('compares a surface against a baseline') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ReferenceSurface','r','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Method','method','str',1,'["addpointarray","addcellarray","projection","distance"]','method of the test'], ['ArrayName','array','str',1,'','name of the array'], ['Tolerance','tolerance','float',1,'','tolerance for numerical comparisons'], ]) self.SetOutputMembers([ ['Result','result','bool',1,'','Output boolean stating if surfaces are equal or not'], ['ResultData','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['ResultLog','log','str',1,'','Result Log'] ]) def arrayCompare(self): if not self.ArrayName: self.PrintError('Error: No ArrayName.') attributeData = None referenceAttributeData = None calculator = vtk.vtkArrayCalculator() if self.Method in ['addpointarray','projection']: attributeData = self.Surface.GetPointData() referenceAttributeData = self.ReferenceSurface.GetPointData() calculator.SetAttributeModeToUsePointData() elif self.Method in ['addcellarray']: attributeData = self.Surface.GetCellData() referenceAttributeData = self.ReferenceSurface.GetCellData() calculator.SetAttributeModeToUseCellData() if not attributeData.GetArray(self.ArrayName): self.PrintError('Error: Invalid ArrayName.') if not referenceAttributeData.GetArray(self.ArrayName): self.PrintError('Error: Invalid ArrayName.') referenceArrayName = 'Ref' + self.ArrayName surfacePoints = self.Surface.GetNumberOfPoints() referencePoints = self.ReferenceSurface.GetNumberOfPoints() pointsDifference = surfacePoints - referencePoints if self.Method in ['addpointarray','addcellarray']: if abs(pointsDifference) > 0: self.ResultLog = 'Uneven NumberOfPoints' return False refArray = referenceAttributeData.GetArray(self.ArrayName) refArray.SetName(referenceArrayName) attributeData.AddArray(refArray) calculator.SetInput(self.Surface) elif self.Method in ['projection']: referenceAttributeData.GetArray(self.ArrayName).SetName(referenceArrayName) projection = vmtkscripts.vmtkSurfaceProjection() projection.Surface = self.Surface projection.ReferenceSurface = self.ReferenceSurface projection.Execute() calculator.SetInput(projection.Surface) calculator.AddScalarVariable('a',self.ArrayName,0) calculator.AddScalarVariable('b',referenceArrayName,0) calculator.SetFunction("a - b") calculator.SetResultArrayName('ResultArray') calculator.Update() self.ResultData = calculator.GetOutput() if self.Method in ['addpointarray','projection']: resultRange = self.ResultData.GetPointData().GetArray('ResultArray').GetRange() elif self.Method in ['addcellarray']: resultRange = self.ResultData.GetCellData().GetArray('ResultArray').GetRange() self.PrintLog('Result Range: ' + str(resultRange)) if max([abs(r) for r in resultRange]) < self.Tolerance: return True return False def distanceCompare(self): distance = vmtkscripts.vmtkSurfaceDistance() distance.Surface = self.Surface distance.ReferenceSurface = self.ReferenceSurface distance.DistanceArrayName = 'Distance' distance.Execute() distanceRange = distance.Surface.GetPointData().GetArray('Distance').GetRange() self.PrintLog('Distance Range: ' + str(distanceRange)) if max(distanceRange) < self.Tolerance: return True return False def Execute(self): if not self.Surface: self.PrintError('Error: No Surface.') if not self.ReferenceSurface: self.PrintError('Error: No Reference Surface.') if not self.Method: self.PrintError('Error: No method.') if self.Method in ['addpointarray','addcellarray','projection']: self.Result = self.arrayCompare() elif self.Method == 'distance': self.Result = self.distanceCompare() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacereferencesystemtransform.py0000664000175000017500000001403311757446472023465 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacereferencesystemtransform.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import math import sys import pypes vmtksurfacereferencesystemtransform = 'vmtkSurfaceReferenceSystemTransform' class vmtkSurfaceReferenceSystemTransform(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ReferenceSystems = None self.ReferenceSystemId = -1 self.ReferenceSystemsIdArrayName = '' self.ReferenceSystemsNormal1ArrayName = '' self.ReferenceSystemsNormal2ArrayName = '' self.ReferenceOrigin = [0.0, 0.0, 0.0] self.ReferenceNormal1 = [0.0, 0.0, 1.0] self.ReferenceNormal2 = [0.0, 1.0, 0.0] self.SetScriptName('vmtksurfacereferencesystemtransform') self.SetScriptDoc('translate and rotate a surface in order to orient its reference system with a target reference system') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ReferenceOrigin','referenceorigin','float',3,'','origin of the target reference system'], ['ReferenceNormal1','referencenormal1','float',3,'','first normal of the target reference system'], ['ReferenceNormal2','referencenormal2','float',3,'','second normal of the target reference system'], ['ReferenceSystems','referencesystems','vtkPolyData',1,'','reference systems of the input surface represented by a set of points with two normals each','vmtksurfacereader'], ['ReferenceSystemId','referencesystemid','int',1,'','id of the reference system to use'], ['ReferenceSystemsIdArrayName','referencesystemidsarray','str',1,'','name of the array where reference system ids are stored'], ['ReferenceSystemsNormal1ArrayName','normal1array','str',1,'','name of the array where the first normals defining the reference systems are stored'], ['ReferenceSystemsNormal2ArrayName','normal2array','str',1,'','name of the array where the second normals defining the reference systems are stored'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def ComputeAngle(self,in_vector0,in_vector1): vector0 = [in_vector0[0], in_vector0[1], in_vector0[2]] vector1 = [in_vector1[0], in_vector1[1], in_vector1[2]] vtk.vtkMath.Normalize(vector0) vtk.vtkMath.Normalize(vector1) sum = [ vector0[0] + vector1[0], vector0[1] + vector1[1], vector0[2] + vector1[2]] difference = [ vector0[0] - vector1[0], vector0[1] - vector1[1], vector0[2] - vector1[2]] sumNorm = vtk.vtkMath.Norm(sum) differenceNorm = vtk.vtkMath.Norm(difference) ## angle = 2.0 * math.atan2(differenceNorm,sumNorm) + math.pi angle = 2.0 * math.atan2(differenceNorm,sumNorm) return angle def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') if self.ReferenceSystems == None: self.PrintError('Error: No ReferenceSystems.') referenceSystemsNormal1Array = self.ReferenceSystems.GetPointData().GetArray(self.ReferenceSystemsNormal1ArrayName) referenceSystemsNormal2Array = self.ReferenceSystems.GetPointData().GetArray(self.ReferenceSystemsNormal2ArrayName) referenceSystemPointId = 0 if self.ReferenceSystemId != -1: referenceSystemsIdArray = self.ReferenceSystems.GetPointData().GetArray(self.ReferenceSystemsIdArrayName) for i in range(self.ReferenceSystems.GetNumberOfPoints()): referenceSystemId = int(referenceSystemsIdArray.GetTuple1(i)) if referenceSystemId == self.ReferenceSystemId: referenceSystemPointId = i break currentOrigin = self.ReferenceSystems.GetPoint(referenceSystemPointId) currentNormal1 = referenceSystemsNormal1Array.GetTuple3(referenceSystemPointId) currentNormal2 = referenceSystemsNormal2Array.GetTuple3(referenceSystemPointId) transform = vtk.vtkTransform() transform.PostMultiply() translation = [0.0, 0.0, 0.0] translation[0] = self.ReferenceOrigin[0] - currentOrigin[0] translation[1] = self.ReferenceOrigin[1] - currentOrigin[1] translation[2] = self.ReferenceOrigin[2] - currentOrigin[2] transform.Translate(translation) cross = [0.0,0.0,0.0] vtk.vtkMath.Cross(currentNormal1,self.ReferenceNormal1,cross) vtk.vtkMath.Normalize(cross) angle = self.ComputeAngle(currentNormal1,self.ReferenceNormal1) angle = angle / (2.0*vtk.vtkMath.Pi()) * 360.0; transform.RotateWXYZ(angle,cross) transformedNormal2 = transform.TransformNormal(currentNormal2) vtk.vtkMath.Cross(transformedNormal2,self.ReferenceNormal2,cross) vtk.vtkMath.Normalize(cross) angle = self.ComputeAngle(transformedNormal2,self.ReferenceNormal2) angle = angle / (2.0*vtk.vtkMath.Pi()) * 360.0; transform.RotateWXYZ(angle,cross) transformFilter = vtk.vtkTransformPolyDataFilter() transformFilter.SetInput(self.Surface) transformFilter.SetTransform(transform) transformFilter.Update() self.Surface = transformFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkboundaryreferencesystems.py0000664000175000017500000000746611757446472022123 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkboundaryreferencesystems.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkboundaryreferencesystems = 'vmtkBoundaryReferenceSystems' class vmtkBoundaryReferenceSystems(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ReferenceSystems = None self.BoundaryRadiusArrayName = 'BoundaryRadius' self.BoundaryNormalsArrayName = 'BoundaryNormals' self.Point1ArrayName = 'Point1' self.Point2ArrayName = 'Point2' self.SetScriptName('vmtkboundaryreferencesystems') self.SetScriptDoc('compute the reference systems relative to each open boundary of a model; a typical use is the specification of boundary conditions for CFD simulations; reference systems are given both as origin and normal, and as origin, a first point defining the x axis with the origin and a second point defining the xy plane with the former two') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['BoundaryRadiusArrayName','boundaryradiusarray','str',1,'','name of the array where the mean radius of each boundary has to be stored'], ['BoundaryNormalsArrayName','boundarynormalsarray','str',1,'','name of the array where outward pointing normals to each boundary have to be stored'], ['Point1ArrayName','point1array','str',1,'','name of the array where the coordinates of a point of each boundary have to be stored'], ['Point2ArrayName','point2array','str',1,'','name of the array where the coordinates of a second point of each boundary have to be stored'] ]) self.SetOutputMembers([ ['ReferenceSystems','o','vtkPolyData',1,'','the output reference systems, given as points coinciding with the origins','vmtksurfacewriter'], ['BoundaryRadiusArrayName','boundaryradiusarray','str',1,'','name of the array where the mean radius of each boundary has to be stored'], ['BoundaryNormalsArrayName','boundarynormalsarray','str',1,'','name of the array where outward pointing normals to each boundary are stored'], ['Point1ArrayName','point1array','str',1,'','name of the array where the coordinates of a point of each boundary are stored'], ['Point2ArrayName','point2array','str',1,'','name of the array where the coordinates of a second point of each boundary are stored'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') boundaryReferenceSystems = vtkvmtk.vtkvmtkBoundaryReferenceSystems() boundaryReferenceSystems.SetInput(self.Surface) boundaryReferenceSystems.SetBoundaryRadiusArrayName(self.BoundaryRadiusArrayName) boundaryReferenceSystems.SetBoundaryNormalsArrayName(self.BoundaryNormalsArrayName) boundaryReferenceSystems.SetPoint1ArrayName(self.Point1ArrayName) boundaryReferenceSystems.SetPoint2ArrayName(self.Point2ArrayName) boundaryReferenceSystems.Update() self.ReferenceSystems = boundaryReferenceSystems.GetOutput() if self.ReferenceSystems.GetSource(): self.ReferenceSystems.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagesmoothing.py0000664000175000017500000000445611757446472017777 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagesmoothing.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkimagesmoothing = 'vmtkImageSmoothing' class vmtkImageSmoothing(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.StandardDeviation = 1.0 self.RadiusFactor = 5.0 self.Dimensionality = 3 self.SetScriptName('vmtkimagesmoothing') self.SetScriptDoc('smooth an image with a Gaussian kernel') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['StandardDeviation','sigma','float',1,'(0.0,)','the standard deviation of the Gaussian in real space units'], ['RadiusFactor','radiusfactor','float',1,'(0.0,)','the factor specifing the width of the discrete Gaussian kernel'], ['Dimensionality','dimensionality','int',1,'(2,3)','the dimensionality of the convolution'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') spacing = self.Image.GetSpacing() pixelStandardDeviations = [self.StandardDeviation/spacing[0],self.StandardDeviation/spacing[1],self.StandardDeviation/spacing[2]] smoothingFilter = vtk.vtkImageGaussianSmooth() smoothingFilter.SetInput(self.Image) smoothingFilter.SetStandardDeviations(pixelStandardDeviations) smoothingFilter.SetRadiusFactor(self.RadiusFactor) smoothingFilter.SetDimensionality(self.Dimensionality) smoothingFilter.Update() self.Image = smoothingFilter.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtknetworkextraction.py0000664000175000017500000000537011757446472020553 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtknetworkextraction.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtkvmtk import vtk import sys import pypes vmtknetworkextraction = 'vmtkNetworkExtraction' class vmtkNetworkExtraction(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Network = None self.GraphLayout = None self.RadiusArrayName = 'Radius' self.TopologyArrayName = 'Topology' self.MarksArrayName = 'Marks' self.AdvancementRatio = 1.05 self.SetScriptName('vmtknetworkextraction') self.SetScriptDoc('extract a network of approximated centerlines from a surface, the surface must have at least an opening') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['AdvancementRatio','advancementratio','float',1,'(1.0,)','the ratio between the sphere step and the local maximum radius'], ['RadiusArrayName','radiusarray','str',1], ['TopologyArrayName','topologyarray','str',1], ['MarksArrayName','marksarray','str',1] ]) self.SetOutputMembers([ ['Network','o','vtkPolyData',1,'','the output network','vmtknetworkwriter'], ['GraphLayout','ograph','vtkPolyData',1,'','the output graph layout','vmtknetworkwriter'] ]) def PrintProgress(self,obj,event): self.OutputProgress(obj.GetProgress(),10) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') networkExtraction = vtkvmtk.vtkvmtkPolyDataNetworkExtraction() networkExtraction.SetInput(self.Surface) networkExtraction.SetAdvancementRatio(self.AdvancementRatio) networkExtraction.SetRadiusArrayName(self.RadiusArrayName) networkExtraction.SetTopologyArrayName(self.TopologyArrayName) networkExtraction.SetMarksArrayName(self.MarksArrayName) networkExtraction.AddObserver("ProgressEvent", self.PrintProgress) networkExtraction.Update() self.EndProgress() self.Network = networkExtraction.GetOutput() self.GraphLayout = networkExtraction.GetGraphLayout() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkcenterlinemodeller.py0000664000175000017500000000557211757446472020641 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkcenterlinemodeller.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import vtkvmtk import pypes vmtkcenterlinemodeller = 'vmtkCenterlineModeller' class vmtkCenterlineModeller(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Centerlines = None self.ReferenceImage = None self.RadiusArrayName = None self.Image = None self.ModelBounds = None self.SampleDimensions = [64,64,64] self.NegateFunction = 0 self.SetScriptName('vmtkcenterlinemodeller') self.SetScriptDoc('converts a centerline to an image containing the tube function') self.SetInputMembers([ ['Centerlines','i','vtkPolyData',1,'','the input centerlines','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1,'','name of the array where radius values are stored'], ['Image','image','vtkImageData',1,'','the input image to use as a reference','vmtkimagereader'], ['SampleDimensions','dimensions','int',3,'(0,)','dimensions of the output image'], ['ModelBounds','bounds','float',6,'(0.0,)','model bounds in physical coordinates (if None, they are computed automatically)'], ['NegateFunction','negate','bool',1,'','produce a function that is negative inside the tube'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter']]) def Execute(self): if self.Centerlines == None: self.PrintError('Error: No input centerlines.') if self.RadiusArrayName == None: self.PrintError('Error: No radius array name.') modeller = vtkvmtk.vtkvmtkPolyBallModeller() modeller.SetInput(self.Centerlines) modeller.SetRadiusArrayName(self.RadiusArrayName) modeller.UsePolyBallLineOn() if self.Image: modeller.SetReferenceImage(self.Image) else: modeller.SetSampleDimensions(self.SampleDimensions) if self.ModelBounds: modeller.SetModelBounds(self.ModelBounds) modeller.SetNegateFunction(self.NegateFunction) modeller.Update() self.Image = modeller.GetOutput() if self.Image.GetSource(): self.Image.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimageobjectenhancement.py0000664000175000017500000000574111757446472021442 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimageobjectenhancement.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkimageobjectenhancement = 'vmtkImageObjectEnhancement' class vmtkImageObjectEnhancement(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.ScalesImage = None self.EnhancedImage = None self.SigmaMin = 1.0 self.SigmaMax = 1.0 self.NumberOfSigmaSteps = 1 self.Alpha = 0.5 self.Beta = 0.5 self.Gamma = 5.0 self.ObjectDimension = 0 self.SetScriptName('vmtkimageobjectenhancement') self.SetScriptDoc('compute a feature image for use in segmentation') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['SigmaMin','sigmamin','float',1,'(0.0,)'], ['SigmaMax','sigmamax','float',1,'(0.0,)'], ['NumberOfSigmaSteps','sigmasteps','int',1,'(0,)'], ['Alpha','alpha','float',1,'(0.0,)',''], ['Beta','beta','float',1,'(0.0,)',''], ['Gamma','gamma','float',1,'(0.0,)',''], ['ObjectDimension','dimension','int',1,'(0,2)',''] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'], ['ScalesImage','oscales','vtkImageData',1,'','the scales image','vmtkimagewriter'] ]) def ApplyObjectness(self): objectness = vtkvmtk.vtkvmtkObjectnessMeasureImageFilter() objectness.SetInput(self.Image) objectness.SetSigmaMin(self.SigmaMin) objectness.SetSigmaMax(self.SigmaMax) objectness.SetNumberOfSigmaSteps(self.NumberOfSigmaSteps) objectness.SetAlpha(self.Alpha) objectness.SetBeta(self.Beta) objectness.SetGamma(self.Gamma) objectness.SetObjectDimension(self.ObjectDimension) objectness.Update() self.EnhancedImage = vtk.vtkImageData() self.EnhancedImage.DeepCopy(objectness.GetOutput()) self.ScalesImage = vtk.vtkImageData() self.ScalesImage.DeepCopy(objectness.GetScalesOutput()) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.SigmaMax < self.SigmaMin: self.SigmaMax = self.SigmaMin self.ApplyObjectness() self.Image = self.EnhancedImage if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshwriter.py0000664000175000017500000003540711757446472017156 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshwriter.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import vtk import vtkvmtk import pypes vmtkmeshwriter = 'vmtkMeshWriter' class vmtkMeshWriter(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.OutputFileName = '' self.Mesh = None self.Input = None self.Compressed = 1 self.CellEntityIdsOffset = -1 self.WriteRegionMarkers = 0 self.CellEntityIdsArrayName = '' self.SetScriptName('vmtkmeshwriter') self.SetScriptDoc('write a mesh to disk') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['Format','f','str',1, '["vtkxml","vtk","xda","fdneut","tecplot","lifev","dolfin","fluent","tetgen","pointdata"]', 'file format (xda - libmesh ASCII format, fdneut - FIDAP neutral format)'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['Compressed','compressed','bool',1,'','output gz compressed file (dolfin only)'], ['OutputFileName','ofile','str',1,'','output file name'], ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where entity ids are stored'], ['CellEntityIdsOffset','entityidsoffset','int',1,'','add this number to entity ids in output (dolfin only)'], ['WriteRegionMarkers','writeregionmarkers','bool',1,'','write entity ids for volume regions to file (dolfin only)'], ]) self.SetOutputMembers([]) def WriteVTKMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK mesh file.') writer = vtk.vtkUnstructuredGridWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) writer.Write() def WriteVTKXMLMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK XML mesh file.') writer = vtk.vtkXMLUnstructuredGridWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) writer.Write() def WriteTetGenMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing TetGen mesh file.') import os.path outputFileName = os.path.splitext(self.OutputFileName)[0] writer = vtkvmtk.vtkvmtkTetGenWriter() writer.SetInput(self.Mesh) writer.SetFileName(outputFileName) if self.CellEntityIdsArrayName != '': writer.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) writer.Write() def WriteXdaMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Xda mesh file.') writer = vtkvmtk.vtkvmtkXdaWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) if self.CellEntityIdsArrayName != '': writer.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) writer.Write() def WriteFDNEUTMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing FDNEUT mesh file.') writer = vtkvmtk.vtkvmtkFDNEUTWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) writer.Write() def WriteTecplotMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Tecplot file.') triangleFilter = vtk.vtkDataSetTriangleFilter() triangleFilter.SetInput(self.Mesh) triangleFilter.Update() self.Mesh = triangleFilter.GetOutput() f=open(self.OutputFileName, 'w') line = "VARIABLES = X,Y,Z" arrayNames = [] for i in range(self.Mesh.GetPointData().GetNumberOfArrays()): array = self.Mesh.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ',' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ',' + arrayName + str(j) line = line + '\n' f.write(line) tetraCellIdArray = vtk.vtkIdTypeArray() tetraCellType = 10 self.Mesh.GetIdsOfCellsOfType(tetraCellType,tetraCellIdArray) numberOfTetras = tetraCellIdArray.GetNumberOfTuples() line = "ZONE " + "N=" + str(self.Mesh.GetNumberOfPoints()) + ',' + "E=" + str(numberOfTetras) + ',' + "F=FEPOINT" + ',' + "ET=TETRAHEDRON" + '\n' f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = self.Mesh.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Mesh.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) for i in range(numberOfTetras): cellPointIds = self.Mesh.GetCell(tetraCellIdArray.GetValue(i)).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if (j>0): line = line + ' ' line = line + str(cellPointIds.GetId(j)+1) line = line + '\n' f.write(line) def WriteLifeVMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing LifeV file.') self.Mesh.BuildLinks() cellEntityIdsArray = vtk.vtkIntArray() cellEntityIdsArray.DeepCopy(self.Mesh.GetCellData().GetArray(self.CellEntityIdsArrayName)) tetraCellType = 10 triangleCellType = 5 f=open(self.OutputFileName, 'w') line = "MeshVersionFormatted 1\n\n" line += "Dimension\n" line += "3\n\n" line += "Vertices\n" line += "%d\n" % self.Mesh.GetNumberOfPoints() f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = self.Mesh.GetPoint(i) pointCells = vtk.vtkIdList() self.Mesh.GetPointCells(i,pointCells) minTriangleCellEntityId = -1 tetraCellEntityId = -1 for j in range(pointCells.GetNumberOfIds()): cellId = pointCells.GetId(j) if self.Mesh.GetCellType(cellId) == triangleCellType: cellEntityId = cellEntityIdsArray.GetValue(cellId) if cellEntityId < minTriangleCellEntityId or minTriangleCellEntityId == -1: minTriangleCellEntityId = cellEntityId else: tetraCellEntityId = cellEntityIdsArray.GetValue(cellId) cellEntityId = tetraCellEntityId if minTriangleCellEntityId != -1: cellEntityId = minTriangleCellEntityId line = "%f %f %f %d\n" % (point[0], point[1], point[2], cellEntityId) f.write(line) line = "\n" tetraCellIdArray = vtk.vtkIdTypeArray() self.Mesh.GetIdsOfCellsOfType(tetraCellType,tetraCellIdArray) numberOfTetras = tetraCellIdArray.GetNumberOfTuples() line += "Tetrahedra\n" line += "%d\n" % numberOfTetras f.write(line) for i in range(numberOfTetras): tetraCellId = tetraCellIdArray.GetValue(i) cellPointIds = self.Mesh.GetCell(tetraCellId).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if j>0: line += ' ' line += "%d" % (cellPointIds.GetId(j)+1) line += ' %d\n' % 1 f.write(line) line = "\n" triangleCellIdArray = vtk.vtkIdTypeArray() self.Mesh.GetIdsOfCellsOfType(triangleCellType,triangleCellIdArray) numberOfTriangles = triangleCellIdArray.GetNumberOfTuples() line += "Triangles\n" line += "%d\n" % numberOfTriangles f.write(line) for i in range(numberOfTriangles): triangleCellId = triangleCellIdArray.GetValue(i) cellPointIds = self.Mesh.GetCell(triangleCellId).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if j>0: line += ' ' line += "%d" % (cellPointIds.GetId(j)+1) cellEntityId = cellEntityIdsArray.GetValue(triangleCellId) line += ' %d\n' % cellEntityId f.write(line) def WriteDolfinMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Dolfin file.') if self.Compressed: self.OutputFileName += '.gz' writer = vtkvmtk.vtkvmtkDolfinWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) if self.CellEntityIdsArrayName != '': writer.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) writer.SetBoundaryDataIdOffset(self.CellEntityIdsOffset) writer.SetStoreCellMarkers(self.WriteRegionMarkers) writer.Write() if self.Compressed: file = open(self.OutputFileName,'r') xml = file.read() file.close() import gzip gzfile = gzip.open(self.OutputFileName,'w') gzfile.write(xml) gzfile.close() def WriteFluentMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') # self.PrintError('Error: Fluent writer not implemented yet.') # return self.PrintLog('Writing Fluent file.') writer = vtkvmtk.vtkvmtkFluentWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) if self.CellEntityIdsArrayName != '': writer.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) # writer.SetBoundaryDataIdOffset(self.CellEntityIdsOffset) writer.Write() def WritePointDataMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PointData file.') f=open(self.OutputFileName, 'w') line = "X Y Z" arrayNames = [] for i in range(self.Mesh.GetPointData().GetNumberOfArrays()): array = self.Mesh.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ' ' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ' ' + arrayName + str(j) line = line + '\n' f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = self.Mesh.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Mesh.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) def Execute(self): if self.Mesh == None: if self.Input == None: self.PrintError('Error: no Mesh.') self.Mesh = self.Input extensionFormats = {'vtu':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'xda':'xda', 'FDNEUT':'fdneut', 'lifev':'lifev', 'xml':'dolfin', 'msh':'fluent', 'tec':'tecplot', 'node':'tetgen', 'ele':'tetgen', 'dat':'pointdata'} if self.OutputFileName == 'BROWSER': import tkFileDialog import os.path initialDir = pypes.pypeScript.lastVisitedPath self.OutputFileName = tkFileDialog.asksaveasfilename(title="Output mesh",initialdir=initialDir) pypes.pypeScript.lastVisitedPath = os.path.dirname(self.OutputFileName) if not self.OutputFileName: self.PrintError('Error: no OutputFileName.') if self.GuessFormat and self.OutputFileName and not self.Format: import os.path extension = os.path.splitext(self.OutputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.WriteVTKMeshFile() elif (self.Format == 'vtkxml'): self.WriteVTKXMLMeshFile() elif (self.Format == 'xda'): self.WriteXdaMeshFile() elif (self.Format == 'fdneut'): self.WriteFDNEUTMeshFile() elif (self.Format == 'lifev'): self.WriteLifeVMeshFile() elif (self.Format == 'dolfin'): self.WriteDolfinMeshFile() elif (self.Format == 'fluent'): self.WriteFluentMeshFile() elif (self.Format == 'tecplot'): self.WriteTecplotMeshFile() elif (self.Format == 'tetgen'): self.WriteTetGenMeshFile() elif (self.Format == 'pointdata'): self.WritePointDataMeshFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtklocalgeometry.py0000664000175000017500000002067411757446472017633 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtklocalgeometry.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:48:31 $ ## Version: $Revision: 1.5 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtklocalgeometry = 'vmtkLocalGeometry' class vmtkLocalGeometry(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Centerlines = None self.VoronoiDiagram = None self.PoleIds = None self.EdgeArrayName = '' self.VoronoiGeodesicDistanceArrayName = 'VoronoiGeodesicDistance' self.VoronoiPoleCenterlineVectorsArrayName = 'VoronoiPoleCenterlineVectors' self.VoronoiCellIdsArrayName = 'VoronoiCellIds' self.VoronoiPCoordsArrayName = 'VoronoiPCoords' self.ComputePoleVectors = 0 self.ComputeGeodesicDistance = 0 self.ComputeNormalizedTangencyDeviation = 0 self.ComputeEuclideanDistance = 0 self.ComputeCenterlineVectors = 0 self.ComputeCellIds = 0 self.ComputePCoords = 0 self.AdjustBoundaryValues = 0 self.PoleVectorsArrayName = 'PoleVectors' self.GeodesicDistanceArrayName = 'GeodesicDistance' self.NormalizedTangencyDeviationArrayName = 'NTD' self.EuclideanDistanceArrayName = 'EuclideanDistance' self.CenterlineVectorsArrayName = 'CenterlineVectors' self.CellIdsArrayName = 'CellIdsArray' self.PCoordsArrayName = 'PCoordsArray' self.SetScriptName('vmtklocalgeometry') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['VoronoiDiagram','voronoidiagram','vtkPolyData',1,'','','vmtksurfacereader'], ['PoleIds','poleids','vtkIdList',1], ['EdgeArrayName','edgearray','str',1], ['VoronoiGeodesicDistanceArrayName','voronoigeodesicdistancearray','str',1], ['VoronoiPoleCenterlineVectorsArrayName','voronoipolecenterlinevectorsarray','str',1], ['VoronoiCellIdsArrayName','voronoicellidsarray','str',1], ['VoronoiPCoordsArrayName','voronoipcoordsarray','str',1], ['ComputePoleVectors','computepolevectors','bool',1], ['ComputeGeodesicDistance','computegeodesicdistance','bool',1], ['ComputeNormalizedTangencyDeviation','computentd','bool',1], ['ComputeEuclideanDistance','computeeuclideandistance','bool',1], ['ComputeCenterlineVectors','computecenterlinevectors','bool',1], ['ComputeCellIds','computecellids','bool',1], ['ComputePCoords','computepcoords','bool',1], ['AdjustBoundaryValues','adjustboundaryvalues','bool',1], ['PoleVectorsArrayName','polevectorsarray','str',1], ['GeodesicDistanceArrayName','geodesicdistancearray','str',1], ['NormalizedTangencyDeviationArrayName','ntdarray','str',1], ['EuclideanDistanceArrayName','euclideandistancearray','str',1], ['CenterlineVectorsArrayName','centerlinevectorsarray','str',1], ['CellIdsArrayName','cellidsarray','str',1], ['PCoordsArrayName','pcoordsarray','str',1] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'], ['PoleVectorsArrayName','polevectorsarray','str',1], ['GeodesicDistanceArrayName','geodesicdistancearray','str',1], ['NormalizedTangencyDeviationArrayName','ntdarray','str',1], ['EuclideanDistanceArrayName','euclideandistancearray','str',1], ['CenterlineVectorsArrayName','centerlinevectorsarray','str',1], ['CellIdsArrayName','cellidsarray','str',1], ['PCoordsArrayName','pcoordsarray','str',1] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if self.Centerlines == None: self.PrintError('Error: No input centerlines.') if self.VoronoiDiagram == None: self.PrintError('Error: No input Voronoi diagram.') if self.PoleIds == None: self.PrintError('Error: No input pole ids.') voronoi = self.VoronoiDiagram if self.ComputeGeodesicDistance | self.ComputeNormalizedTangencyDeviation | self.ComputeEuclideanDistance | self.ComputeCenterlineVectors | self.ComputeCellIds | self.ComputePCoords: if self.EdgeArrayName == '': self.PrintError('Error: No input edge array name.') voronoiRadialFastMarching = vtkvmtk.vtkvmtkNonManifoldFastMarching() voronoiRadialFastMarching.SetInput(voronoi) voronoiRadialFastMarching.UnitSpeedOn() voronoiRadialFastMarching.SetSolutionArrayName(self.VoronoiGeodesicDistanceArrayName) voronoiRadialFastMarching.PolyDataBoundaryConditionsOn() voronoiRadialFastMarching.SetBoundaryPolyData(self.Centerlines) voronoiRadialFastMarching.SetIntersectedEdgesArrayName(self.EdgeArrayName) voronoiRadialFastMarching.Update() voronoi = voronoiRadialFastMarching.GetOutput() if self.ComputeEuclideanDistance | self.ComputeCenterlineVectors | self.ComputeCellIds | self.ComputePCoords: voronoiShooter = vtkvmtk.vtkvmtkSteepestDescentShooter() voronoiShooter.SetInput(voronoi) voronoiShooter.SetTarget(self.Centerlines) voronoiShooter.SetDescentArrayName(self.VoronoiGeodesicDistanceArrayName) voronoiShooter.SetEdgeArrayName(self.EdgeArrayName) voronoiShooter.SetSeeds(self.PoleIds) voronoiShooter.SetTargetVectorsArrayName(self.VoronoiPoleCenterlineVectorsArrayName) voronoiShooter.SetTargetCellIdsArrayName(self.VoronoiCellIdsArrayName) voronoiShooter.Update() voronoi = voronoiShooter.GetOutput() surfaceLocalGeometry = vtkvmtk.vtkvmtkPolyDataLocalGeometry() surfaceLocalGeometry.SetInput(self.Surface) surfaceLocalGeometry.SetVoronoiDiagram(voronoi) surfaceLocalGeometry.SetVoronoiGeodesicDistanceArrayName(self.VoronoiGeodesicDistanceArrayName) surfaceLocalGeometry.SetPoleIds(self.PoleIds) surfaceLocalGeometry.SetVoronoiPoleCenterlineVectorsArrayName(self.VoronoiPoleCenterlineVectorsArrayName) surfaceLocalGeometry.SetVoronoiCellIdsArrayName(self.VoronoiCellIdsArrayName) surfaceLocalGeometry.SetVoronoiPCoordsArrayName(self.VoronoiPCoordsArrayName) surfaceLocalGeometry.SetComputePoleVectors(self.ComputePoleVectors) surfaceLocalGeometry.SetComputeGeodesicDistance(self.ComputeGeodesicDistance) surfaceLocalGeometry.SetComputeNormalizedTangencyDeviation(self.ComputeNormalizedTangencyDeviation) surfaceLocalGeometry.SetComputeEuclideanDistance(self.ComputeEuclideanDistance) surfaceLocalGeometry.SetComputeCenterlineVectors(self.ComputeCenterlineVectors) surfaceLocalGeometry.SetComputeCellIds(self.ComputeCellIds) surfaceLocalGeometry.SetComputePCoords(self.ComputePCoords) surfaceLocalGeometry.SetAdjustBoundaryValues(self.AdjustBoundaryValues) surfaceLocalGeometry.SetPoleVectorsArrayName(self.PoleVectorsArrayName) surfaceLocalGeometry.SetGeodesicDistanceArrayName(self.GeodesicDistanceArrayName) surfaceLocalGeometry.SetNormalizedTangencyDeviationArrayName(self.NormalizedTangencyDeviationArrayName) surfaceLocalGeometry.SetEuclideanDistanceArrayName(self.EuclideanDistanceArrayName) surfaceLocalGeometry.SetCenterlineVectorsArrayName(self.CenterlineVectorsArrayName) surfaceLocalGeometry.SetCellIdsArrayName(self.CellIdsArrayName) surfaceLocalGeometry.SetPCoordsArrayName(self.PCoordsArrayName) surfaceLocalGeometry.Update() self.Surface = surfaceLocalGeometry.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacekiteremoval.py0000664000175000017500000000355111757446472020653 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacekiteremoval.py,v $ ## Language: Python ## Date: $Date: 2006/03/01 11:53:48 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import vtk import vtkvmtk import pypes vmtksurfacekiteremoval = 'vmtkSurfaceKiteRemoval' class vmtkSurfaceKiteRemoval(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.SizeFactor = 0.1 self.SetScriptName('vmtksurfacekiteremoval') self.SetScriptDoc('remove small kites in a surface mesh to avoid Taubin smoothing artifacts') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['SizeFactor','sizefactor','float',1,'(0.0,)','ratio between local and global average triangle area'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') kiteRemoval = vtkvmtk.vtkvmtkPolyDataKiteRemovalFilter() kiteRemoval.SetInput(self.Surface) kiteRemoval.SetSizeFactor(self.SizeFactor) kiteRemoval.Update() self.Surface = kiteRemoval.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagereslice.py0000664000175000017500000001411211757446472017404 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagereslice.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.8 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 improved by ## Hugo Gratama van Andel ## Academic Medical Centre - University of Amsterdam ## Dept. Biomedical Engineering & Physics import vtk import sys import pypes vmtkimagereslice = 'vmtkImageReslice' class vmtkImageReslice(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.ReferenceImage = None self.OutputSpacing = [] self.OutputOrigin = [] self.OutputExtent = [] self.Interpolation = 'linear' self.Cast = 1 self.BackgroundLevel = 0.0 self.MatrixCoefficients = [] self.InvertMatrix = 0 self.Matrix4x4 = None self.Rotation = [0.0,0.0,0.0] self.Translation = [0.0,0.0,0.0] self.Scaling = [1.0,1.0,1.0] self.TransformInputSampling = 1 self.SetScriptName('vmtkimagereslice') self.SetScriptDoc('reslice an image based on user-specified parameters or on a reference image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['ReferenceImage','r','vtkImageData',1,'','the reference image','vmtkimagereader'], ['OutputSpacing','spacing','float',3,'','the output spacing'], ['OutputOrigin','origin','float',3,'','the output origin'], ['OutputExtent','extent','int',6,'','the output extent'], ['Interpolation','interpolation','str',1,'["nearestneighbor","linear","cubic"]','interpolation during reslice'], ['Cast','cast','bool',1,'','toggle cast image to float type'], ['BackgroundLevel','background','float',1,'','the output image background'], ['Matrix4x4','matrix4x4','vtkMatrix4x4',1,'','the input transform matrix'], ['MatrixCoefficients','matrix','float',16,'','coefficients of transform matrix'], ['InvertMatrix','invert','bool',1,'','invert matrix before applying transformation'], ['Rotation','rotation','float',3,'','rotations around the x-,y- and z-axis'], ['Translation','translation','float',3,'','translation in the x-,y- and z-directions'], ['Scaling','scaling','float',3,'','scaling of the x-,y- and z-directions'], ['TransformInputSampling','transforminputsampling','bool',1,'','transform spacing, origin and extent of the Input (or the InformationInput) according to the direction cosines and origin of the ResliceAxes before applying them as the default output spacing, origin and extent'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.Cast: cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() self.Image = cast.GetOutput() resliceFilter = vtk.vtkImageReslice() resliceFilter.SetInput(self.Image) if self.ReferenceImage: resliceFilter.SetInformationInput(self.ReferenceImage) else: if self.OutputSpacing: resliceFilter.SetOutputSpacing(self.OutputSpacing) if self.OutputOrigin: resliceFilter.SetOutputOrigin(self.OutputOrigin) if self.OutputExtent: resliceFilter.SetOutputExtent(self.OutputExtent) if self.Interpolation == 'nearestneighbor': resliceFilter.SetInterpolationModeToNearestNeighbor() elif self.Interpolation == 'linear': resliceFilter.SetInterpolationModeToLinear() elif self.Interpolation == 'cubic': resliceFilter.SetInterpolationModeToCubic() else: self.PrintError('Error: unsupported interpolation mode') resliceFilter.SetBackgroundLevel(self.BackgroundLevel) if self.TransformInputSampling: resliceFilter.TransformInputSamplingOn() else: resliceFilter.TransformInputSamplingOff() if not self.Matrix4x4: if self.MatrixCoefficients != []: self.PrintLog('Setting up transform matrix using specified coefficients') self.Matrix4x4 = vtk.vtkMatrix4x4() self.Matrix4x4.DeepCopy(self.MatrixCoefficients) elif self.Translation != [0.0,0.0,0.0] or self.Rotation != [0.0,0.0,0.0] or self.Scaling != [1.0,1.0,1.0]: self.PrintLog('Setting up transform matrix using specified translation, rotation and/or scaling') transform = vtk.vtkTransform() transform.RotateX(self.Rotation[0]) transform.RotateY(self.Rotation[1]) transform.RotateZ(self.Rotation[2]) transform.Translate(self.Translation[0], self.Translation[1], self.Translation[2]) transform.Scale(self.Scaling[0], self.Scaling[1], self.Scaling[2]) self.Matrix4x4 = vtk.vtkMatrix4x4() self.Matrix4x4.DeepCopy(transform.GetMatrix()) if self.InvertMatrix and self.Matrix4x4: self.Matrix4x4.Invert() if self.Matrix4x4: transform = vtk.vtkMatrixToLinearTransform() transform.SetInput(self.Matrix4x4) resliceFilter.SetResliceTransform(transform) resliceFilter.Update() self.Image = resliceFilter.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacepointdatatocelldata.py0000664000175000017500000000343111757446472022346 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacepointdatatocelldata.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfacepointdatatocelldata = 'vmtkSurfacePointDataToCellData' class vmtkSurfacePointDataToCellData(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.SetScriptName('vmtksurfacepointdatatocelldata') self.SetScriptDoc('convert point data arrays to cell data surface arrays') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') pointDataToCellDataFilter = vtk.vtkPointDataToCellData() pointDataToCellDataFilter.SetInput(self.Surface) pointDataToCellDataFilter.PassPointDataOn() pointDataToCellDataFilter.Update() self.Surface = pointDataToCellDataFilter.GetPolyDataOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacetransforminteractive.py0000664000175000017500000001541611757446472022605 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacetransforminteractive.py,v $ ## Language: Python ## Date: $Date: 2009/01/30 15:52:00 $ ## Version: $Revision: 1.0 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Hugo Gratama van Andel ## Academic Medical Centre - University of Amsterdam ## Dept. Biomedical Engineering & Physics import vtk import sys import vmtkrenderer import pypes vmtksurfacetransforminteractive = 'vmtkSurfaceTransformInteractive' class vmtkSurfaceTransformInteractive(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.TransformedSurface = vtk.vtkPolyData() self.ReferenceSurface = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Actor = None self.BoxWidget = None self.Matrix4x4 = None self.Transform = None self.TransformFilter = None self.Scaling = 0 self.SetScriptName('vmtksurfacetransforminteractive') self.SetScriptDoc('interactively transform a surface to another surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ReferenceSurface','r','vtkPolyData',1,'','the reference surface','vmtksurfacereader'], ['Scaling','scaling','bool',1,'','allow scaling of surface'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ['Matrix4x4','omatrix4x4','vtkMatrix4x4',1,'','the output transform matrix'] ]) def MoveCallback(self,obj): if self.BoxWidget.GetEnabled() != 1: return self.BoxWidget.GetTransform(self.Transform) self.TransformFilter.Update() self.TransformedSurface.ShallowCopy(self.TransformFilter.GetOutput()) self.TransformedSurface.Update() if self.TransformedSurface.GetSource(): self.TransformedSurface.GetSource().UnregisterAllOutputs() self.vmtkRenderer.RenderWindow.Render() def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) ##def KeyPressed(self,obj,event): ## key = obj.GetKeySym() ##if key != 'space': ## return ##if self.BoxWidget.GetEnabled() != 1: ## return ##self.BoxWidget.GetTransform(self.Transform) ##self.TransformFilter.Update() ##self.TransformedSurface.ShallowCopy(self.TransformFilter.GetOutput()) ##self.TransformedSurface.Update() ##if self.TransformedSurface.GetSource(): ## self.TransformedSurface.GetSource().UnregisterAllOutputs() ##self.vmtkRenderer.RenderWindow.Render() def Display(self): self.Surface.ComputeBounds() self.BoxWidget.PlaceWidget(self.Surface.GetBounds()) #self.vmtkRenderer.RenderWindowInteractor.Initialize() self.vmtkRenderer.Render() #self.vmtkRenderer.RenderWindowInteractor.Start() def Execute(self): if (self.Surface == None): self.PrintError('Error: no Surface.') #if (self.ReferenceSurface == None): # self.PrintError('Error: no Reference Surface.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) if self.Transform == None: self.Transform = vtk.vtkTransform() if self.TransformFilter == None: self.TransformFilter= vtk.vtkTransformPolyDataFilter() self.TransformFilter.SetInput(self.Surface) self.TransformFilter.SetTransform(self.Transform) self.TransformFilter.Update() self.TransformFilter.GetOutput().Update() self.TransformedSurface.ShallowCopy(self.TransformFilter.GetOutput()) self.TransformedSurface.Update() mapper = vtk.vtkPolyDataMapper() mapper.SetInput(self.TransformedSurface) mapper.ScalarVisibilityOff() self.Actor = vtk.vtkActor() self.Actor.SetMapper(mapper) self.Actor.GetProperty().SetColor(1.0, 0.1, 0.1) #self.Actor.GetProperty().SetOpacity(0.5) self.vmtkRenderer.Renderer.AddActor(self.Actor) if self.ReferenceSurface: mapper2 = vtk.vtkPolyDataMapper() mapper2.SetInput(self.ReferenceSurface) mapper2.ScalarVisibilityOff() self.Actor2 = vtk.vtkActor() self.Actor2.SetMapper(mapper2) self.Actor2.GetProperty().SetColor(1.0, 1.0, 1.0) self.Actor2.GetProperty().SetOpacity(0.5) self.vmtkRenderer.Renderer.AddActor(self.Actor2) self.BoxWidget = vtk.vtkBoxWidget() self.BoxWidget.SetPlaceFactor(1.0) self.BoxWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.BoxWidget.GetFaceProperty().SetColor(0.6,0.6,0.2) self.BoxWidget.GetFaceProperty().SetOpacity(0.25) self.BoxWidget.ScalingEnabledOff() self.BoxWidget.HandlesOff() if self.Scaling: self.BoxWidget.ScalingEnabledOn() self.BoxWidget.HandlesOn() self.vmtkRenderer.RegisterScript(self) self.InputInfo('Use the left-mousebutton to rotate the box \nUse the middle-mouse-button to move the box \nPress space to move the surface to its new postion') #self.OutputText('Press \'i\' to activate the box widget interactor \n') #self.OutputText('Use the left-mousebutton to rotate the box \n') #self.OutputText('Use the middle-mouse-button to move the box \n') #self.OutputText('Press space to move the surface to its new postion \n') #self.OutputText('Press \'q\' to quit and apply the transform \n') self.vmtkRenderer.AddKeyBinding('space','Move the surface.',self.MoveCallback) self.vmtkRenderer.AddKeyBinding('i','Interact.',self.InteractCallback) self.Display() self.Surface = self.TransformedSurface self.Matrix4x4 = self.Transform.GetMatrix() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshvorticityhelicity.py0000664000175000017500000000540411757446472021423 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshvorticityhelicity.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtkvmtk import vtk import sys import pypes vmtkmeshvorticityhelicity = 'vmtkMeshVorticityHelicity' class vmtkMeshVorticityHelicity(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.VelocityArrayName = None self.VorticityArrayName = 'Vorticity' self.HelicityArrayName = 'Helicity' self.ComputeHelicity = True self.ConvergenceTolerance = 1E-6 self.QuadratureOrder = 3 self.SetScriptName('vmtkmeshvorticityhelicity') self.SetScriptDoc('compute vorticity and helicity from a velocity field') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['ComputeHelicity','helicity','bool',1,'',''], ['VelocityArrayName','velocityarray','str',1,'',''], ['VorticityArrayName','vorticityarray','str',1,'',''], ['HelicityArrayName','helicityarray','str',1,'',''], ['ConvergenceTolerance','tolerance','float',1,'',''], ['QuadratureOrder','quadratureorder','int',1,'',''] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') vorticityFilter = vtkvmtk.vtkvmtkUnstructuredGridVorticityFilter() vorticityFilter.SetInput(self.Mesh) vorticityFilter.SetVelocityArrayName(self.VelocityArrayName) vorticityFilter.SetVorticityArrayName(self.VorticityArrayName) vorticityFilter.SetHelicityFactorArrayName(self.HelicityArrayName) vorticityFilter.SetConvergenceTolerance(self.ConvergenceTolerance) vorticityFilter.SetQuadratureOrder(self.QuadratureOrder) if self.ComputeHelicity: vorticityFilter.ComputeHelicityFactorOn() else: vorticityFilter.ComputeHelicityFactorOff() vorticityFilter.Update() self.Mesh = vorticityFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshtransform.py0000664000175000017500000000727611757446472017660 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshtransform.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 improved by ## Hugo Gratama van Andel ## Academic Medical Centre - University of Amsterdam ## Dept. Biomedical Engineering & Physics import vtk import sys import pypes vmtkmeshtransform = 'vmtkMeshTransform' class vmtkMeshTransform(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.MatrixCoefficients = [] self.InvertMatrix = 0 self.Matrix4x4 = None self.Rotation = [0.0,0.0,0.0] self.Translation = [0.0,0.0,0.0] self.Scaling = [1.0,1.0,1.0] #TODO: define covariant vector array names self.SetScriptName('vmtkmeshtransform') self.SetScriptDoc('transform a mesh with a provided matrix') self.SetInputMembers([ ['Mesh','i','vtkPolyData',1,'','the input mesh','vmtkmeshreader'], ['Matrix4x4','matrix4x4','vtkMatrix4x4',1,'','the input transform matrix'], ['MatrixCoefficients','matrix','float',16,'','coefficients of transform matrix'], ['InvertMatrix','invert','bool',1,'','invert matrix before applying transformation'], ['Rotation','rotation','float',3,'','rotations around the x-,y- and z-axis'], ['Translation','translation','float',3,'','translation in the x-,y- and z-directions'], ['Scaling','scaling','float',3,'','scaling of the x-,y- and z-directions'] ]) self.SetOutputMembers([ ['Mesh','o','vtkPolyData',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') if not self.Matrix4x4: self.Matrix4x4 = vtk.vtkMatrix4x4() if self.MatrixCoefficients != []: self.PrintLog('Setting up transform matrix using specified coefficients') self.Matrix4x4.DeepCopy(self.MatrixCoefficients) elif self.Translation != [0.0,0.0,0.0] or self.Rotation != [0.0,0.0,0.0] or self.Scaling != [1.0,1.0,1.0]: self.PrintLog('Setting up transform matrix using specified translation, rotation and/or scaling') transform = vtk.vtkTransform() transform.RotateX(self.Rotation[0]) transform.RotateY(self.Rotation[1]) transform.RotateZ(self.Rotation[2]) transform.Translate(self.Translation[0], self.Translation[1], self.Translation[2]) transform.Scale(self.Scaling[0], self.Scaling[1], self.Scaling[2]) self.Matrix4x4.DeepCopy(transform.GetMatrix()) if self.InvertMatrix: self.Matrix4x4.Invert() transform = vtk.vtkMatrixToLinearTransform() transform.SetInput(self.Matrix4x4) transformFilter = vtk.vtkTransformFilter() transformFilter.SetInput(self.Mesh) transformFilter.SetTransform(transform) transformFilter.Update() self.Mesh = transformFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimageshiftscale.py0000664000175000017500000001137711757446472020115 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimageshiftscale.py,v $ ## Language: Python ## Date: $Date: 2009/01/09 13:56:00 $ ## Version: $Revision: 1.0 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Hugo Gratama van Andel ## Academic Medical Centre - University of Amsterdam ## Dept. Biomedical Engineering & Physics import vtk import sys import pypes vmtkimageshiftscale = 'vmtkImageShiftScale' class vmtkImageShiftScale(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.OutputType = 'unchanged' self.Shift = 0.0 self.Scale = 1.0 self.MapRanges = 0 self.InputRange = [0.0,0.0] self.OutputRange = [0.0,0.0] self.ClampOverflowOn = 1 self.SetScriptName('vmtkimageshiftscale') self.SetScriptDoc('shift and scale the intensity of an image and cast it to a specified type') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['OutputType','type','str',1,'["unchanged","float","double","uchar","char","ushort","short","long","ulong","int","uint"]','the output image type - use "unchanged", the default, to keep same type as input'], ['ClampOverflowOn','clamp','bool',1,'','Whith ClampOverflow On, the data is thresholded so that the output value does not exceed the max or min of the data type'], ['Shift','shift','float',1,'','the shift value'], ['Scale','scale','float',1,'','the scale value'], ['MapRanges','mapranges','bool',1,'','toggle mapping of input range to output range instead of simple shift scale'], ['InputRange','inputrange','float',2,'','the input range that will be mapped in the output range - leave default or set to 0.0 0.0 for using input image scalar range as input range'], ['OutputRange','outputrange','float',2,'','the output range into which the input range will be mapped'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No input image.') if self.MapRanges: if self.InputRange == [0.0,0.0]: self.InputRange = self.Image.GetScalarRange() if self.InputRange[1] == self.InputRange[0]: self.PrintError('Error: Input range has zero width. Cannot map values') self.Shift = -self.InputRange[0] self.Scale = (self.OutputRange[1] - self.OutputRange[0]) / (self.InputRange[1] - self.InputRange[0]) shiftScale = vtk.vtkImageShiftScale() shiftScale.SetInput(self.Image) shiftScale.SetShift(self.Shift) shiftScale.SetScale(self.Scale) if self.OutputType == 'double': shiftScale.SetOutputScalarTypeToDouble() elif self.OutputType == 'uchar': shiftScale.SetOutputScalarTypeToUnsignedChar() elif self.OutputType == 'char': shiftScale.SetOutputScalarTypeToChar() elif self.OutputType == 'ushort': shiftScale.SetOutputScalarTypeToUnsignedShort() elif self.OutputType == 'short': shiftScale.SetOutputScalarTypeToShort() elif self.OutputType == 'ulong': shiftScale.SetOutputScalarTypeToUnsignedLong() elif self.OutputType == 'long': shiftScale.SetOutputScalarTypeToLong() elif self.OutputType == 'uint': shiftScale.SetOutputScalarTypeToUnsignedInt() elif self.OutputType == 'int': shiftScale.SetOutputScalarTypeToInt() elif self.OutputType == 'float': shiftScale.SetOutputScalarTypeToFloat() if self.OutputType != 'unchanged': if self.ClampOverflowOn: shiftScale.ClampOverflowOn() shiftScale.ClampOverflowOff() shiftScale.Update() self.Image = shiftScale.GetOutput() if self.MapRanges and self.OutputRange[0] != 0.0: shiftScale2 = vtk.vtkImageShiftScale() shiftScale2.SetInput(self.Image) shiftScale2.SetShift(self.OutputRange[0]) shiftScale2.SetScale(1.0) shiftScale2.Update() self.Image = shiftScale2.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshprojection.py0000664000175000017500000000400411757446472020003 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshprojection.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkmeshprojection = 'vmtkMeshProjection' class vmtkMeshProjection(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.ReferenceMesh = None self.Mesh = None self.Tolerance = 1E-8 self.SetScriptName('vmtkmeshprojection') self.SetScriptDoc('interpolates the point data of a reference mesh onto the input mesh') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['ReferenceMesh','r','vtkUnstructuredGrid',1,'','the reference mesh','vmtkmeshreader'], ['Tolerance','tolerance','double',1,'(0.0,)','locator tolerance'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No Mesh.') if self.ReferenceMesh == None: self.PrintError('Error: No ReferenceMesh.') self.PrintLog('Computing projection.') meshProjection = vtkvmtk.vtkvmtkMeshProjection() meshProjection.SetInput(self.Mesh) meshProjection.SetReferenceMesh(self.ReferenceMesh) meshProjection.SetTolerance(self.Tolerance) meshProjection.Update() self.Mesh = meshProjection.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshgenerator.py0000664000175000017500000002461511757446472017627 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshgenerator.py,v $ ## Language: Python ## Date: $Date: 2006/02/23 09:27:52 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import vmtkscripts import pypes vmtkmeshgenerator = 'vmtkMeshGenerator' class vmtkMeshGenerator(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.TargetEdgeLength = 1.0 self.TargetEdgeLengthFactor = 1.0 self.TargetEdgeLengthArrayName = '' self.MaxEdgeLength = 1E16 self.MinEdgeLength = 0.0 self.CellEntityIdsArrayName = 'CellEntityIds' self.ElementSizeMode = 'edgelength' self.VolumeElementScaleFactor = 0.8 self.CappingMethod = 'simple' self.SkipCapping = 0 self.RemeshCapsOnly = 0 self.BoundaryLayer = 0 self.NumberOfSubLayers = 2 self.BoundaryLayerThicknessFactor = 0.25 self.Tetrahedralize = 0 self.SizingFunctionArrayName = 'VolumeSizingFunction' # Output objects self.Mesh = None self.RemeshedSurface = None self.SetScriptName('vmtkmeshgenerator') self.SetScriptDoc('generate a mesh suitable for CFD from a surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['TargetEdgeLength','edgelength','float',1,'(0.0,)'], ['TargetEdgeLengthArrayName','edgelengtharray','str',1], ['TargetEdgeLengthFactor','edgelengthfactor','float',1,'(0.0,)'], ['MaxEdgeLength','maxedgelength','float',1,'(0.0,)'], ['MinEdgeLength','minedgelength','float',1,'(0.0,)'], ['CellEntityIdsArrayName','entityidsarray','str',1], ['ElementSizeMode','elementsizemode','str',1,'["edgelength","edgelengtharray"]'], ['CappingMethod','cappingmethod','str',1,'["simple","annular"]'], ['SkipCapping','skipcapping','bool',1,''], ['VolumeElementScaleFactor','volumeelementfactor','float',1,'(0.0,)'], ['BoundaryLayer','boundarylayer','bool',1,''], ['NumberOfSubLayers','sublayers','int',1,'(0,)'], ['BoundaryLayerThicknessFactor','thicknessfactor','float',1,'(0.0,1.0)'], ['RemeshCapsOnly','remeshcapsonly','bool',1,''], ['Tetrahedralize','tetrahedralize','bool',1,''] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['CellEntityIdsArrayName','entityidsarray','str',1], ['RemeshedSurface','remeshedsurface','vtkPolyData',1,'','the output surface','vmtksurfacewriter'], ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') wallEntityOffset = 1 if self.SkipCapping: self.PrintLog("Not capping surface") surface = self.Surface else: self.PrintLog("Capping surface") capper = vmtkscripts.vmtkSurfaceCapper() capper.Surface = self.Surface capper.Interactive = 0 capper.Method = self.CappingMethod capper.TriangleOutput = 0 capper.CellEntityIdOffset = 1 capper.CellEntityIdOffset = wallEntityOffset capper.Execute() surface = capper.Surface self.PrintLog("Remeshing surface") remeshing = vmtkscripts.vmtkSurfaceRemeshing() remeshing.Surface = surface remeshing.CellEntityIdsArrayName = self.CellEntityIdsArrayName remeshing.TargetEdgeLength = self.TargetEdgeLength remeshing.MaxEdgeLength = self.MaxEdgeLength remeshing.MinEdgeLength = self.MinEdgeLength remeshing.TargetEdgeLengthFactor = self.TargetEdgeLengthFactor remeshing.TargetEdgeLengthArrayName = self.TargetEdgeLengthArrayName remeshing.ElementSizeMode = self.ElementSizeMode if self.RemeshCapsOnly: remeshing.ExcludeEntityIds = [wallEntityOffset] remeshing.Execute() if self.BoundaryLayer: projection = vmtkscripts.vmtkSurfaceProjection() projection.Surface = remeshing.Surface projection.ReferenceSurface = surface projection.Execute() normals = vmtkscripts.vmtkSurfaceNormals() normals.Surface = projection.Surface normals.NormalsArrayName = 'Normals' normals.Execute() surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = normals.Surface surfaceToMesh.Execute() self.PrintLog("Generating boundary layer") boundaryLayer = vmtkscripts.vmtkBoundaryLayer() boundaryLayer.Mesh = surfaceToMesh.Mesh boundaryLayer.WarpVectorsArrayName = 'Normals' boundaryLayer.NegateWarpVectors = True boundaryLayer.ThicknessArrayName = self.TargetEdgeLengthArrayName if self.ElementSizeMode == 'edgelength': boundaryLayer.ConstantThickness = True else: boundaryLayer.ConstantThickness = False boundaryLayer.IncludeSurfaceCells = 0 boundaryLayer.NumberOfSubLayers = self.NumberOfSubLayers boundaryLayer.SubLayerRatio = 0.5 boundaryLayer.Thickness = self.BoundaryLayerThicknessFactor * self.TargetEdgeLength boundaryLayer.ThicknessRatio = self.BoundaryLayerThicknessFactor * self.TargetEdgeLengthFactor boundaryLayer.MaximumThickness = self.BoundaryLayerThicknessFactor * self.MaxEdgeLength boundaryLayer.Execute() cellEntityIdsArray = vtk.vtkIntArray() cellEntityIdsArray.SetName(self.CellEntityIdsArrayName) cellEntityIdsArray.SetNumberOfTuples(boundaryLayer.Mesh.GetNumberOfCells()) cellEntityIdsArray.FillComponent(0,0.0) boundaryLayer.Mesh.GetCellData().AddArray(cellEntityIdsArray) innerCellEntityIdsArray = vtk.vtkIntArray() innerCellEntityIdsArray.SetName(self.CellEntityIdsArrayName) innerCellEntityIdsArray.SetNumberOfTuples(boundaryLayer.InnerSurfaceMesh.GetNumberOfCells()) innerCellEntityIdsArray.FillComponent(0,0.0) boundaryLayer.InnerSurfaceMesh.GetCellData().AddArray(cellEntityIdsArray) meshToSurface = vmtkscripts.vmtkMeshToSurface() meshToSurface.Mesh = boundaryLayer.InnerSurfaceMesh meshToSurface.Execute() self.PrintLog("Computing sizing function") sizingFunction = vtkvmtk.vtkvmtkPolyDataSizingFunction() sizingFunction.SetInput(meshToSurface.Surface) sizingFunction.SetSizingFunctionArrayName(self.SizingFunctionArrayName) sizingFunction.SetScaleFactor(self.VolumeElementScaleFactor) sizingFunction.Update() surfaceToMesh2 = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh2.Surface = sizingFunction.GetOutput() surfaceToMesh2.Execute() self.PrintLog("Generating volume mesh") tetgen = vmtkscripts.vmtkTetGen() tetgen.Mesh = surfaceToMesh2.Mesh tetgen.GenerateCaps = 0 tetgen.UseSizingFunction = 1 tetgen.SizingFunctionArrayName = self.SizingFunctionArrayName tetgen.CellEntityIdsArrayName = self.CellEntityIdsArrayName tetgen.Order = 1 tetgen.Quality = 1 tetgen.PLC = 1 tetgen.NoBoundarySplit = 1 tetgen.RemoveSliver = 1 tetgen.OutputSurfaceElements = 0 tetgen.OutputVolumeElements = 1 tetgen.Execute() if tetgen.Mesh.GetNumberOfCells() == 0 and surfaceToMesh.Mesh.GetNumberOfCells() > 0: self.PrintLog('An error occurred during tetrahedralization. Will only output surface mesh and boundary layer.') appendFilter = vtkvmtk.vtkvmtkAppendFilter() appendFilter.AddInput(surfaceToMesh.Mesh) appendFilter.AddInput(boundaryLayer.Mesh) appendFilter.AddInput(tetgen.Mesh) appendFilter.Update() self.Mesh = appendFilter.GetOutput() else: self.PrintLog("Computing sizing function") sizingFunction = vtkvmtk.vtkvmtkPolyDataSizingFunction() sizingFunction.SetInput(remeshing.Surface) sizingFunction.SetSizingFunctionArrayName(self.SizingFunctionArrayName) sizingFunction.SetScaleFactor(self.VolumeElementScaleFactor) sizingFunction.Update() self.PrintLog("Converting surface to mesh") surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = sizingFunction.GetOutput() surfaceToMesh.Execute() self.PrintLog("Generating volume mesh") tetgen = vmtkscripts.vmtkTetGen() tetgen.Mesh = surfaceToMesh.Mesh tetgen.GenerateCaps = 0 tetgen.UseSizingFunction = 1 tetgen.SizingFunctionArrayName = self.SizingFunctionArrayName tetgen.CellEntityIdsArrayName = self.CellEntityIdsArrayName tetgen.Order = 1 tetgen.Quality = 1 tetgen.PLC = 1 tetgen.NoBoundarySplit = 1 tetgen.RemoveSliver = 1 tetgen.OutputSurfaceElements = 1 tetgen.OutputVolumeElements = 1 tetgen.Execute() self.Mesh = tetgen.Mesh if self.Mesh.GetNumberOfCells() == 0 and surfaceToMesh.Mesh.GetNumberOfCells() > 0: self.PrintLog('An error occurred during tetrahedralization. Will only output surface mesh.') self.Mesh = surfaceToMesh.Mesh if self.Tetrahedralize: tetrahedralize = vtk.vtkDataSetTriangleFilter() tetrahedralize.SetInput(self.Mesh) tetrahedralize.Update() self.Mesh = tetrahedralize.GetOutput() self.RemeshedSurface = remeshing.Surface if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshtetrahedralize.py0000664000175000017500000000347511757446472020651 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshtetrahedralize.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes import vtkvmtk vmtkmeshtetrahedralize = 'vmtkMeshTetrahedralize' class vmtkMeshTetrahedralize(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.TetrahedraOnly = 0 self.SetScriptName('vmtkmeshtetrahedralize') self.SetScriptDoc('convert the elements of a mesh to linear') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['TetrahedraOnly','tetonly','bool',1,'','toggle suppression of 1D and 2D cells'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter']]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') tetrahedralizeFilter = vtk.vtkDataSetTriangleFilter() tetrahedralizeFilter.SetInput(self.Mesh) tetrahedralizeFilter.SetTetrahedraOnly(self.TetrahedraOnly) tetrahedralizeFilter.Update() self.Mesh = tetrahedralizeFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtklevelsetsegmentation.py0000664000175000017500000003714411757446472021226 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtklevelsetsegmentation.py,v $ ## Language: Python ## Date: $Date: 2006/05/31 10:51:21 $ ## Version: $Revision: 1.19 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import math import string import vtk import vtkvmtk import vmtkscripts import pypes vmtklevelsetsegmentation = 'vmtkLevelSetSegmentation' class vmtkLevelSetSegmentation(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.vmtkRenderer = None self.OwnRenderer = 0 self.InitialLevelSets = None self.InitializationImage = None self.FeatureImage = None self.LevelSetsInput = None self.LevelSetsOutput = None self.LevelSets = None self.UpperThreshold = 0.0 self.LowerThreshold = 0.0 self.NumberOfIterations = 0 self.PropagationScaling = 0.0 self.CurvatureScaling = 0.0 self.AdvectionScaling = 1.0 self.IsoSurfaceValue = 0.0 self.MaximumRMSError = 1E-20 self.DerivativeSigma = 0.0 self.FeatureDerivativeSigma = 0.0 self.NegateForInitialization = 0 self.SigmoidRemapping = 0 self.LevelSetsType = 'geodesic' self.FeatureImageType = 'gradient' self.UpwindFactor = 1.0 self.FWHMRadius = [1.0, 1.0, 1.0] self.FWHMBackgroundValue = 0.0 self.EdgeWeight = 0.0 self.SmoothingIterations = 5 self.SmoothingTimeStep = 0.1 self.SmoothingConductance = 0.8 self.SetScriptName('vmtklevelsetsegmentation') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','','vmtkimagereader'], ['FeatureImage','featureimage','vtkImageData',1,'','','vmtkimagereader'], ['InitializationImage','initializationimage','vtkImageData',1,'','','vmtkimagereader'], ['InitialLevelSets','initiallevelsets','vtkImageData',1,'','','vmtkimagereader'], ['LevelSets','levelsets','vtkImageData',1,'','','vmtkimagereader'], ['LevelSetsType','levelsetstype','str',1,'["geodesic","curves","threshold","laplacian"]'], ['FeatureImageType','featureimagetype','str',1,'["vtkgradient","gradient","upwind","fwhm"]'], ['NegateForInitialization','negate','bool',1], ['SigmoidRemapping','sigmoid','bool',1], ['IsoSurfaceValue','isosurfacevalue','float',1], ['DerivativeSigma','derivativesigma','float',1,'(0.0,)'], ['FeatureDerivativeSigma','featurederivativesigma','float',1,'(0.0,)'], ['UpwindFactor','upwindfactor','float',1,'(0.0,1.0)'], ['FWHMRadius','fwhmradius','float',3,'(0.0,)'], ['FWHMBackgroundValue','fwhmbackgroundvalue','float',1], ['NumberOfIterations','iterations','int',1,'(0,)'], ['PropagationScaling','propagation','float',1,'(0.0,)'], ['CurvatureScaling','curvature','float',1,'(0.0,)'], ['AdvectionScaling','advection','float',1,'(0.0,)'], ['EdgeWeight','edgeweight','float',1,'(0.0,)'], ['SmoothingIterations','smoothingiterations','int',1,'(0,)'], ['SmoothingTimeStep','smoothingtimestep','float',1,'(0,)'], ['SmoothingConductance','smoothingconductance','float',1,'(0,)'], ['vmtkRenderer','renderer','vmtkRenderer',1] ]) self.SetOutputMembers([ ['LevelSets','o','vtkImageData',1,'','','vmtkimagewriter'], ['FeatureImage','ofeatureimage','vtkImageData',1,'','','vmtkimagewriter'] ]) def ThresholdValidator(self,text): if text == 'n': return 1 if text == 'i': self.vmtkRenderer.Render() return 0 try: float(text) except ValueError: return 0 return 1 def ThresholdInput(self,queryString): thresholdString = self.InputText(queryString,self.ThresholdValidator) threshold = None if thresholdString != 'n': threshold = float(thresholdString) return threshold def PrintProgress(self,obj,event): self.OutputProgress(obj.GetProgress(),10) def LevelSetEvolution(self): if self.LevelSetsType == "geodesic": levelSets = vtkvmtk.vtkvmtkGeodesicActiveContourLevelSetImageFilter() levelSets.SetFeatureImage(self.FeatureImage) levelSets.SetDerivativeSigma(self.FeatureDerivativeSigma) levelSets.SetAutoGenerateSpeedAdvection(1) levelSets.SetPropagationScaling(self.PropagationScaling) levelSets.SetCurvatureScaling(self.CurvatureScaling) levelSets.SetAdvectionScaling(self.AdvectionScaling) elif self.LevelSetsType == "curves": levelSets = vtkvmtk.vtkvmtkCurvesLevelSetImageFilter() levelSets.SetFeatureImage(self.FeatureImage) levelSets.SetDerivativeSigma(self.FeatureDerivativeSigma) levelSets.SetAutoGenerateSpeedAdvection(1) levelSets.SetPropagationScaling(self.PropagationScaling) levelSets.SetCurvatureScaling(self.CurvatureScaling) levelSets.SetAdvectionScaling(self.AdvectionScaling) elif self.LevelSetsType == "threshold": levelSets = vtkvmtk.vtkvmtkThresholdSegmentationLevelSetImageFilter() levelSets.SetFeatureImage(self.Image) queryString = "Please input lower threshold (\'n\' for none): " self.LowerThreshold = self.ThresholdInput(queryString) queryString = "Please input upper threshold (\'n\' for none): " self.UpperThreshold = self.ThresholdInput(queryString) scalarRange = self.Image.GetScalarRange() if self.LowerThreshold != None: levelSets.SetLowerThreshold(self.LowerThreshold) else: levelSets.SetLowerThreshold(scalarRange[0]-1.0) if self.UpperThreshold != None: levelSets.SetUpperThreshold(self.UpperThreshold) else: levelSets.SetUpperThreshold(scalarRange[1]+1.0) levelSets.SetEdgeWeight(self.EdgeWeight) levelSets.SetSmoothingIterations(self.SmoothingIterations) levelSets.SetSmoothingTimeStep(self.SmoothingTimeStep) levelSets.SetSmoothingConductance(self.SmoothingConductance) levelSets.SetPropagationScaling(self.PropagationScaling) levelSets.SetCurvatureScaling(self.CurvatureScaling) elif self.LevelSetsType == "laplacian": levelSets = vtkvmtk.vtkvmtkLaplacianSegmentationLevelSetImageFilter() levelSets.SetFeatureImage(self.Image) levelSets.SetPropagationScaling(-self.PropagationScaling) levelSets.SetCurvatureScaling(self.CurvatureScaling) else: self.PrintError('Unsupported LevelSetsType') levelSets.SetInput(self.LevelSetsInput) levelSets.SetNumberOfIterations(self.NumberOfIterations) levelSets.SetIsoSurfaceValue(self.IsoSurfaceValue) levelSets.SetMaximumRMSError(self.MaximumRMSError) levelSets.SetInterpolateSurfaceLocation(1) levelSets.SetUseImageSpacing(1) levelSets.AddObserver("ProgressEvent", self.PrintProgress) levelSets.Update() self.EndProgress() self.LevelSetsOutput = vtk.vtkImageData() self.LevelSetsOutput.DeepCopy(levelSets.GetOutput()) self.LevelSetsOutput.Update() if self.LevelSetsOutput.GetSource(): self.LevelSetsOutput.GetSource().UnRegisterAllOutputs() def MergeLevelSet(self): if self.LevelSets == None: self.LevelSets = self.LevelSetsOutput else: minFilter = vtk.vtkImageMathematics() minFilter.SetOperationToMin() minFilter.SetInput1(self.LevelSets) minFilter.SetInput2(self.LevelSetsOutput) minFilter.Update() self.LevelSets = minFilter.GetOutput() if self.LevelSets.GetSource(): self.LevelSets.GetSource().UnRegisterAllOutputs() def DisplayLevelSetSurface(self,levelSets,value=0.0): marchingCubes = vtk.vtkMarchingCubes() marchingCubes.SetInput(levelSets) marchingCubes.SetValue(0,value) marchingCubes.Update() self.OutputText('Displaying.\n') self.SurfaceViewer.Surface = marchingCubes.GetOutput() if self.SurfaceViewer.Surface.GetSource(): self.SurfaceViewer.Surface.GetSource().UnRegisterAllOutputs() self.SurfaceViewer.Display = 0 self.SurfaceViewer.Opacity = 0.5 self.SurfaceViewer.BuildView() def YesNoValidator(self,text): if text in ['n','y']: return 1 return 0 def EvolutionParametersValidator(self,text): if not text: return 1 if text in ['q','e']: return 1 splitText = text.strip().split(' ') if len(splitText) not in [1,4]: return 0 try: int(splitText[0]) if len(splitText) == 4: float(splitText[1]) float(splitText[2]) float(splitText[3]) except ValueError: return 0 return 1 def Execute(self): if self.Image == None: self.PrintError('Error: no Image.') cast = vtk.vtkImageCast() cast.SetInput(self.Image) cast.SetOutputScalarTypeToFloat() cast.Update() self.Image = cast.GetOutput() if not self.InitializationImage: self.InitializationImage = self.Image if not self.FeatureImage: if self.LevelSetsType in ["geodesic", "curves"]: imageFeatures = vmtkscripts.vmtkImageFeatures() imageFeatures.Image = self.Image imageFeatures.FeatureImageType = self.FeatureImageType imageFeatures.SigmoidRemapping = self.SigmoidRemapping imageFeatures.DerivativeSigma = self.FeatureDerivativeSigma imageFeatures.UpwindFactor = self.UpwindFactor imageFeatures.FWHMRadius = self.FWHMRadius imageFeatures.FWHMBackgroundValue = self.FWHMBackgroundValue imageFeatures.Execute() self.FeatureImage = imageFeatures.FeatureImage elif self.LevelSetsType in ["threshold", "laplacian"]: self.FeatureImage = self.Image else: self.PrintError('Unsupported LevelSetsType') if self.NumberOfIterations != 0: self.LevelSetsInput = self.InitialLevelSets self.LevelSetEvolution() self.MergeLevelSet() return if not self.vmtkRenderer: self.vmtkRenderer = vmtkscripts.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) self.ImageSeeder = vmtkscripts.vmtkImageSeeder() self.ImageSeeder.vmtkRenderer = self.vmtkRenderer #self.ImageSeeder.Image = self.Image self.ImageSeeder.Image = self.InitializationImage self.ImageSeeder.Display = 0 self.ImageSeeder.Execute() ##self.ImageSeeder.Display = 1 self.ImageSeeder.BuildView() self.SurfaceViewer = vmtkscripts.vmtkSurfaceViewer() self.SurfaceViewer.vmtkRenderer = self.vmtkRenderer if self.LevelSets != None: self.DisplayLevelSetSurface(self.LevelSets,0.0) self.vmtkImageInitialization = vmtkscripts.vmtkImageInitialization() #self.vmtkImageInitialization.Image = self.Image self.vmtkImageInitialization.Image = self.InitializationImage self.vmtkImageInitialization.vmtkRenderer = self.vmtkRenderer self.vmtkImageInitialization.ImageSeeder = self.ImageSeeder self.vmtkImageInitialization.SurfaceViewer = self.SurfaceViewer self.vmtkImageInitialization.NegateImage = self.NegateForInitialization self.vmtkImageInitialization.OwnRenderer = 0 endSegmentation = 0 while (endSegmentation == 0): if self.InitialLevelSets == None: self.vmtkImageInitialization.Execute() self.LevelSetsInput = self.vmtkImageInitialization.InitialLevelSets # self.IsoSurfaceValue = self.vmtkImageInitialization.IsoSurfaceValue self.vmtkImageInitialization.InitialLevelSets = None # self.vmtkImageInitialization.IsosurfaceValue = 0.0 self.IsoSurfaceValue = 0.0 else: self.LevelSetsInput = self.InitialLevelSets self.InitialLevelSets = None self.DisplayLevelSetSurface(self.LevelSetsInput,self.IsoSurfaceValue) endEvolution = False while not endEvolution: queryString = 'Please input parameters (type return to accept current values, \'e\' to end, \'q\' to quit):\nNumberOfIterations('+str(self.NumberOfIterations)+') [PropagationScaling('+str(self.PropagationScaling)+') CurvatureScaling('+str(self.CurvatureScaling)+') AdvectionScaling('+str(self.AdvectionScaling)+')]: ' inputString = self.InputText(queryString,self.EvolutionParametersValidator) if inputString == 'q': return elif inputString == 'e': endEvolution = True elif inputString != '': splitInputString = inputString.strip().split(' ') if len(splitInputString) == 1: self.NumberOfIterations = int(splitInputString[0]) elif len(splitInputString) == 4: self.NumberOfIterations = int(splitInputString[0]) self.PropagationScaling = float(splitInputString[1]) self.CurvatureScaling = float(splitInputString[2]) self.AdvectionScaling = float(splitInputString[3]) else: self.PrintLog('Wrong number of parameters.') continue if endEvolution: break self.LevelSetEvolution() self.DisplayLevelSetSurface(self.LevelSetsOutput) queryString = 'Accept result? (y/n): ' inputString = self.InputText(queryString,self.YesNoValidator) if inputString == 'y': endEvolution = True elif inputString == 'n': endEvolution = False queryString = 'Merge branch? (y/n): ' inputString = self.InputText(queryString,self.YesNoValidator) if inputString == 'y': self.MergeLevelSet() elif inputString == 'n': pass if self.LevelSets != None: self.DisplayLevelSetSurface(self.LevelSets) queryString = 'Segment another branch? (y/n): ' inputString = self.InputText(queryString,self.YesNoValidator) if inputString == 'y': endSegmentation = False elif inputString == 'n': endSegmentation = True if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkpotentialfit.py0000664000175000017500000000730511757446472017463 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkpotentialfit.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:51:28 $ ## Version: $Revision: 1.5 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtkpotentialfit = 'vmtkPotentialFit' class vmtkPotentialFit(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.Image = None self.PotentialImage = None self.NumberOfIterations = 100 self.NumberOfStiffnessSubIterations = 0 self.NumberOfInflationSubIterations = 0 self.PotentialWeight = 1.0 self.StiffnessWeight = 1.0 self.InflationWeight = 1.0 self.Convergence = 1E-5 self.MaxTimeStep = 1.0 self.TimeStep = 1.0 self.AdaptiveTimeStep = 1 self.Relaxation = 1E-1 self.Dimensionality = 3 self.SetScriptName('vmtkpotentialfit') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','','vmtksurfacereader'], ['Image','image','vtkImageData',1,'','','vmtkimagereader'], ['NumberOfIterations','iterations','int',1,'(0,)'], ['NumberOfStiffnessSubIterations','stiffnesssubiterations','int',1,'(0,)'], ['NumberOfInflationSubIterations','inflationsubiterations','int',1,'(0,)'], ['PotentialWeight','potentialweight','float',1,'(0.0,)'], ['StiffnessWeight','stiffnessweight','float',1,'(0.0,)'], ['InflationWeight','inflationweight','float',1,'(0.0,)'], ['Convergence','convergence','float',1,'(0.0,)'], ['MaxTimeStep','maxtimestep','float',1,'(0.0,)'], ['TimeStep','timestep','float',1,'(0.0,)'], ['AdaptiveTimeStep','adaptivetimestep','bool',1], ['Relaxation','relaxation','float',1,'(0.0,)'], ['Dimensionality','dimensionality','int',1,'(2,3)'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def Execute(self): if (self.Image == None): self.PrintError('Error: Image not set.') polyDataPotentialFit = vtkvmtk.vtkvmtkPolyDataPotentialFit() polyDataPotentialFit.SetInput(self.Surface) polyDataPotentialFit.SetPotentialImage(self.Image) polyDataPotentialFit.SetMaxTimeStep(self.MaxTimeStep) polyDataPotentialFit.SetTimeStep(self.TimeStep) polyDataPotentialFit.SetAdaptiveTimeStep(self.AdaptiveTimeStep) polyDataPotentialFit.SetRelaxation(self.Relaxation) polyDataPotentialFit.SetConvergence(self.Convergence) polyDataPotentialFit.SetPotentialWeight(self.PotentialWeight) polyDataPotentialFit.SetStiffnessWeight(self.StiffnessWeight) polyDataPotentialFit.SetInflationWeight(self.InflationWeight) polyDataPotentialFit.SetNumberOfStiffnessSubIterations(self.NumberOfStiffnessSubIterations) polyDataPotentialFit.SetNumberOfInflationSubIterations(self.NumberOfInflationSubIterations) polyDataPotentialFit.SetNumberOfIterations(self.NumberOfIterations) polyDataPotentialFit.SetDimensionality(self.Dimensionality) polyDataPotentialFit.Update() self.Surface = polyDataPotentialFit.GetOutput() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/0000775000175000017500000000000011757446472015140 5ustar lucalucavmtk-1.0.1/vmtkScripts/contrib/vmtkmeshmerge.py0000664000175000017500000000614611757446472020377 0ustar lucaluca#!/usr/bin/env python import sys import math import numpy import vtk from vmtk import pypes from vmtk import vmtkscripts from vmtk import vtkvmtk vmtkmeshmerge = 'vmtkMeshMerge' class vmtkMeshMerge(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.SetScriptName("vmtkmeshmerge") self.SetScriptDoc('Merge two or three meshes into one.') self.Mesh1 = None self.Mesh2 = None self.Mesh3 = None self.Mesh = None self.CellEntityIdsArrayName = "CellEntityIds" self.CellEntityIdOffset1 = 0 self.CellEntityIdOffset2 = 0 self.CellEntityIdOffset3 = 0 # Member info: name, cmdlinename, typename, num, default, desc[, defaultpipetoscript] self.SetInputMembers([ ['Mesh1', 'mesh1', 'vtkUnstructuredGrid', 1, '', 'the first of meshes to merge', 'vmtkmeshreader'], ['Mesh2', 'mesh2', 'vtkUnstructuredGrid', 1, '', 'the second of meshes to merge', 'vmtkmeshreader'], ['Mesh3', 'mesh3', 'vtkUnstructuredGrid', 1, '', '(optional) the third of meshes to merge', 'vmtkmeshreader'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, '', 'name of the array where entity ids have been stored'], ['CellEntityIdOffset1', 'cellentityidoffset1', 'int', 1, '', 'offset added to cell entity ids from mesh1', ''], ['CellEntityIdOffset2', 'cellentityidoffset2', 'int', 1, '', 'offset added to cell entity ids from mesh2', ''], ['CellEntityIdOffset3', 'cellentityidoffset3', 'int', 1, '', 'offset added to cell entity ids from mesh3', ''], ]) self.SetOutputMembers([ ['Mesh', 'o', 'vtkUnstructuredGrid', 1, '', 'the output mesh', 'vmtkmeshwriter'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, '', 'name of the array where entity ids have been stored'], ]) def Execute(self): if self.Mesh1 == None: self.PrintError('Error: No Mesh1.') if self.Mesh2 == None: self.PrintError('Error: No Mesh2.') def addIds(mesh, offset): if offset != 0: cellids = mesh.GetCellData().GetScalars(self.CellEntityIdsArrayName) for i in range(cellids.GetNumberOfTuples()): cellids.SetValue(i, cellids.GetValue(i) + offset) addIds(self.Mesh1, self.CellEntityIdOffset1) addIds(self.Mesh2, self.CellEntityIdOffset2) if self.Mesh3 != None: addIds(self.Mesh3, self.CellEntityIdOffset3) merger = vtkvmtk.vtkvmtkAppendFilter() merger.AddInput(self.Mesh1) merger.AddInput(self.Mesh2) if self.Mesh3 != None: merger.AddInput(self.Mesh3) merger.SetMergeDuplicatePoints(1) merger.Update() self.Mesh = merger.GetOutput() if __name__ == '__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkthreshold.py0000664000175000017500000000527511757446472020421 0ustar lucaluca#!/usr/bin/env python import sys import math import numpy import vtk from vmtk import pypes from vmtk import vmtkscripts vmtkthreshold = 'VmtkThreshold' class VmtkThreshold(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.SetScriptName(vmtkthreshold) self.SetScriptDoc('Extract part of surface or mesh with cell entitiy ids between given thresholds.') self.Surface = None self.Mesh = None self.CellEntityIdsArrayName = 'CellEntityIds' self.LowThreshold = 0 self.HighThreshold = 1 # Member info: name, cmdlinename, typename, num, default, desc[, defaultpipetoscript] self.SetInputMembers([ ['Surface', 'isurface', 'vtkPolyData', 1, '', 'the input surface', 'vmtksurfacereader'], ['Mesh', 'imesh', 'vtkUnstructuredGrid', 1, '', 'the input mesh', 'vmtkmeshreader'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, 'CellEntityIds', 'name of the array where entity ids have been stored'], ['LowThreshold', 'lowthreshold', 'int', 1, '', 'lower threshold for surface filtering', ''], ['HighThreshold', 'highthreshold', 'int', 1, '', 'higher threshold for surface filtering', ''], ]) self.SetOutputMembers([ ['Surface', 'osurface', 'vtkPolyData', 1, '', 'the output surface', 'vmtksurfacewriter'], ['Mesh', 'omesh', 'vtkUnstructuredGrid', 1, '', 'the output mesh', 'vmtkmeshwriter'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, 'CellEntityIds', 'name of the array where entity ids have been stored'], ]) def Execute(self): if self.Surface == None and self.Mesh == None: self.PrintError('Error: No Surface or Mesh.') if self.Surface != None and self.Mesh != None: self.PrintError('Error: Both Surface and Mesh, expecting only one.') input = self.Surface or self.Mesh th = vtk.vtkThreshold() th.SetInput(input) th.SetInputArrayToProcess(0, 0, 0, 1, self.CellEntityIdsArrayName) th.ThresholdBetween(self.LowThreshold, self.HighThreshold) th.Update() if self.Mesh != None: self.Mesh = th.GetOutput() else: assert self.Surface != None gf = vtk.vtkGeometryFilter() gf.SetInput(th.GetOutput()) gf.Update() self.Surface = gf.GetOutput() if __name__ == '__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkmeshclipcenterlines.py0000664000175000017500000006661611757446472022473 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshclipcenterlines.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## Interactively clip a mesh using the distance to centerlines import vtk import sys import vtkvmtk import vtkvmtkcontrib import vmtkrenderer import vmtkscripts import pypes vmtkmeshclipcenterlines = 'vmtkMeshClipCenterlines' class vmtkMeshClipCenterlines(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) #The orignal mesh self.Mesh = None #Preview of the resulting mesh self.PreviewMesh = None #Clipped part of the mesh self.ClippedMesh = None #Which mesh is displayed : 0 intial mesh, 1 preview mesh, 2 clipped mesh self.DisplayedMesh = 0 self.vmtkRenderer = None self.OwnRenderer = 0 self.Clipper = None #self.LineClipper = None self.InsideOut = 1 #Type of polyball : 0 global, 1 local self.PolyBallType = 0 self.CellEntityIdsArrayName = 'CellEntityIds' #Id of the first wall (mesh surface) self.WallCellEntityId = 1 #Should we include the new surface cells self.IncludeSurfaceCells = 1 #Tolerance used for reporjecting the cellentityid array self.Tolerance = -1. self.Centerlines = None self.RadiusArrayName = '' self.RadiusArray = None self.MeshActor = None self.CenterlinesActor = None #Spheres used to drive the radius array interpolation self.SpheresActor = None self.Spheres = vtk.vtkPolyData() self.SpheresIndices = vtk.vtkIdList() self.SpheresRadii = None self.CurrentSphereId = -1 self.SphereWidget = None #Used to display the interpolated spheres self.InterpolatedGlyphs = None self.InterpolatedSpheresActor = None self.PolyBall = None #used to display the polyball function used for clipping self.PolyBallActor = None self.PolyBallResolution = [32, 32, 32] self.SetScriptName('vmtkmeshclipcenterlines') self.SetScriptDoc('interactively clip a mesh using the distance to centerlines') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['Centerlines','centerlines','vtkPolyData',1,'','','vmtksurfacereader'], ['RadiusArrayName','radiusarray','str',1], ['PolyBallType','polyballtype','int',1,'','type of polyball used (0: global, 1: local)'], ['PolyBallResolution','polyballres','int',3,'','grid resolution for displaying the polyball'], ['InsideOut','insideout','bool',1,'','choose whether to clip the inside or outside of the polyball'], ['CellEntityIdsArrayName','entityidsarray','str',1,''], ['WallCellEntityId','wallid','int',1,'','id of the first surface cells in the entityids list'], ['Tolerance','tol','float',1,'','tolerance used to reproject the entity ids on the new surface'] #['IncludeSurfaceCells','includesurfacecells','bool',0,'','include new surface cells in output mesh'], #['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['ClippedMesh','clippedmesh','vtkUnstructuredGrid',1,'','the clipped mesh','vmtkmeshwriter'] ]) def InitializeSpheres(self): #Reset the sphere array self.Spheres.Initialize() spherePoints = vtk.vtkPoints() self.Spheres.SetPoints(spherePoints) self.Spheres.GetPointData().Initialize() self.SpheresIndices.Initialize() self.SpheresRadii = vtk.vtkDoubleArray() self.SpheresRadii.SetName("SpheresRadii") self.Spheres.GetPointData().SetScalars(self.SpheresRadii) self.CurrentSphereId = -1 #Hide the widget self.SphereWidget.Off() #Disable scaling self.InterpolatedGlyphs.SetScaleModeToDataScalingOff() self.InterpolatedGlyphs.SetScaleFactor(0.) #reset the polyball self.PolyBall = None def PlaceSphere(self): if self.CurrentSphereId == -1: return self.SphereWidget.SetCenter(self.Spheres.GetPoint(self.CurrentSphereId)) self.SphereWidget.SetRadius(self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId)) self.SphereWidget.On() def SphereCallback(self,widget,event_string): if self.CurrentSphereId == -1: return minRadius = self.Centerlines.GetLength()*0.001 if self.SphereWidget.GetRadius() < minRadius: self.SphereWidget.SetRadius(minRadius) self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,self.SphereWidget.GetRadius()) self.Spheres.Modified() def InterpolateRadius(self): #if we have no values return if self.SpheresRadii.GetNumberOfTuples() == 0: return; interpolator = vtkvmtkcontrib.vtkvmtkCenterlineInterpolateArray() interpolator.SetInput(self.Centerlines) interpolator.SetValues(self.SpheresRadii) interpolator.SetValuesIds(self.SpheresIndices) interpolator.SetInterpolatedArrayName("InterpolatedRadius") interpolator.Update() self.Centerlines = interpolator.GetOutput() self.Centerlines.GetPointData().SetActiveScalars("InterpolatedRadius") self.InterpolatedGlyphs.SetInput(self.Centerlines) #enable scaling self.InterpolatedGlyphs.SetScaleModeToScaleByScalar() self.InterpolatedGlyphs.SetScaleFactor(1) def BuildPolyBall(self): #if we have no values return if self.SpheresRadii.GetNumberOfTuples() == 0: return #interpolate the radius array self.InterpolateRadius() if self.PolyBallType==1: self.PolyBall = vtkvmtkcontrib.vtkvmtkPolyBallLine2() else: self.PolyBall = vtkvmtk.vtkvmtkPolyBallLine() self.PolyBall.SetInput(self.Centerlines) self.PolyBall.SetUseRadiusInformation(1) self.PolyBall.SetPolyBallRadiusArrayName("InterpolatedRadius") def BuildPolyBallSurface(self): #Build a surface for displaying the polyball if self.PolyBall == None: return #Sample the polyball sampler = vtk.vtkSampleFunction() sampler.SetImplicitFunction(self.PolyBall) #Set the bounds to be slightly larger than those of the mesh meshBounds = self.Mesh.GetBounds() meshCenter = self.Mesh.GetCenter() polyBallBounds = [0, 0, 0, 0, 0, 0] for i in range(0,3): length = 1.2*(meshBounds[2*i+1] - meshCenter[i]) polyBallBounds[2*i] = meshCenter[i] - length polyBallBounds[2*i+1] = meshCenter[i] + length sampler.SetModelBounds(polyBallBounds) sampler.SetSampleDimensions(self.PolyBallResolution) sampler.ComputeNormalsOff() sampler.Update() #Extract the isosurface at 0 contour = vtk.vtkContourFilter() contour.SetInput(sampler.GetOutput()) contour.SetValue(0,0.) contour.Update() #Set the new model as the mapper input self.PolyBallActor.GetMapper().SetInput(contour.GetOutput()) #self.PolyBallActor.VisibilityOn() def ClipMesh(self): #if we have no values simply return the original mesh if self.SpheresRadii.GetNumberOfTuples() == 0: self.PreviewMesh = self.Mesh self.ClippedMesh = None return self.BuildPolyBall() #Update the polyball model if necessary if self.PolyBallActor.GetVisibility(): self.BuildPolyBallSurface() self.Clipper.SetClipFunction(self.PolyBall) self.Clipper.Update() self.PreviewMesh = self.Clipper.GetOutput() self.ClippedMesh = self.Clipper.GetClippedOutput() #Clip the mesh using vtkvmtkClipDataSetLine #def ClipMeshLine(self): ##if we have no values simply return the original mesh #if self.SpheresRadii.GetNumberOfTuples() == 0: #self.PreviewMesh = self.Mesh #self.ClippedMesh = None #return #self.BuildPolyBall() ##Update the polyball model if necessary #if self.PolyBallActor.GetVisibility(): #self.BuildPolyBallSurface() #lineIntersector = vtkvmtkcontrib.vtkvmtkPolyBallLineIntersector() #lineIntersector.SetImplicitFunction(self.PolyBall) #self.LineClipper.SetLineIntersector(lineIntersector) #self.LineClipper.Update() #self.PreviewMesh = self.LineClipper.GetOutput() #self.ClippedMesh = self.LineClipper.GetClippedOutput() #Recreate the surface cells on the clipped and project the cell entity ids def CreateSurfaceCells(self,inMesh): #Remove the surface cells from the mesh cellDimFilter = vtkvmtkcontrib.vtkvmtkCellDimensionFilter() cellDimFilter.SetInput(inMesh) cellDimFilter.ThresholdByUpper(3) cellDimFilter.Update() volumetricMesh = cellDimFilter.GetOutput() #Get new surface cells geomFilter = vtk.vtkGeometryFilter() geomFilter.SetInput(cellDimFilter.GetOutput()) geomFilter.Update() newSurfaceCells = geomFilter.GetOutput() #If the celEntityIdArray exist, project the original entity ids cellEntityIdsArray = newSurfaceCells.GetCellData().GetArray(self.CellEntityIdsArrayName) if (cellEntityIdsArray != None): #Convert the surface cells to poly data surfaceCellsToSurface = vmtkscripts.vmtkMeshToSurface() surfaceCellsToSurface.Mesh = newSurfaceCells surfaceCellsToSurface.Execute() #Get the original surface cells meshThreshold = vtk.vtkThreshold() meshThreshold.SetInput(self.Mesh) meshThreshold.ThresholdByUpper(self.WallCellEntityId+0.5) meshThreshold.SetInputArrayToProcess(0,0,0,1,self.CellEntityIdsArrayName) meshThreshold.Update() meshToSurface = vmtkscripts.vmtkMeshToSurface() meshToSurface.Mesh = meshThreshold.GetOutput() meshToSurface.Execute() #Project the entity ids form the old surface cells to the new surface cells #TODO: This is hackish(need for a tolerance), find a beeter way projector = vtkvmtkcontrib.vtkvmtkSurfaceProjectCellArray() projector.SetInput(surfaceCellsToSurface.Surface) projector.SetReferenceSurface(meshToSurface.Surface) projector.SetProjectedArrayName(self.CellEntityIdsArrayName) projector.SetDefaultValue(self.WallCellEntityId) projector.SetDistanceTolerance(self.Tolerance) projector.Update() #Convert the surface cells back to unstructured grid surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = projector.GetOutput() surfaceToMesh.Execute() newSurfaceCells = surfaceToMesh.Mesh #append the new surface cells to the volumetric elements appendFilter = vtkvmtk.vtkvmtkAppendFilter() appendFilter.AddInput(volumetricMesh) appendFilter.AddInput(newSurfaceCells) appendFilter.Update() return appendFilter.GetOutput() def LCallback(self,obj): self.DisplayedMesh = (self.DisplayedMesh+1)%3 if self.DisplayedMesh == 0: self.MeshActor.GetMapper().SetInput(self.Mesh) elif self.DisplayedMesh == 1: self.MeshActor.GetMapper().SetInput(self.PreviewMesh) elif self.DisplayedMesh == 2: self.MeshActor.GetMapper().SetInput(self.ClippedMesh) self.vmtkRenderer.RenderWindow.Render() def ClipCallback(self, obj): self.ClipMesh() if self.DisplayedMesh == 1: self.MeshActor.GetMapper().SetInput(self.PreviewMesh) elif self.DisplayedMesh == 2: self.MeshActor.GetMapper().SetInput(self.ClippedMesh) self.vmtkRenderer.RenderWindow.Render() #def MCallback(self, obj) #self.ClipMeshLine() #if self.DisplayedMesh == 1: #self.MeshActor.GetMapper().SetInput(self.PreviewMesh) #elif self.DisplayedMesh == 2: #self.MeshActor.GetMapper().SetInput(self.ClippedMesh) #self.vmtkRenderer.RenderWindow.Render() def SpaceCallback(self, obj): #Disable the sphere Widget so as not to pick it self.SphereWidget.Off() #add a new sphere picker = vtk.vtkPointPicker() picker.SetTolerance(1E-3 * self.Centerlines.GetLength()) eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() #eventPosition = obj.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: #Reenable the sphere widget self.SphereWidget.On() return pickId = picker.GetPointId() #Only insert a new sphere if this id is not already in the list if self.SpheresIndices.IsId(pickId) == -1: self.CurrentSphereId = self.Spheres.GetPoints().InsertNextPoint(self.Centerlines.GetPoint(pickId)) self.SpheresIndices.InsertNextId(pickId) interpolatedArray = self.Centerlines.GetPointData().GetArray("InterpolatedRadius") if interpolatedArray and (interpolatedArray.GetValue(pickId) != 0.): self.SpheresRadii.InsertNextValue(interpolatedArray.GetValue(pickId)) elif self.RadiusArray: self.SpheresRadii.InsertNextValue(self.RadiusArray.GetValue(pickId)) else: self.SpheresRadii.InsertNextValue(self.Centerlines.GetLength()*0.01) self.Spheres.Modified() self.PlaceSphere() #Reenable the sphere widget self.SphereWidget.On() self.vmtkRenderer.RenderWindow.Render() def KeyPressed(self,obj,event): key = obj.GetKeySym() if key == 'space': #Disable the sphere Widget so as not to pick it self.SphereWidget.Off() #add a new sphere picker = vtk.vtkPointPicker() picker.SetTolerance(1E-3 * self.Centerlines.GetLength()) eventPosition = obj.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: #Reenable the sphere widget self.SphereWidget.On() return pickId = picker.GetPointId() #Only insert a new sphere if this id is not already in the list if self.SpheresIndices.IsId(pickId) == -1: self.CurrentSphereId = self.Spheres.GetPoints().InsertNextPoint(self.Centerlines.GetPoint(pickId)) self.SpheresIndices.InsertNextId(pickId) interpolatedArray = self.Centerlines.GetPointData().GetArray("InterpolatedRadius") if interpolatedArray and (interpolatedArray.GetValue(pickId) != 0.): self.SpheresRadii.InsertNextValue(interpolatedArray.GetValue(pickId)) elif self.RadiusArray: self.SpheresRadii.InsertNextValue(self.RadiusArray.GetValue(pickId)) else: self.SpheresRadii.InsertNextValue(self.Centerlines.GetLength()*0.01) self.Spheres.Modified() self.PlaceSphere() #Reenable the sphere widget self.SphereWidget.On() self.vmtkRenderer.RenderWindow.Render() def PlusCallback(self, obj): if self.CurrentSphereId != -1: #increase sphere radius newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) + self.Centerlines.GetLength()*0.01 self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def MinusCallback(self, obj): if self.CurrentSphereId != -1: #decrease sphere radius newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) - self.Centerlines.GetLength()*0.01 if newval> 0: self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def NextSphereCallback(self, obj): if self.CurrentSphereId != -1: #skip to next sphere self.CurrentSphereId = (self.CurrentSphereId + 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def ProviousSphereCallback(self, obj): if self.CurrentSphereId != -1: #skip to previous sphere self.CurrentSphereId = (self.CurrentSphereId - 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def UndoCallback(self, obj): #undo self.InitializeSpheres() self.Spheres.Modified() self.vmtkRenderer.RenderWindow.Render() def DeleteSphereCallback(self, obj): if self.CurrentSphereId != -1: #delete the current sphere #if no spheres would be left initialize if self.Spheres.GetNumberOfPoints() == 1: self.InitializeSpheres() else: #Copy the spheres into a new structure oldPoints = vtk.vtkPoints() oldPoints.DeepCopy(self.Spheres.GetPoints()) self.Spheres.Initialize() spherePoints = vtk.vtkPoints() for i in range(0,oldPoints.GetNumberOfPoints()): if i != self.CurrentSphereId: spherePoints.InsertNextPoint(oldPoints.GetPoint(i)) self.Spheres.SetPoints(spherePoints) self.SpheresRadii.RemoveTuple(self.CurrentSphereId) self.Spheres.GetPointData().SetScalars(self.SpheresRadii) self.SpheresIndices.DeleteId(self.SpheresIndices.GetId(i)) self.CurrentSphereId = (self.CurrentSphereId + 1) % self.Spheres.GetNumberOfPoints() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def InterpolatedSphereCallback(self, obj): #Display the interpolated spheres self.InterpolatedSpheresActor.SetVisibility(not self.InterpolatedSpheresActor.GetVisibility()) self.vmtkRenderer.RenderWindow.Render() def PolyballSurfaceCallback(self, obj): #Display/hide the polyball surface if self.PolyBallActor.GetVisibility(): self.PolyBallActor.VisibilityOff() elif self.PolyBall != None: self.BuildPolyBallSurface() self.PolyBallActor.VisibilityOn() self.vmtkRenderer.RenderWindow.Render() def MeshVisalizationCallback(self, obj): #Switch between transparent/opaque mesh for better visualisation if self.MeshActor.GetProperty().GetOpacity() == 0.25: self.MeshActor.GetProperty().SetOpacity(1.) else: self.MeshActor.GetProperty().SetOpacity(0.25) self.vmtkRenderer.RenderWindow.Render() def PolyballVisualizationCallback(self, obj): #Switch between transparent/opaque polyball for better visualisation if self.PolyBallActor.GetProperty().GetOpacity() == 0.25: self.PolyBallActor.GetProperty().SetOpacity(1.) self.MeshActor.VisibilityOff() else: self.PolyBallActor.GetProperty().SetOpacity(0.25) self.MeshActor.VisibilityOn() self.vmtkRenderer.RenderWindow.Render() def PolyballTypeCallback(self, obj): self.PolyBallType = (self.PolyBallType + 1)%2 def Display(self): self.vmtkRenderer.RenderWindowInteractor.Initialize() #self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.vmtkRenderer.AddKeyBinding('f','Change Polyball type',self.PolyballTypeCallback) self.vmtkRenderer.AddKeyBinding('y','Switch between transparent/opaque polyball',self.PolyballVisualizationCallback) self.vmtkRenderer.AddKeyBinding('w','Switch between transparent/opaque mesh',self.MeshVisalizationCallback) self.vmtkRenderer.AddKeyBinding('b','Display/hide the polyball surface',self.PolyballSurfaceCallback) self.vmtkRenderer.AddKeyBinding('o','Display the interpolated spheres',self.InterpolatedSphereCallback) self.vmtkRenderer.AddKeyBinding('d','Delete the current sphere',self.DeleteSphereCallback) self.vmtkRenderer.AddKeyBinding('u','Undo',self.UndoCallback) self.vmtkRenderer.AddKeyBinding('v','Skip to previous sphere',self.ProviousSphereCallback) self.vmtkRenderer.AddKeyBinding('n','skip to next sphere',self.NextSphereCallback) self.vmtkRenderer.AddKeyBinding('minus','Decrease sphere radius',self.MinusCallback) self.vmtkRenderer.AddKeyBinding('plus','Increase sphere radius',self.PlusCallback) self.vmtkRenderer.AddKeyBinding('space','Disable the sphere Widget',self.SpaceCallback) self.vmtkRenderer.AddKeyBinding('c','Clip Mesh',self.ClipCallback) self.vmtkRenderer.AddKeyBinding('l','Change Displayed Mesh',self.LCallback) self.vmtkRenderer.Render() #self.vmtkRenderer.RenderWindowInteractor.Start() def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') if (self.Centerlines == None): self.PrintError('Error: no Centerlines') #Save the centerlines previousCenterlines = self.Centerlines cleaner = vtk.vtkCleanPolyData() cleaner.SetInput(self.Centerlines) cleaner.Update() self.Centerlines = cleaner.GetOutput() if self.Tolerance == -1: self.Tolerance = 0.000001*self.Mesh.GetLength() if self.RadiusArrayName != '': self.RadiusArray = self.Centerlines.GetPointData().GetArray(self.RadiusArrayName) if self.RadiusArray == None: self.PrintError('Error : could not find radius array') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 meshMapper = vtk.vtkDataSetMapper() meshMapper.SetInput(self.Mesh) meshMapper.ScalarVisibilityOff() self.MeshActor = vtk.vtkActor() self.MeshActor.SetMapper(meshMapper) self.MeshActor.GetProperty().SetOpacity(0.25) self.MeshActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.MeshActor) centerlinesMapper = vtk.vtkDataSetMapper() centerlinesMapper.SetInput(self.Centerlines) centerlinesMapper.ScalarVisibilityOff() self.CenterlinesActor = vtk.vtkActor() self.CenterlinesActor.SetMapper(centerlinesMapper) self.vmtkRenderer.Renderer.AddActor(self.CenterlinesActor) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphSource.SetRadius(1) glyphs.SetInput(self.Spheres) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToScaleByScalar() glyphs.SetScaleFactor(1.) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) glyphMapper.ScalarVisibilityOff() self.SpheresActor = vtk.vtkActor() self.SpheresActor.SetMapper(glyphMapper) self.SpheresActor.GetProperty().SetColor(1.0,0.0,0.0) self.SpheresActor.GetProperty().SetOpacity(0.25) self.SpheresActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.SpheresActor) self.InterpolatedGlyphs = vtk.vtkGlyph3D() interpolatedGlyphSource = vtk.vtkSphereSource() interpolatedGlyphSource.SetRadius(1) self.InterpolatedGlyphs.SetInput(self.Centerlines) self.InterpolatedGlyphs.SetSource(interpolatedGlyphSource.GetOutput()) #scaling is off for now self.InterpolatedGlyphs.SetScaleModeToDataScalingOff() self.InterpolatedGlyphs.SetScaleFactor(0.) interpolatedGlyphMapper = vtk.vtkPolyDataMapper() interpolatedGlyphMapper.SetInput(self.InterpolatedGlyphs.GetOutput()) interpolatedGlyphMapper.ScalarVisibilityOff() self.InterpolatedSpheresActor = vtk.vtkActor() self.InterpolatedSpheresActor.SetMapper(interpolatedGlyphMapper) self.InterpolatedSpheresActor.GetProperty().SetColor(0.0,1.0,0.0) self.InterpolatedSpheresActor.GetProperty().SetOpacity(0.25) self.InterpolatedSpheresActor.PickableOff() self.InterpolatedSpheresActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.InterpolatedSpheresActor) polyBallMapper = vtk.vtkPolyDataMapper() polyBallMapper.ScalarVisibilityOff() self.PolyBallActor = vtk.vtkActor() self.PolyBallActor.SetMapper(polyBallMapper) self.PolyBallActor.GetProperty().SetColor(0.0,1.0,0.0) self.PolyBallActor.GetProperty().SetOpacity(0.25) self.PolyBallActor.PickableOff() self.PolyBallActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.PolyBallActor) self.SphereWidget = vtk.vtkSphereWidget() self.SphereWidget.TranslationOff() self.SphereWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.SphereWidget.AddObserver("InteractionEvent", self.SphereCallback) self.Clipper = vtk.vtkClipDataSet() self.Clipper.SetInput(self.Mesh) self.Clipper.SetInsideOut(self.InsideOut) self.Clipper.GenerateClippedOutputOn() #self.LineClipper = vtkvmtk.vtkvmtkClipDataSetLine() #self.LineClipper.SetInput(self.Mesh) #self.LineClipper.SetInsideOut(self.InsideOut) #self.LineClipper.GenerateClippedOutputOn() self.InitializeSpheres() self.PreviewMesh = self.Mesh self.Display() self.PolyBallActor.VisibilityOff() self.ClipMesh() if self.ClippedMesh == None: #return an empty mesh self.ClippedMesh = vtk.vtkUnstructuredGrid() elif self.IncludeSurfaceCells: #Create the surface cells self.PreviewMesh = self.CreateSurfaceCells(self.PreviewMesh) self.ClippedMesh = self.CreateSurfaceCells(self.ClippedMesh) self.Mesh = self.PreviewMesh if self.OwnRenderer: self.vmtkRenderer.Deallocate() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() #Restore the centerlines self.Centerlines = previousCenterlines if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtksurfaceresolution.py0000664000175000017500000003335411757446472022200 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfaceresolution.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This allows the user to specify a edge-length array to be used to specify resolution for surface remeshing ## The array is produced by RBF interpolation of values specified by the user by positioning spheres import vtk import sys import vtkvmtk import vtkvmtkcontrib import vmtkrenderer import pypes vmtksurfaceresolution = 'vmtkSufaceResolution' class vmtkSufaceResolution(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ResolutionArrayName = 'ResolutionArray' self.RBFType = 'biharmonic' self.Spheres = vtk.vtkPolyData() self.vmtkRenderer = None self.OwnRenderer = 0 self.DisplayArray = False self.SurfaceMapper = None self.CurrentSphereId = -1 self.SphereWidget = None self.Opacity = 1. self.SpheresActor = None self.ScalarBarActor = None self.InteractionMode = 0 self.ExamineSurface = None self.ExamineSpheres = vtk.vtkPolyData() self.ExamineSpheresActor = None self.ExamineText = None self.SetScriptName('vtksurfaceresolution') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ResolutionArrayName','resolutionarray','str',1,'','array storing the desired edge length'], ['RBFType','rbftype','str',1,'["thinplatespline","biharmonic","triharmonic"]','the type of RBF interpolation'], ['Opacity','opacity','float',1,'(0.0,1.0)','object opacities in the scene'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def ComputeArray(self): rbf = vtkvmtkcontrib.vtkvmtkRBFInterpolation2() rbf.SetSource(self.Spheres) if self.RBFType == "thinplatespline": rbf.SetRBFTypeToThinPlateSpline() elif self.RBFType == "biharmonic": rbf.SetRBFTypeToBiharmonic() elif self.RBFType == "triharmonic": rbf.SetRBFTypeToTriharmonic() rbf.ComputeCoefficients() sampler = vtkvmtkcontrib.vtkvmtkPolyDataSampleFunction() sampler.SetInput(self.Surface) sampler.SetImplicitFunction(rbf) sampler.SetSampleArrayName(self.ResolutionArrayName) sampler.Update() return sampler.GetOutput() def InitializeSpheres(self): if (self.InteractionMode==0): self.Spheres.Initialize() seedPoints = vtk.vtkPoints() self.Spheres.SetPoints(seedPoints) self.Spheres.GetPointData().Initialize() seedRadii = vtk.vtkDoubleArray() self.Spheres.GetPointData().SetScalars(seedRadii) self.CurrentSphereId = -1 self.SphereWidget.Off() else: self.ExamineSpheres.Initialize() spherePoints = vtk.vtkPoints() self.ExamineSpheres.SetPoints(spherePoints) self.ExamineSpheres.GetPointData().Initialize() sphereRadii = vtk.vtkDoubleArray() self.ExamineSpheres.GetPointData().SetScalars(sphereRadii) def PlaceSphere(self): if self.CurrentSphereId == -1: return self.SphereWidget.SetCenter(self.Spheres.GetPoint(self.CurrentSphereId)) self.SphereWidget.SetRadius(self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId)) def SphereCallback(self,widget,event_string): if self.CurrentSphereId == -1: return minRadius = self.Surface.GetLength()*0.001 if self.SphereWidget.GetRadius() < minRadius: self.SphereWidget.SetRadius(minRadius) self.Spheres.GetPoints().SetPoint(self.CurrentSphereId,self.SphereWidget.GetCenter()) self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,self.SphereWidget.GetRadius()) self.Spheres.Modified() def UndoCallback(self,obj): self.InitializeSpheres() self.Spheres.Modified() self.vmtkRenderer.RenderWindow.Render() def PickCallback(self,obj): picker = vtk.vtkCellPicker() picker.SetTolerance(1E-4 * self.Surface.GetLength()) eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() #eventPosition = obj.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: return pickPosition = picker.GetPickPosition() if (self.InteractionMode==0): self.CurrentSphereId = self.Spheres.GetPoints().InsertNextPoint(pickPosition) self.Spheres.GetPointData().GetScalars().InsertNextValue(self.Surface.GetLength()*0.01) self.Spheres.Modified() self.PlaceSphere() self.SphereWidget.On() else: pickedCellPointIds = self.Surface.GetCell(picker.GetCellId()).GetPointIds() minDistance = 1E10 pickedPointId = -1 for i in range(pickedCellPointIds.GetNumberOfIds()): distance = vtk.vtkMath.Distance2BetweenPoints(pickPosition,self.Surface.GetPoint(pickedCellPointIds.GetId(i))) if distance < minDistance: minDistance = distance pickedPointId = pickedCellPointIds.GetId(i) if pickedPointId == -1: pickedPointId = pickedCellPointIds.GetId(0) point = self.Surface.GetPoint(pickedPointId) self.ExamineSpheres.GetPoints().InsertNextPoint(point) length = 0. array = self.ExamineSurface.GetPointData().GetArray(self.ResolutionArrayName) if (array): length = array.GetComponent(pickedPointId,0) self.ExamineSpheres.GetPointData().GetScalars().InsertNextValue(length) self.ExamineSpheres.Modified() self.vmtkRenderer.RenderWindow.Render() def IncreaseSphereRadiusCallback(self,obj): if self.CurrentSphereId != -1: newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) + self.Surface.GetLength()*0.01 self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def DecreaseSphereRadiusCallback(self,obj): if self.CurrentSphereId != -1: newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) - self.Surface.GetLength()*0.01 if newval> 0: self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def NextCallback(self,obj): if self.CurrentSphereId != -1: self.CurrentSphereId = (self.CurrentSphereId + 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def PreviousCallback(self,obj): if self.CurrentSphereId != -1: self.CurrentSphereId = (self.CurrentSphereId - 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def DistancesCallback(self,obj): self.DisplayArray = not self.DisplayArray if self.DisplayArray: self.ExamineSurface = self.ComputeArray() self.SurfaceMapper.SetInput(self.ExamineSurface) self.ExamineSurface.GetPointData().SetActiveScalars(self.ResolutionArrayName) array = self.ExamineSurface.GetPointData().GetScalars() if (array): array.Modified() self.SurfaceMapper.SetScalarRange(array.GetRange(0)) self.ScalarBarActor.VisibilityOn() else: self.SurfaceMapper.SetInput(self.Surface) self.ScalarBarActor.VisibilityOff() self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) self.vmtkRenderer.RenderWindow.Render() def ExamineCallback(self,obj): #Switch beetween examien and interact mode if self.InteractionMode == 0: self.InteractionMode = 1 self.ExamineSurface = self.ComputeArray() #self.SpheresActor.VisibilityOff() self.SphereWidget.Off() self.ExamineSpheresActor.VisibilityOn() self.ExamineText.VisibilityOn() self.InitializeSpheres() else: self.InteractionMode = 0 #Compute the distances self.SpheresActor.VisibilityOn() self.ExamineSpheresActor.VisibilityOff() self.ExamineText.VisibilityOff() if (self.CurrentSphereId!=-1): self.SphereWidget.On() self.vmtkRenderer.RenderWindow.Render() def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphSource.SetRadius(1) glyphs.SetInput(self.Spheres) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToScaleByScalar() glyphs.SetScaleFactor(1.) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) glyphMapper.ScalarVisibilityOff() self.SpheresActor = vtk.vtkActor() self.SpheresActor.SetMapper(glyphMapper) self.SpheresActor.GetProperty().SetColor(1.0,0.0,0.0) self.SpheresActor.GetProperty().SetOpacity(self.Opacity) self.SpheresActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.SpheresActor) examineGlyphs = vtk.vtkGlyph3D() examineGlyphSource = vtk.vtkSphereSource() examineGlyphSource.SetRadius(1) examineGlyphs.SetInput(self.ExamineSpheres) examineGlyphs.SetSource(examineGlyphSource.GetOutput()) examineGlyphs.SetScaleModeToScaleByScalar() examineGlyphs.SetScaleFactor(1.) examineGlyphMapper = vtk.vtkPolyDataMapper() examineGlyphMapper.SetInput(examineGlyphs.GetOutput()) examineGlyphMapper.ScalarVisibilityOff() self.ExamineSpheresActor = vtk.vtkActor() self.ExamineSpheresActor.SetMapper(examineGlyphMapper) self.ExamineSpheresActor.GetProperty().SetColor(0.0,1.0,0.0) self.ExamineSpheresActor.GetProperty().SetOpacity(self.Opacity) self.ExamineSpheresActor.PickableOff() self.ExamineSpheresActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ExamineSpheresActor) self.vmtkRenderer.AddKeyBinding('u','Undo.',self.UndoCallback) self.vmtkRenderer.AddKeyBinding('space','Place picks.',self.PickCallback) self.vmtkRenderer.AddKeyBinding('+','Increase sphere radius.',self.IncreaseSphereRadiusCallback) self.vmtkRenderer.AddKeyBinding('-','Decrease sphere radius.',self.DecreaseSphereRadiusCallback) self.vmtkRenderer.AddKeyBinding('n','Skip to next sphere.',self.NextCallback) self.vmtkRenderer.AddKeyBinding('v','Skip to previous sphere.',self.PreviousCallback) self.vmtkRenderer.AddKeyBinding('d','Show distances graph.',self.DistancesCallback) self.vmtkRenderer.AddKeyBinding('x','Examine mode.',self.ExamineCallback) #self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.SurfaceMapper = vtk.vtkPolyDataMapper() self.SurfaceMapper.SetInput(self.Surface) self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(self.SurfaceMapper) surfaceActor.GetProperty().SetOpacity(self.Opacity) self.vmtkRenderer.Renderer.AddActor(surfaceActor) self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.SurfaceMapper.GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() self.ScalarBarActor.SetLabelFormat('%.2f') self.ScalarBarActor.SetTitle('distances') self.ScalarBarActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) self.SphereWidget = vtk.vtkSphereWidget() self.SphereWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.SphereWidget.AddObserver("InteractionEvent", self.SphereCallback) self.ExamineText = vtk.vtkTextActor() self.ExamineText.SetInput("Examine Mode") self.ExamineText.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() self.ExamineText.SetPosition(0.05,0.95) self.ExamineText.VisibilityOff() self.vmtkRenderer.Renderer.AddActor2D(self.ExamineText) self.InputInfo('Please position the mouse and press space to add spheres, \'u\' to undo\n') any = 0 while any == 0: self.InitializeSpheres() self.vmtkRenderer.Render() any = (self.Spheres.GetNumberOfPoints()>1) self.InputInfo('Please position the mouse and press space to add spheres, \'u\' to undo\nInsert at least 2 spheres.') self.Surface = self.ComputeArray() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkmeshtetrahedralize2.py0000664000175000017500000000406311757446472022365 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshtetrahedralize2.py,v $ ## Language: Python ## Date: $Date: 2006/07/17 09:53:14 $ ## Version: $Revision: 1.1 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## Bug fix for VTK 5.0 import vtk import sys import pypes from vmtk import vtkvmtk vmtkmeshtetrahedralize2 = 'vmtkMeshTetrahedralize2' class vmtkMeshTetrahedralize2(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.TetrahedraOnly = 0 self.SetScriptName('vmtkmeshtetrahedralize') self.SetScriptDoc('convert the elements of a mesh to linear') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['TetrahedraOnly','tetonly','bool',1,'','toggle suppression of 1D and 2D cells'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter']]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') tetrahedralizeFilter = vtk.vtkDataSetTriangleFilter() tetrahedralizeFilter.SetInput(self.Mesh) if ((vtk.vtkVersion.GetVTKMajorVersion()>=5) and (vtk.vtkVersion.GetVTKMinorVersion()>0)): tetrahedralizeFilter.SetTetrahedraOnly(self.TetrahedraOnly) tetrahedralizeFilter.Update() self.Mesh = tetrahedralizeFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtksurfaceextractinnercylinder.py0000664000175000017500000001110711757446472024225 0ustar lucaluca#!/usr/bin/env python import sys import math import numpy import vtk from vmtk import pypes from vmtk import vmtkscripts vmtksurfaceextractinnercylinder = 'VmtkSurfaceExtractInnerCylinder' class VmtkSurfaceExtractInnerCylinder(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.SetScriptName(vmtksurfaceextractinnercylinder) self.SetScriptDoc('Extract inner surface from an annular-cylindric volume.') # Define members self.Surface = None self.DoubleSurface = None self.ColoredSurface = None self.InnerSurface = None self.CellEntityIdsArrayName = 'CellEntityIds' self.EndcapsThresholdLow = 0 self.EndcapsThresholdHigh = 1 # Potential output values self.InnerRegionId = None # Member info: name, cmdlinename, typename, num, default, desc[, defaultpipetoscript] self.SetInputMembers([ ['Surface', 'i', 'vtkPolyData', 1, '', 'the input surface', 'vmtksurfacereader'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, '', 'name of the array where entity ids have been stored'], ['EndcapsThresholdLow', 'lowthreshold', 'int', 1, '', 'lower threshold for encaps filtering', ''], ['EndcapsThresholdHigh', 'highthreshold', 'int', 1, '', 'higher threshold for encaps filtering', ''], ]) self.SetOutputMembers([ ['DoubleSurface', 'doublesurface', 'vtkPolyData', 1, '', 'the double surface without caps', 'vmtksurfacewriter'], ['ColoredSurface', 'coloredsurface', 'vtkPolyData', 1, '', 'the colored surface', 'vmtksurfacewriter'], ['InnerSurface', 'o', 'vtkPolyData', 1, '', 'the innermost surface', 'vmtksurfacewriter'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, '', 'name of the array where entity ids have been stored'], ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') self.removeEndCaps() self.colorSurfaceRegions() self.extractInnerSurface() def removeEndCaps(self): self.PrintLog("Using thresholding to remove endcaps.") th = vtk.vtkThreshold() th.SetInput(self.Surface) th.SetInputArrayToProcess(0, 0, 0, 1, self.CellEntityIdsArrayName) th.ThresholdBetween(self.EndcapsThresholdLow, self.EndcapsThresholdHigh) th.Update() gf = vtk.vtkGeometryFilter() gf.SetInput(th.GetOutput()) gf.Update() self.DoubleSurface = gf.GetOutput() def colorSurfaceRegions(self): self.PrintLog("Coloring surface regions.") connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInput(self.DoubleSurface) connectivityFilter.ColorRegionsOn() connectivityFilter.SetExtractionModeToAllRegions() connectivityFilter.Update() assert connectivityFilter.GetNumberOfExtractedRegions() == 2 self.ColoredSurface = connectivityFilter.GetOutput() def extractInnerSurface(self): self.PrintLog("Extracting inner surface.") def bnorm(data): bounds = data.GetBounds() return math.sqrt(sum((bounds[2*i+1]-bounds[2*i])**2 for i in range(3))) # Get bounds of entire surface bounds_norm = bnorm(self.Surface) # Currently assuming that this is the region numbers that were produced by coloring! # TODO: If necessary, get from array to be more robust. region_ids = (0, 1) # Extract each surface in turn to find the smallest one for k in region_ids: connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInput(self.ColoredSurface) connectivityFilter.SetExtractionModeToSpecifiedRegions() connectivityFilter.AddSpecifiedRegion(k) connectivityFilter.ColorRegionsOff() connectivityFilter.SetScalarConnectivity(0) connectivityFilter.Update() subsurface = connectivityFilter.GetOutput() # The inner surface has smaller bounds if bnorm(subsurface) < bounds_norm - 1e-12: self.InnerRegionId = k self.InnerSurface = subsurface break assert self.InnerRegionId in region_ids if __name__ == '__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkmeshviewer2.py0000664000175000017500000002664711757446472020673 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshviewer2.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This class is a slightly modified version of vmtkmeshviewer ## which allows for per-cell array visualization, mesh clipping ## and thresholding based on array values. import vtk import sys import vmtkrenderer import pypes vmtkmeshviewer2 = 'vmtkMeshViewer2' class vmtkMeshViewer2(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.vmtkRenderer = None self.OwnRenderer = 0 self.Display = 1 self.Opacity = 1.0 self.ArrayName = '' self.ScalarRange = [0.0, 0.0] self.Legend = 0 self.Grayscale = 0 self.FlatInterpolation = 0 self.DisplayCellData = 0 self.Color = [-1.0, -1.0, -1.0] self.Threshold = float('-Inf') self.ThresholdUpper = True self.DoThreshold = False self.ThresholdedMesh = None self.InitialMesh = None self.PlaneWidget = None self.InteractiveClip = False self.ClipExtract = False self.InsideOut = False self.ObserverId = -1 self.Actor = None self.ScalarBarActor = None self.SetScriptName('vmtkmeshviewer') self.SetScriptDoc('display a mesh') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'], ['Display','display','bool',1,'','toggle rendering'], ['Opacity','opacity','float',1,'(0.0,1.0)','object opacity in the scene'], ['ArrayName','array','str',1,'','name of the array where the scalars to be displayed are stored'], ['ScalarRange','scalarrange','float',2,'','range of the scalar map'], ['Legend','legend','bool',1,'','toggle scalar bar'], ['Grayscale','grayscale','bool',1,'','toggle color or grayscale'], ['FlatInterpolation','flat','bool',1,'','toggle flat or shaded surface display'], ['DisplayCellData','celldata','bool',1,'','toggle display of point or cell data'], ['Color','color','float',3,'','RGB color of the object in the scene'], ['Threshold','threshold','float',1,'','threshold to apply to the array when pressing t'], ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def ClipMesh(self): meshClipFilter = vtk.vtkClipDataSet() meshClipFilter.SetInput(self.Mesh) meshClipFilter.SetInsideOut(self.InsideOut) clipPlane = vtk.vtkPlane() self.PlaneWidget.GetPlane(clipPlane) meshClipFilter.SetClipFunction(clipPlane) meshClipFilter.Update() return meshClipFilter.GetOutput() def ExtractMesh(self): meshExtractFilter = vtk.vtkExtractGeometry() meshExtractFilter.SetInput(self.Mesh) meshExtractFilter.SetExtractInside(self.InsideOut) clipPlane = vtk.vtkPlane() self.PlaneWidget.GetPlane(clipPlane) meshExtractFilter.SetImplicitFunction(clipPlane) meshExtractFilter.Update() return meshExtractFilter.GetOutput() def ThresholdMesh(self): thresholder = vtk.vtkThreshold() thresholder.SetInput(self.InitialMesh) if (self.ThresholdUpper): thresholder.ThresholdByUpper(self.Threshold) else: thresholder.ThresholdByLower(self.Threshold) thresholder.SetInputArrayToProcess(0,0,0,1,self.ArrayName) thresholder.Update() self.Mesh = thresholder.GetOutput() def PlaneCallback(self,widget,event_string): if self.ClipExtract: self.Actor.GetMapper().SetInput(self.ExtractMesh()) else: self.Actor.GetMapper().SetInput(self.ClipMesh()) def InteractCallback(self,obj): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def ClipCallback(self,obj): if self.Mesh != None: self.ClipExtract = False if self.PlaneWidget.GetEnabled(): self.Actor.GetMapper().SetInput(self.ClipMesh()) else: self.Actor.GetMapper().SetInput(self.Mesh) self.vmtkRenderer.RenderWindow.Render() def ExtractCallback(self,obj): if self.Mesh: self.ClipExtract = True if self.PlaneWidget.GetEnabled(): self.Actor.GetMapper().SetInput(self.ExtractMesh()) else: self.Actor.GetMapper().SetInput(self.Mesh) self.vmtkRenderer.RenderWindow.Render() def NCallback(self,obj): if self.Actor.GetMapper() != None: self.InteractiveClip = not self.InteractiveClip if self.InteractiveClip: self.ObserverId = self.PlaneWidget.AddObserver("InteractionEvent",self.PlaneCallback) self.PlaneWidget.On() self.PlaneWidget.InvokeEvent('InteractionEvent') elif self.ObserverId != -1: self.PlaneWidget.RemoveObserver(self.ObserverId) self.ObserverId = -1 self.PlaneWidget.Off() self.Actor.GetMapper().SetInput(self.Mesh) self.vmtkRenderer.RenderWindow.Render() def DCallback(self,obj): if self.PlaneWidget.GetEnabled(): self.InsideOut = not self.InsideOut self.PlaneWidget.InvokeEvent('InteractionEvent') self.vmtkRenderer.RenderWindow.Render() def TCallback(self,obj): if self.Mesh and self.ArrayName != '': #has the mesh been clipped? isClipped = (self.Actor.GetMapper().GetInput() != self.Mesh) self.DoThreshold = not self.DoThreshold if self.DoThreshold: self.ThresholdMesh() else: self.Mesh = self.InitialMesh #Redo the clipping if the mesh was clipped if isClipped: if self.ClipExtract: self.Actor.GetMapper().SetInput(self.ExtractMesh()) else: self.Actor.GetMapper().SetInput(self.ClipMesh()) else: self.Actor.GetMapper().SetInput(self.Mesh) self.vmtkRenderer.RenderWindow.Render() def UndoCallback(self,obj): self.ThresholdUpper = not self.ThresholdUpper if self.DoThreshold: isClipped = (self.Actor.GetMapper().GetInput() != self.Mesh) self.ThresholdMesh() if isClipped: if self.ClipExtract: self.Actor.GetMapper().SetInput(self.ExtractMesh()) else: self.Actor.GetMapper().SetInput(self.ClipMesh()) else: self.Actor.GetMapper().SetInput(self.Mesh) self.vmtkRenderer.RenderWindow.Render() def BuildView(self): if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 if self.Actor != None: self.vmtkRenderer.Renderer.RemoveActor(self.Actor) if self.ScalarBarActor != None: self.vmtkRenderer.Renderer.RemoveActor(self.ScalarBarActor) if self.Mesh != None: self.InitialMesh = self.Mesh self.DisplayMesh = self.Mesh mapper = vtk.vtkDataSetMapper() mapper.SetInput(self.DisplayMesh) array = None if (self.ArrayName != ''): if self.DisplayCellData == 0: self.Mesh.GetPointData().SetActiveScalars(self.ArrayName) array = self.Mesh.GetPointData().GetScalars() else: self.Mesh.GetCellData().SetActiveScalars(self.ArrayName) array = self.Mesh.GetCellData().GetScalars() mapper.SetScalarModeToUseCellData() if (array != None): if (self.ScalarRange[1] > self.ScalarRange[0]): mapper.SetScalarRange(self.ScalarRange) else: mapper.SetScalarRange(array.GetRange(0)) if (self.Grayscale == 1): lut = vtk.vtkLookupTable() lut.SetValueRange(0.0,1.0) lut.SetSaturationRange(0.0,0.0) mapper.SetLookupTable(lut) self.Actor = vtk.vtkActor() self.Actor.SetMapper(mapper) if (self.Color[0] >= 0.0): self.Actor.GetProperty().SetColor(self.Color) if (self.FlatInterpolation == 1): self.Actor.GetProperty().SetInterpolationToFlat() self.Actor.GetProperty().SetOpacity(self.Opacity) self.vmtkRenderer.Renderer.AddActor(self.Actor) if (self.Legend == 1) & (self.Actor != None): self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.Actor.GetMapper().GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() ## self.ScalarBarActor.GetLabelTextProperty().SetColor(0.0,0.0,0.0) self.ScalarBarActor.SetLabelFormat('%.2f') self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) #self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.vmtkRenderer.AddKeyBinding('i','Interact.',self.InteractCallback) self.vmtkRenderer.AddKeyBinding('c','Clip.',self.ClipCallback) self.vmtkRenderer.AddKeyBinding('e','Extract.',self.ExtractCallback) self.vmtkRenderer.AddKeyBinding('n','Show clipped area.',self.NCallback) self.vmtkRenderer.AddKeyBinding('d','Switch clipped/unclipped area.',self.DCallback) self.vmtkRenderer.AddKeyBinding('t','Redo.',self.TCallback) self.vmtkRenderer.AddKeyBinding('u','Undo.',self.UndoCallback) self.PlaneWidget = vtk.vtkImplicitPlaneWidget() self.PlaneWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidget.SetPlaceFactor(1.25) self.PlaneWidget.DrawPlaneOff() self.PlaneWidget.SetProp3D(self.Actor) self.PlaneWidget.PlaceWidget() #Work around bug/strange behaviour in vtk self.PlaneWidget.SetOrigin(self.Actor.GetCenter()) if (self.Display == 1): self.vmtkRenderer.Render() self.Mesh = self.InitialMesh if self.OwnRenderer: self.vmtkRenderer.Deallocate() def Execute(self): if (self.Mesh == None) & (self.Display == 1): self.PrintError('Error: no Mesh.') self.BuildView() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkdistancetospheres.py0000664000175000017500000003641311757446472022152 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkdistancetospheres.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This class computes the euclidean from a set of user-selected spheres to a surface import vtk import sys import vtkvmtk import vtkvmtkcontrib import vmtkrenderer import pypes vmtkdistancetospheres = 'vmtkDistanceToSpheres' class vmtkDistanceToSpheres(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.DistanceToSpheresArrayName = 'DistanceToSpheres' self.DistanceOffset = 0. self.DistanceScale = 1. self.MinDistance = 0. self.MaxDistance = -1. self.Spheres = vtk.vtkPolyData() self.vmtkRenderer = None self.OwnRenderer = 0 self.DisplayArray = False self.SurfaceMapper = None self.CurrentSphereId = -1 self.SphereWidget = None self.Opacity = 1. self.SpheresActor = None self.ScalarBarActor = None self.InteractionMode = 0 self.ExamineSurface = None self.ExamineSpheres = vtk.vtkPolyData() self.ExamineSpheresActor = None self.ExamineText = None self.SetScriptName('vmtkdistancetospheres') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['DistanceToSpheresArrayName','distancetospheresarray','str',1,'','array storing the distances'], ['DistanceOffset','offset','float',1,'','offset added to the distances'], ['DistanceScale','scale','float',1.,'','scale applied to the distances'], ['MinDistance','mindistance','float',1,'','minimum value for the distances'], ['MaxDistance','maxdistance','float',1,'','maximum value for the distances'], ['Opacity','opacity','float',1,'(0.0,1.0)','object opacities in the scene'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def DistanceParametersValidator(self,text): if not text: return 1 splitText = text.strip().split(' ') if len(splitText) not in range(1,5): return 0 try: for i in range(1,len(splitText)+1): float(splitText[i-1]) except ValueError: return 0 return 1 def ComputeDistances(self): distanceToSpheresFilter = vtkvmtkcontrib.vtkvmtkPolyDataDistanceToSpheres() distanceToSpheresFilter.SetInput(self.Surface) distanceToSpheresFilter.SetSpheres(self.Spheres) distanceToSpheresFilter.SetDistanceOffset(self.DistanceOffset) distanceToSpheresFilter.SetDistanceScale(self.DistanceScale) distanceToSpheresFilter.SetMinDistance(self.MinDistance); distanceToSpheresFilter.SetMaxDistance(self.MaxDistance); distanceToSpheresFilter.SetDistanceToSpheresArrayName(self.DistanceToSpheresArrayName) distanceToSpheresFilter.Update() return distanceToSpheresFilter.GetOutput() def InitializeSpheres(self): if (self.InteractionMode==0): self.Spheres.Initialize() seedPoints = vtk.vtkPoints() self.Spheres.SetPoints(seedPoints) self.Spheres.GetPointData().Initialize() seedRadii = vtk.vtkDoubleArray() self.Spheres.GetPointData().SetScalars(seedRadii) self.CurrentSphereId = -1 self.SphereWidget.Off() else: self.ExamineSpheres.Initialize() spherePoints = vtk.vtkPoints() self.ExamineSpheres.SetPoints(spherePoints) self.ExamineSpheres.GetPointData().Initialize() sphereRadii = vtk.vtkDoubleArray() self.ExamineSpheres.GetPointData().SetScalars(sphereRadii) def PlaceSphere(self): if self.CurrentSphereId == -1: return self.SphereWidget.SetCenter(self.Spheres.GetPoint(self.CurrentSphereId)) self.SphereWidget.SetRadius(self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId)) def SphereCallback(self,widget,event_string): if self.CurrentSphereId == -1: return minRadius = self.Surface.GetLength()*0.001 if self.SphereWidget.GetRadius() < minRadius: self.SphereWidget.SetRadius(minRadius) self.Spheres.GetPoints().SetPoint(self.CurrentSphereId,self.SphereWidget.GetCenter()) self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,self.SphereWidget.GetRadius()) self.Spheres.Modified() def UndoCallback(self,obj): self.InitializeSpheres() self.Spheres.Modified() self.vmtkRenderer.RenderWindow.Render() def PickCallback(self,obj): picker = vtk.vtkCellPicker() picker.SetTolerance(1E-4 * self.Surface.GetLength()) eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() #eventPosition = obj.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: return pickPosition = picker.GetPickPosition() if (self.InteractionMode==0): self.CurrentSphereId = self.Spheres.GetPoints().InsertNextPoint(pickPosition) self.Spheres.GetPointData().GetScalars().InsertNextValue(self.Surface.GetLength()*0.01) self.Spheres.Modified() self.PlaceSphere() self.SphereWidget.On() else: pickedCellPointIds = self.Surface.GetCell(picker.GetCellId()).GetPointIds() minDistance = 1E10 pickedPointId = -1 for i in range(pickedCellPointIds.GetNumberOfIds()): distance = vtk.vtkMath.Distance2BetweenPoints(pickPosition,self.Surface.GetPoint(pickedCellPointIds.GetId(i))) if distance < minDistance: minDistance = distance pickedPointId = pickedCellPointIds.GetId(i) if pickedPointId == -1: pickedPointId = pickedCellPointIds.GetId(0) point = self.Surface.GetPoint(pickedPointId) self.ExamineSpheres.GetPoints().InsertNextPoint(point) length = 0. array = self.ExamineSurface.GetPointData().GetArray(self.DistanceToSpheresArrayName) if (array): length = array.GetComponent(pickedPointId,0) self.ExamineSpheres.GetPointData().GetScalars().InsertNextValue(length) self.ExamineSpheres.Modified() self.vmtkRenderer.RenderWindow.Render() def IncreaseSphereRadiusCallback(self,obj): if self.CurrentSphereId != -1: #increase sphere radius newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) + self.Surface.GetLength()*0.01 self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def DecreaseSphereRadiusCallback(self,obj): if self.CurrentSphereId != -1: #decrease sphere radius newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) - self.Surface.GetLength()*0.01 if newval> 0: self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def NextCallback(self,obj): if self.CurrentSphereId != -1: self.CurrentSphereId = (self.CurrentSphereId + 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def PreviousCallback(self,obj): if self.CurrentSphereId != -1: self.CurrentSphereId = (self.CurrentSphereId - 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def DistancesCallback(self,obj): self.DisplayArray = not self.DisplayArray if self.DisplayArray: self.ExamineSurface = self.ComputeDistances() self.SurfaceMapper.SetInput(self.ExamineSurface) self.ExamineSurface.GetPointData().SetActiveScalars(self.DistanceToSpheresArrayName) array = self.ExamineSurface.GetPointData().GetScalars() if (array): array.Modified() self.SurfaceMapper.SetScalarRange(array.GetRange(0)) self.ScalarBarActor.VisibilityOn() else: self.SurfaceMapper.SetInput(self.Surface) self.ScalarBarActor.VisibilityOff() self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) self.vmtkRenderer.RenderWindow.Render() def ParametersCallback(self,obj): queryString = 'Please input new parameters :\nDistanceOffset('+str(self.DistanceOffset)+') [DistanceScale('+str(self.DistanceScale)+') MinDistance('+str(self.MinDistance)+') MaxDistance('+str(self.MaxDistance)+'): ' inputString = self.InputText(queryString,self.DistanceParametersValidator) splitInputString = inputString.strip().split(' ') if len(splitInputString) >= 1 and splitInputString[0] != '': self.DistanceOffset = float(splitInputString[0]) if len(splitInputString) >= 2: self.DistanceScale = float(splitInputString[1]) if len(splitInputString) >= 3: self.MinDistance = float(splitInputString[2]) if len(splitInputString) >= 4: self.MaxDistance = float(splitInputString[3]) def SwitchModeCallback(self,obj): #Switch beetween examien and interact mode if self.InteractionMode == 0: self.InteractionMode = 1 self.ExamineSurface = self.ComputeDistances() self.SpheresActor.VisibilityOff() self.SphereWidget.Off() self.ExamineSpheresActor.VisibilityOn() self.ExamineText.VisibilityOn() self.InitializeSpheres() else: self.InteractionMode = 0 #Compute the distances self.SpheresActor.VisibilityOn() self.ExamineSpheresActor.VisibilityOff() self.ExamineText.VisibilityOff() if (self.CurrentSphereId!=-1): self.SphereWidget.On() self.vmtkRenderer.RenderWindow.Render() def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphSource.SetRadius(1) glyphs.SetInput(self.Spheres) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToScaleByScalar() glyphs.SetScaleFactor(1.) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) glyphMapper.ScalarVisibilityOff() self.SpheresActor = vtk.vtkActor() self.SpheresActor.SetMapper(glyphMapper) self.SpheresActor.GetProperty().SetColor(1.0,0.0,0.0) self.SpheresActor.GetProperty().SetOpacity(self.Opacity) self.SpheresActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.SpheresActor) examineGlyphs = vtk.vtkGlyph3D() examineGlyphSource = vtk.vtkSphereSource() examineGlyphSource.SetRadius(1) examineGlyphs.SetInput(self.ExamineSpheres) examineGlyphs.SetSource(examineGlyphSource.GetOutput()) examineGlyphs.SetScaleModeToScaleByScalar() examineGlyphs.SetScaleFactor(1.) examineGlyphMapper = vtk.vtkPolyDataMapper() examineGlyphMapper.SetInput(examineGlyphs.GetOutput()) examineGlyphMapper.ScalarVisibilityOff() self.ExamineSpheresActor = vtk.vtkActor() self.ExamineSpheresActor.SetMapper(examineGlyphMapper) self.ExamineSpheresActor.GetProperty().SetColor(0.0,1.0,0.0) self.ExamineSpheresActor.GetProperty().SetOpacity(self.Opacity) self.ExamineSpheresActor.PickableOff() self.ExamineSpheresActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ExamineSpheresActor) self.vmtkRenderer.AddKeyBinding('u','Undo.',self.UndoCallback) self.vmtkRenderer.AddKeyBinding('space','Pick.',self.PickCallback) self.vmtkRenderer.AddKeyBinding('+','Increase sphere radius.',self.IncreaseSphereRadiusCallback) self.vmtkRenderer.AddKeyBinding('-','Decrease sphere radius.',self.DecreaseSphereRadiusCallback) self.vmtkRenderer.AddKeyBinding('n','Skip to next sphere.',self.NextCallback) self.vmtkRenderer.AddKeyBinding('v','Skip to previous sphere.',self.PreviousCallback) self.vmtkRenderer.AddKeyBinding('d','Show distances graph.',self.DistancesCallback) self.vmtkRenderer.AddKeyBinding('a','Change parameters.',self.ParametersCallback) self.vmtkRenderer.AddKeyBinding('w','Switch modes.',self.SwitchModeCallback) #self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.SurfaceMapper = vtk.vtkPolyDataMapper() self.SurfaceMapper.SetInput(self.Surface) self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(self.SurfaceMapper) surfaceActor.GetProperty().SetOpacity(self.Opacity) self.vmtkRenderer.Renderer.AddActor(surfaceActor) self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.SurfaceMapper.GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() self.ScalarBarActor.SetLabelFormat('%.2f') self.ScalarBarActor.SetTitle('distances') self.ScalarBarActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) self.SphereWidget = vtk.vtkSphereWidget() self.SphereWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.SphereWidget.AddObserver("InteractionEvent", self.SphereCallback) self.ExamineText = vtk.vtkTextActor() self.ExamineText.SetInput("Examine Mode") self.ExamineText.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() self.ExamineText.SetPosition(0.05,0.95) self.ExamineText.VisibilityOff() self.vmtkRenderer.Renderer.AddActor2D(self.ExamineText) self.InputInfo('Please position the mouse and press space to add spheres, \'u\' to undo\n') any = 0 while any == 0: self.InitializeSpheres() self.vmtkRenderer.Render() any = self.Spheres.GetNumberOfPoints() self.Surface = self.ComputeDistances() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkboundarylayer2.py0000664000175000017500000001633711757446472021370 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkboundarylayer2.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## Extended version of vmtkboundarylayer2 ## ## 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. import vtk import vtkvmtkcontrib import sys import pypes vmtkboundarylayer2 = 'vmtkBoundaryLayer2' class vmtkBoundaryLayer2(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.InnerSurfaceMesh = None self.WarpVectorsArrayName = '' self.ThicknessArrayName = '' self.Thickness = 1.0 self.ThicknessRatio = 0.1 self.MaximumThickness = 1E10 self.NumberOfSubLayers = 1 self.SubLayerRatio = 1.0 self.UseWarpVectorMagnitudeAsThickness = 0; self.ConstantThickness = 0 self.IncludeSurfaceCells = 1 self.NegateWarpVectors = 0 self.CellEntityIdsArrayName = '' self.OpenProfilesIdsArrayName = '' self.IncludeExtrudedOpenProfilesCells = 1 self.IncludeExtrudedSurfaceCells = 1 self.IncludeOriginalSurfaceCells = 1 self.LayerEntityId = 0 self.SurfaceEntityId = 1 self.OpenProfilesEntityId = 2 self.SetScriptName('vmtkboundarylayer2') self.SetScriptDoc('create a prismatic boundary layer from a surface mesh and a set of vectors defined on the nodes') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['WarpVectorsArrayName','warpvectorsarray','str',1,'','name of the array where warp vectors are stored'], ['ThicknessArrayName','thicknessarray','str',1,'','name of the array where scalars defining boundary layer thickness are stored'], ['Thickness','thickness','float',1,'','value of constant boundary layer thickness'], ['ThicknessRatio','thicknessratio','float',1,'(0.0,)','multiplying factor for boundary layer thickness'], ['MaximumThickness','maximumthickness','float',1,'','maximum allowed value for boundary layer thickness'], ['NumberOfSubLayers','numberofsublayers','int',1,'(0,)','number of sublayers which the boundary layer has to be made of'], ['SubLayerRatio','sublayerratio','float',1,'(0.0,)','ratio between the thickness of two successive boundary layers'], ['UseWarpVectorMagnitudeAsThickness','warpvectormagnitudeasthickness','bool',1,'','compute boundary layer thickness as the norm of warp vectors'], ['ConstantThickness','constantthickness','bool',1,'','toggle constant boundary layer thickness'], ['IncludeSurfaceCells','includesurfacecells','bool',1,'','include all surface cells in output mesh'], ['NegateWarpVectors','negatewarpvectors','bool',1,'','flip the orientation of warp vectors'], ['CellEntityIdsArrayName','cellentityidsarray','str',1,'','name of the array where the cell entity ids will be stored'], ['OpenProfilesIdsArrayName','openprofilesidsarray','str',1,'','name of the array indicating which points are on open profiles'], ['IncludeExtrudedOpenProfilesCells','includeextrudedopenprofilescells','bool',1,'','include the cells from the open profiles extruded surface in output mesh'], ['IncludeExtrudedSurfaceCells','includeextrudedsurfacecells','bool',1,'','include the cells from the extruded surface in output mesh'], ['IncludeOriginalSurfaceCells','includeoriginalsurfacecells','bool',1,'','include the cells from the original surface in output mesh'], ['LayerEntityId','layerentityid','int',1,'','id assigned to the volumetric layer'], ['SurfaceEntityId','surfaceentityid','int',1,'','id assigned to the first surface entity (ids go increasingly)'], ['OpenProfilesEntityId','openprofilesentityid','int',1,'','id assigned to the first extruded open profile (ids go increasingly)'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ['InnerSurfaceMesh','oinner','vtkUnstructuredGrid',1,'','the output inner surface mesh','vmtkmeshwriter'] ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') boundaryLayerGenerator = vtkvmtkcontrib.vtkvmtkBoundaryLayerGenerator2() boundaryLayerGenerator.SetInput(self.Mesh) boundaryLayerGenerator.SetWarpVectorsArrayName(self.WarpVectorsArrayName) boundaryLayerGenerator.SetLayerThickness(self.Thickness) boundaryLayerGenerator.SetLayerThicknessArrayName(self.ThicknessArrayName) boundaryLayerGenerator.SetLayerThicknessRatio(self.ThicknessRatio) boundaryLayerGenerator.SetMaximumLayerThickness(self.MaximumThickness) boundaryLayerGenerator.SetNumberOfSubLayers(self.NumberOfSubLayers) boundaryLayerGenerator.SetSubLayerRatio(self.SubLayerRatio) boundaryLayerGenerator.SetConstantThickness(self.ConstantThickness) boundaryLayerGenerator.SetUseWarpVectorMagnitudeAsThickness(self.UseWarpVectorMagnitudeAsThickness) boundaryLayerGenerator.SetIncludeSurfaceCells(self.IncludeSurfaceCells) boundaryLayerGenerator.SetNegateWarpVectors(self.NegateWarpVectors) boundaryLayerGenerator.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) boundaryLayerGenerator.SetOpenProfilesIdsArrayName(self.OpenProfilesIdsArrayName) boundaryLayerGenerator.SetIncludeExtrudedOpenProfilesCells(self.IncludeExtrudedOpenProfilesCells) boundaryLayerGenerator.SetIncludeExtrudedSurfaceCells(self.IncludeExtrudedSurfaceCells) boundaryLayerGenerator.SetIncludeOriginalSurfaceCells(self.IncludeOriginalSurfaceCells) boundaryLayerGenerator.SetLayerEntityId(self.LayerEntityId) boundaryLayerGenerator.SetSurfaceEntityId(int(self.SurfaceEntityId)) boundaryLayerGenerator.SetOpenProfilesEntityId(int(self.OpenProfilesEntityId)) boundaryLayerGenerator.Update() self.Mesh = boundaryLayerGenerator.GetOutput() self.InnerSurfaceMesh = boundaryLayerGenerator.GetInnerSurface() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/CMakeLists.txt0000664000175000017500000000423711757446472017706 0ustar lucalucaPROJECT(VMTK_CONTRIB_SCRIPTS) SET(CONTRIB_SCRIPTS_SRCS vmtkboundarylayer2.py vmtkdijkstradistancetopoints.py vmtkdistancetospheres.py vmtkgeodesicsurfaceresolution.py vmtkmeshaddexternallayer.py vmtkmeshclipcenterlines.py vmtkmeshtetrahedralize2.py vmtkmeshviewer2.py vmtkmeshwriter2.py vmtksurfaceresolution.py vmtksurfacewriter2.py vmtksurfaceextractinnercylinder.py vmtkthreshold.py vmtkmeshmerge.py vmtkentityrenumber.py ) SET(CONTRIB_MODULE_SRCS vmtkcontribscripts.py ) IF(NOT VMTK_CONTRIB_SCRIPTS_INSTALL_BIN_DIR) #SET(VMTK_CONTRIB_SCRIPTS_INSTALL_BIN_DIR ${VMTK_CONTRIB_SCRIPTS_INSTALL_ROOT}/bin) SET(VMTK_CONTRIB_SCRIPTS_INSTALL_BIN_DIR bin) ENDIF(NOT VMTK_CONTRIB_SCRIPTS_INSTALL_BIN_DIR) IF(NOT VMTK_CONTRIB_SCRIPTS_INSTALL_LIB_DIR) #SET(VMTK_CONTRIB_SCRIPTS_INSTALL_LIB_DIR ${VMTK_CONTRIB_SCRIPTS_INSTALL_ROOT}/lib/vmtk/vmtk) SET(VMTK_CONTRIB_SCRIPTS_INSTALL_LIB_DIR lib/vmtk/vmtk) ENDIF(NOT VMTK_CONTRIB_SCRIPTS_INSTALL_LIB_DIR) FOREACH (SCRIPT_FILE ${CONTRIB_SCRIPTS_SRCS}) CONFIGURE_FILE(${VMTK_CONTRIB_SCRIPTS_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_CONTRIB_SCRIPTS_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) ENDFOREACH (SCRIPT_FILE) #INSTALL_FILES(${VMTK_CONTRIB_SCRIPTS_INSTALL_LIB_DIR} .py ${CONTRIB_SCRIPTS_SRCS}) INSTALL(FILES ${CONTRIB_SCRIPTS_SRCS} ${CONTRIB_MODULE_SRCS} DESTINATION ${VMTK_CONTRIB_SCRIPTS_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries) IF (NOT WIN32 AND NOT VMTK_MINIMAL_INSTALL) SET (STRIPPED_CONTRIB_SCRIPTS_SRCS ) FOREACH (SCRIPT_FILE ${CONTRIB_SCRIPTS_SRCS}) STRING(REGEX REPLACE ".py$" "" STRIPPED_SCRIPT_FILE ${SCRIPT_FILE}) CONFIGURE_FILE(${PYPES_SOURCE_DIR}/pyperun.py ${VMTK_CONTRIB_SCRIPTS_BINARY_DIR}/${STRIPPED_SCRIPT_FILE} COPYONLY) SET (CONTRIB_STRIPPED_SCRIPTS_SRCS ${CONTRIB_STRIPPED_SCRIPTS_SRCS} ${VMTK_CONTRIB_SCRIPTS_BINARY_DIR}/${STRIPPED_SCRIPT_FILE}) ENDFOREACH (SCRIPT_FILE) #INSTALL_PROGRAMS(${VMTK_CONTRIB_SCRIPTS_INSTALL_BIN_DIR} FILES ${CONTRIB_STRIPPED_SCRIPTS_SRCS}) INSTALL(PROGRAMS ${CONTRIB_STRIPPED_SCRIPTS_SRCS} DESTINATION ${VMTK_CONTRIB_SCRIPTS_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables) ENDIF (NOT WIN32 AND NOT VMTK_MINIMAL_INSTALL) vmtk-1.0.1/vmtkScripts/contrib/vmtkgeodesicsurfaceresolution.py0000664000175000017500000003352111757446472023677 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkgeodesicsurfaceresolution.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This allows the user to specify a edge-length array to be used to specify resolution for surface remeshing ## The array is produced by RBF interpolation of values specified by the user by positioning spheres ## This version use the geodesic distance along the surface instead of hte 3D euclidean distance for hte RBF import vtk import sys import vtkvmtk import vtkvmtkcontrib import vmtkrenderer import pypes vmtkgeodesicsurfaceresolution = 'vmtkGeodesicSurfaceResolution' class vmtkGeodesicSurfaceResolution(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.ResolutionArrayName = 'ResolutionArray' self.RBFType = 'biharmonic' self.Spheres = vtk.vtkPolyData() self.SphereIds = vtk.vtkIdList() self.vmtkRenderer = None self.OwnRenderer = 0 self.DisplayArray = False self.SurfaceMapper = None self.CurrentSphereId = -1 self.SphereWidget = None self.Opacity = 1. self.SpheresActor = None self.ScalarBarActor = None self.InteractionMode = 0 self.ExamineSurface = None self.ExamineSpheres = vtk.vtkPolyData() self.ExamineSpheresActor = None self.ExamineText = None self.SetScriptName('vtksurfaceresolution') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['ResolutionArrayName','resolutionarray','str',1,'','array storing the desired edge length'], ['RBFType','rbftype','str',1,'["thinplatespline","biharmonic","triharmonic"]','the type of RBF interpolation'], ['Opacity','opacity','float',1,'(0.0,1.0)','object opacities in the scene'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def ComputeArray(self): rbf = vtkvmtkcontrib.vtkvmtkPolyDataGeodesicRBFInterpolation() rbf.SetSeedIds(self.SphereIds) seedValues = self.Spheres.GetPointData().GetScalars() rbf.SetSeedValues(seedValues) if self.RBFType == "thinplatespline": rbf.SetRBFTypeToThinPlateSpline() elif self.RBFType == "biharmonic": rbf.SetRBFTypeToBiharmonic() elif self.RBFType == "triharmonic": rbf.SetRBFTypeToTriharmonic() rbf.SetInput(self.Surface) rbf.SetInterpolatedArrayName(self.ResolutionArrayName) rbf.Update() return rbf.GetOutput() def InitializeSpheres(self): if (self.InteractionMode==0): self.SphereIds.Initialize() self.Spheres.Initialize() seedPoints = vtk.vtkPoints() self.Spheres.SetPoints(seedPoints) self.Spheres.GetPointData().Initialize() seedRadii = vtk.vtkDoubleArray() self.Spheres.GetPointData().SetScalars(seedRadii) self.CurrentSphereId = -1 self.SphereWidget.Off() else: self.ExamineSpheres.Initialize() spherePoints = vtk.vtkPoints() self.ExamineSpheres.SetPoints(spherePoints) self.ExamineSpheres.GetPointData().Initialize() sphereRadii = vtk.vtkDoubleArray() self.ExamineSpheres.GetPointData().SetScalars(sphereRadii) def PlaceSphere(self): if self.CurrentSphereId == -1: return self.SphereWidget.SetCenter(self.Spheres.GetPoint(self.CurrentSphereId)) self.SphereWidget.SetRadius(self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId)) def SphereCallback(self,widget,event_string): if self.CurrentSphereId == -1: return minRadius = self.Surface.GetLength()*0.001 if self.SphereWidget.GetRadius() < minRadius: self.SphereWidget.SetRadius(minRadius) self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,self.SphereWidget.GetRadius()) self.Spheres.Modified() def UndoCallback(self, obj): self.InitializeSpheres() self.Spheres.Modified() self.vmtkRenderer.RenderWindow.Render() def PlusCallback(self, obj): if self.CurrentSphereId != -1: #increase sphere radius newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) + self.Surface.GetLength()*0.01 self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def MinusCallback(self, obj): if self.CurrentSphereId != -1: #decrease sphere radius newval = self.Spheres.GetPointData().GetScalars().GetValue(self.CurrentSphereId) - self.Surface.GetLength()*0.01 if newval> 0: self.Spheres.GetPointData().GetScalars().SetValue(self.CurrentSphereId,newval) self.Spheres.Modified() self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def NextSphereCallback(self, obj): if self.CurrentSphereId != -1: self.CurrentSphereId = (self.CurrentSphereId + 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def PreviousSphereCallback(self, obj): if self.CurrentSphereId != -1: self.CurrentSphereId = (self.CurrentSphereId - 1) % self.Spheres.GetNumberOfPoints(); self.PlaceSphere() self.vmtkRenderer.RenderWindow.Render() def DisplayCallback(self, obj): self.DisplayArray = not self.DisplayArray if self.DisplayArray: self.ExamineSurface = self.ComputeArray() self.SurfaceMapper.SetInput(self.ExamineSurface) self.ExamineSurface.GetPointData().SetActiveScalars(self.ResolutionArrayName) array = self.ExamineSurface.GetPointData().GetScalars() if (array): array.Modified() self.SurfaceMapper.SetScalarRange(array.GetRange(0)) self.ScalarBarActor.VisibilityOn() else: self.SurfaceMapper.SetInput(self.Surface) self.ScalarBarActor.VisibilityOff() self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) self.vmtkRenderer.RenderWindow.Render() def ExmienModeCallback(self, obj): #Switch beetween examien and interact mode if self.InteractionMode == 0: self.InteractionMode = 1 self.ExamineSurface = self.ComputeArray() #self.SpheresActor.VisibilityOff() self.SphereWidget.Off() self.ExamineSpheresActor.VisibilityOn() self.ExamineText.VisibilityOn() self.InitializeSpheres() else: self.InteractionMode = 0 #Compute the distances self.SpheresActor.VisibilityOn() self.ExamineSpheresActor.VisibilityOff() self.ExamineText.VisibilityOff() if (self.CurrentSphereId!=-1): self.SphereWidget.On() self.vmtkRenderer.RenderWindow.Render() def PickCallback(self, obj): picker = vtk.vtkCellPicker() picker.SetTolerance(1E-4 * self.Surface.GetLength()) eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() #eventPosition = obj.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: return pickPosition = picker.GetPickPosition() pickedCellPointIds = self.Surface.GetCell(picker.GetCellId()).GetPointIds() minDistance = 1E10 pickedPointId = -1 for i in range(pickedCellPointIds.GetNumberOfIds()): distance = vtk.vtkMath.Distance2BetweenPoints(pickPosition,self.Surface.GetPoint(pickedCellPointIds.GetId(i))) if distance < minDistance: minDistance = distance pickedPointId = pickedCellPointIds.GetId(i) if pickedPointId == -1: pickedPointId = pickedCellPointIds.GetId(0) pickedPoint = self.Surface.GetPoint(pickedPointId) if (self.InteractionMode==0): self.SphereIds.InsertNextId(pickedPointId) self.CurrentSphereId = self.Spheres.GetPoints().InsertNextPoint(pickedPoint) self.Spheres.GetPointData().GetScalars().InsertNextValue(self.Surface.GetLength()*0.01) self.Spheres.Modified() self.PlaceSphere() self.SphereWidget.On() else: self.ExamineSpheres.GetPoints().InsertNextPoint(pickedPoint) length = 0. array = self.ExamineSurface.GetPointData().GetArray(self.ResolutionArrayName) if (array): length = array.GetComponent(pickedPointId,0) self.ExamineSpheres.GetPointData().GetScalars().InsertNextValue(length) self.ExamineSpheres.Modified() self.vmtkRenderer.RenderWindow.Render() def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphSource.SetRadius(1) glyphs.SetInput(self.Spheres) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToScaleByScalar() glyphs.SetScaleFactor(1.) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) glyphMapper.ScalarVisibilityOff() self.SpheresActor = vtk.vtkActor() self.SpheresActor.SetMapper(glyphMapper) self.SpheresActor.GetProperty().SetColor(1.0,0.0,0.0) self.SpheresActor.GetProperty().SetOpacity(self.Opacity) self.SpheresActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.SpheresActor) examineGlyphs = vtk.vtkGlyph3D() examineGlyphSource = vtk.vtkSphereSource() examineGlyphSource.SetRadius(1) examineGlyphs.SetInput(self.ExamineSpheres) examineGlyphs.SetSource(examineGlyphSource.GetOutput()) examineGlyphs.SetScaleModeToScaleByScalar() examineGlyphs.SetScaleFactor(1.) examineGlyphMapper = vtk.vtkPolyDataMapper() examineGlyphMapper.SetInput(examineGlyphs.GetOutput()) examineGlyphMapper.ScalarVisibilityOff() self.ExamineSpheresActor = vtk.vtkActor() self.ExamineSpheresActor.SetMapper(examineGlyphMapper) self.ExamineSpheresActor.GetProperty().SetColor(0.0,1.0,0.0) self.ExamineSpheresActor.GetProperty().SetOpacity(self.Opacity) self.ExamineSpheresActor.PickableOff() self.ExamineSpheresActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ExamineSpheresActor) #self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.vmtkRenderer.AddKeyBinding('u','undo',self.UndoCallback) self.vmtkRenderer.AddKeyBinding('plus','Increase sphere radius',self.PlusCallback) self.vmtkRenderer.AddKeyBinding('minus','Decrease sphere radius',self.MinusCallback) self.vmtkRenderer.AddKeyBinding('n','Show next sphere',self.NextSphereCallback) self.vmtkRenderer.AddKeyBinding('v','Show previous sphere',self.PreviousSphereCallback) self.vmtkRenderer.AddKeyBinding('d','Display ',self.DisplayCallback) self.vmtkRenderer.AddKeyBinding('w','Switch beetween examien and interact mode ',self.ExmienModeCallback) self.vmtkRenderer.AddKeyBinding('space','Pick sphere',self.PickCallback) self.SurfaceMapper = vtk.vtkPolyDataMapper() self.SurfaceMapper.SetInput(self.Surface) self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(self.SurfaceMapper) surfaceActor.GetProperty().SetOpacity(self.Opacity) self.vmtkRenderer.Renderer.AddActor(surfaceActor) self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.SurfaceMapper.GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() self.ScalarBarActor.SetLabelFormat('%.2f') self.ScalarBarActor.SetTitle('distances') self.ScalarBarActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) self.SphereWidget = vtk.vtkSphereWidget() self.SphereWidget.TranslationOff() self.SphereWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.SphereWidget.AddObserver("InteractionEvent", self.SphereCallback) self.ExamineText = vtk.vtkTextActor() self.ExamineText.SetInput("Examine Mode") self.ExamineText.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() self.ExamineText.SetPosition(0.05,0.95) self.ExamineText.VisibilityOff() self.vmtkRenderer.Renderer.AddActor2D(self.ExamineText) self.InputInfo('Please position the mouse and press space to add spheres, \'u\' to undo\n') any = 0 while any == 0: self.InitializeSpheres() self.vmtkRenderer.Render() any = (self.Spheres.GetNumberOfPoints()>1) self.Surface = self.ComputeArray() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtksurfacewriter2.py0000664000175000017500000002113311757446472021363 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacewriter2.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This class is a slightly modified version of vmtkmeshwriter. ## An option has been added to write ascii files. ## The Dolphin writer has been modified (see vtkvmtkDolfinWriter2) import vtk import sys import pypes vmtksurfacewriter2 = 'vmtkSurfaceWriter2' class vmtkSurfaceWriter2(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.OutputFileName = '' self.Surface = None self.Input = None self.CellData = 0 self.Ascii = False self.SetScriptName('vmtksurfacewriter') self.SetScriptDoc('write surface to disk') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['Format','f','str',1,'["vtkxml","vtk","stl","pointdata","tecplot"]','file format'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['CellData','celldata','bool',1,'','write CellData when using pointdata format'], ['OutputFileName','ofile','str',1,'','output file name'], ['OutputFileName','o','str',1,'','output file name (deprecated: use -ofile)'], ['Ascii','ascii','boolean',1,'','write the data as ascii'] ]) self.SetOutputMembers([]) def WriteVTKSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK surface file.') writer = vtk.vtkPolyDataWriter() if self.Ascii: writer.SetDataModeToAscii() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) writer.Write() def WriteVTKXMLSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK XML surface file.') writer = vtk.vtkXMLPolyDataWriter() if self.Ascii: writer.SetDataModeToAscii() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) writer.Write() def WriteSTLSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing STL surface file.') writer = vtk.vtkSTLWriter() writer.SetInput(self.Surface) writer.SetFileName(self.OutputFileName) writer.Write() def WritePointDataSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PointData file.') f=open(self.OutputFileName, 'w') line = "X Y Z" arrayNames = [] dataArrays = self.Surface.GetPointData() if self.CellData: dataArrays = self.Surface.GetCellData(); for i in range(dataArrays.GetNumberOfArrays()): array = dataArrays.GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ' ' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ' ' + arrayName + str(j) line = line + '\n' f.write(line) numberOfLines = self.Surface.GetNumberOfPoints() if self.CellData: numberOfLines = self.Surface.GetNumberOfCells() for i in range(numberOfLines): point = None if not self.CellData: point = self.Surface.GetPoint(i) else: point = self.Surface.GetCell(i).GetPoints().GetPoint(0) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = dataArrays.GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) def WriteTecplotSurfaceFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Tecplot file.') triangleFilter = vtk.vtkTriangleFilter() triangleFilter.SetInput(self.Surface) triangleFilter.PassVertsOff() triangleFilter.PassLinesOff() triangleFilter.Update() self.Surface = triangleFilter.GetOutput() f=open(self.OutputFileName, 'w') line = "VARIABLES = X,Y,Z" arrayNames = [] for i in range(self.Surface.GetPointData().GetNumberOfArrays()): array = self.Surface.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ',' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ',' + arrayName + str(j) line = line + '\n' f.write(line) line = "ZONE " + "N=" + str(self.Surface.GetNumberOfPoints()) + ',' + "E=" + str(self.Surface.GetNumberOfCells()) + ',' + "F=FEPOINT" + ',' + "ET=TRIANGLE" + '\n' f.write(line) for i in range(self.Surface.GetNumberOfPoints()): point = self.Surface.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Surface.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) for i in range(self.Surface.GetNumberOfCells()): cellPointIds = self.Surface.GetCell(i).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if (j>0): line = line + ' ' line = line + str(cellPointIds.GetId(j)+1) line = line + '\n' f.write(line) def Execute(self): if self.Surface == None: if self.Input == None: self.PrintError('Error: no Surface.') self.Surface = self.Input extensionFormats = {'vtp':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'stl':'stl', 'tec':'tecplot', 'dat':'pointdata'} if self.OutputFileName == 'BROWSER': import tkFileDialog initialDir = '.' self.OutputFileName = tkFileDialog.asksaveasfilename(title="Output surface",initialdir=initialDir) if not self.OutputFileName: self.PrintError('Error: no OutputFileName.') if self.GuessFormat and self.OutputFileName and not self.Format: import os.path extension = os.path.splitext(self.OutputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.WriteVTKSurfaceFile() elif (self.Format == 'vtkxml'): self.WriteVTKXMLSurfaceFile() elif (self.Format == 'stl'): self.WriteSTLSurfaceFile() elif (self.Format == 'pointdata'): self.WritePointDataSurfaceFile() elif (self.Format == 'tecplot'): self.WriteTecplotSurfaceFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkmeshwriter2.py0000664000175000017500000003422611757446472020676 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshwriter2.py,v $ ## Language: Python ## Date: $Date: 2006/07/27 08:27:40 $ ## Version: $Revision: 1.13 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This class is a slightly modified version of vmtkmeshwriter. ## An option has been added to write ascii files. ## The Dolphin writer has been modified (see vtkvmtkDolfinWriter2) import sys import vtk import vtkvmtk import vtkvmtkcontrib import pypes vmtkmeshwriter2 = 'vmtkMeshWriter2' class vmtkMeshWriter2(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Format = '' self.GuessFormat = 1 self.OutputFileName = '' self.Mesh = None self.Input = None self.Ascii = False self.Compressed = 1 self.CellEntityIdsOffset = 0 self.CellEntityIdsArrayName = '' self.SetScriptName('vmtkmeshwriter') self.SetScriptDoc('write a mesh to disk') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['Format','f','str',1,'["vtkxml","vtk","xda","fdneut","tecplot","lifev","dolfin","fluent","pointdata"]','file format (xda - libmesh ASCII format, fdneut - FIDAP neutral format)'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ['Compressed','compressed','bool',1,'','output gz compressed file (dolfin only)'], ['OutputFileName','ofile','str',1,'','output file name'], ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh'], ['CellEntityIdsArrayName','entityidsarray','str',1,'','name of the array where entity ids are stored'], ['CellEntityIdsOffset','entityidsoffset','int',1,'','add this number to entity ids in output (dolfin only)'], ['Ascii','ascii','boolean',1,'','write the data as ascii'] ]) self.SetOutputMembers([]) def WriteVTKMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK mesh file.') writer = vtk.vtkUnstructuredGridWriter() if self.Ascii: writer.SetDataModeToAscii() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) writer.Write() def WriteVTKXMLMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing VTK XML mesh file.') writer = vtk.vtkXMLUnstructuredGridWriter() if self.Ascii: writer.SetDataModeToAscii() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) writer.Write() def WriteXdaMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Xda mesh file.') writer = vtkvmtk.vtkvmtkXdaWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) if self.CellEntityIdsArrayName != '': writer.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) writer.Write() def WriteFDNEUTMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing FDNEUT mesh file.') writer = vtkvmtk.vtkvmtkFDNEUTWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) writer.Write() def WriteTecplotMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Tecplot file.') triangleFilter = vtk.vtkDataSetTriangleFilter() triangleFilter.SetInput(self.Mesh) triangleFilter.Update() self.Mesh = triangleFilter.GetOutput() f=open(self.OutputFileName, 'w') line = "VARIABLES = X,Y,Z" arrayNames = [] for i in range(self.Mesh.GetPointData().GetNumberOfArrays()): array = self.Mesh.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ',' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ',' + arrayName + str(j) line = line + '\n' f.write(line) tetraCellIdArray = vtk.vtkIdTypeArray() tetraCellType = 10 self.Mesh.GetIdsOfCellsOfType(tetraCellType,tetraCellIdArray) numberOfTetras = tetraCellIdArray.GetNumberOfTuples() line = "ZONE " + "N=" + str(self.Mesh.GetNumberOfPoints()) + ',' + "E=" + str(numberOfTetras) + ',' + "F=FEPOINT" + ',' + "ET=TETRAHEDRON" + '\n' f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = self.Mesh.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Mesh.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) for i in range(numberOfTetras): cellPointIds = self.Mesh.GetCell(tetraCellIdArray.GetValue(i)).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if (j>0): line = line + ' ' line = line + str(cellPointIds.GetId(j)+1) line = line + '\n' f.write(line) def WriteLifeVMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing LifeV file.') self.Mesh.BuildLinks() cellEntityIdsArray = vtk.vtkIntArray() cellEntityIdsArray.DeepCopy(self.Mesh.GetCellData().GetArray(self.CellEntityIdsArrayName)) tetraCellType = 10 triangleCellType = 5 f=open(self.OutputFileName, 'w') line = "MeshVersionFormatted 1\n\n" line += "Dimension\n" line += "3\n\n" line += "Vertices\n" line += "%d\n" % self.Mesh.GetNumberOfPoints() f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = self.Mesh.GetPoint(i) pointCells = vtk.vtkIdList() self.Mesh.GetPointCells(i,pointCells) minTriangleCellEntityId = -1 tetraCellEntityId = -1 for j in range(pointCells.GetNumberOfIds()): cellId = pointCells.GetId(j) if self.Mesh.GetCellType(cellId) == triangleCellType: cellEntityId = cellEntityIdsArray.GetValue(cellId) if cellEntityId < minTriangleCellEntityId or minTriangleCellEntityId == -1: minTriangleCellEntityId = cellEntityId else: tetraCellEntityId = cellEntityIdsArray.GetValue(cellId) cellEntityId = tetraCellEntityId if minTriangleCellEntityId != -1: cellEntityId = minTriangleCellEntityId line = "%f %f %f %d\n" % (point[0], point[1], point[2], cellEntityId) f.write(line) line = "\n" tetraCellIdArray = vtk.vtkIdTypeArray() self.Mesh.GetIdsOfCellsOfType(tetraCellType,tetraCellIdArray) numberOfTetras = tetraCellIdArray.GetNumberOfTuples() line += "Tetrahedra\n" line += "%d\n" % numberOfTetras f.write(line) for i in range(numberOfTetras): tetraCellId = tetraCellIdArray.GetValue(i) cellPointIds = self.Mesh.GetCell(tetraCellId).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if j>0: line += ' ' line += "%d" % (cellPointIds.GetId(j)+1) line += ' %d\n' % 1 f.write(line) line = "\n" triangleCellIdArray = vtk.vtkIdTypeArray() self.Mesh.GetIdsOfCellsOfType(triangleCellType,triangleCellIdArray) numberOfTriangles = triangleCellIdArray.GetNumberOfTuples() line += "Triangles\n" line += "%d\n" % numberOfTriangles f.write(line) for i in range(numberOfTriangles): triangleCellId = triangleCellIdArray.GetValue(i) cellPointIds = self.Mesh.GetCell(triangleCellId).GetPointIds() line = '' for j in range(cellPointIds.GetNumberOfIds()): if j>0: line += ' ' line += "%d" % (cellPointIds.GetId(j)+1) cellEntityId = cellEntityIdsArray.GetValue(triangleCellId) line += ' %d\n' % cellEntityId f.write(line) def WriteDolfinMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing Dolfin file.') if self.Compressed: self.OutputFileName += '.gz' writer = vtkvmtkcontrib.vtkvmtkDolfinWriter2() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) if self.CellEntityIdsArrayName != '': writer.SetCellEntityIdsArrayName(self.CellEntityIdsArrayName) writer.SetCellEntityIdsOffset(self.CellEntityIdsOffset) writer.Write() if self.Compressed: file = open(self.OutputFileName,'r') xml = file.read() file.close() import gzip gzfile = gzip.open(self.OutputFileName,'w') gzfile.write(xml) gzfile.close() def WriteFluentMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') # self.PrintError('Error: Fluent writer not implemented yet.') # return self.PrintLog('Writing Fluent file.') writer = vtkvmtk.vtkvmtkFluentWriter() writer.SetInput(self.Mesh) writer.SetFileName(self.OutputFileName) if self.CellEntityIdsArrayName != '': writer.SetBoundaryDataArrayName(self.CellEntityIdsArrayName) writer.Write() def WritePointDataMeshFile(self): if (self.OutputFileName == ''): self.PrintError('Error: no OutputFileName.') self.PrintLog('Writing PointData file.') f=open(self.OutputFileName, 'w') line = "X Y Z" arrayNames = [] for i in range(self.Mesh.GetPointData().GetNumberOfArrays()): array = self.Mesh.GetPointData().GetArray(i) arrayName = array.GetName() if arrayName == None: continue if (arrayName[-1]=='_'): continue arrayNames.append(arrayName) if (array.GetNumberOfComponents() == 1): line = line + ' ' + arrayName else: for j in range(array.GetNumberOfComponents()): line = line + ' ' + arrayName + str(j) line = line + '\n' f.write(line) for i in range(self.Mesh.GetNumberOfPoints()): point = self.Mesh.GetPoint(i) line = str(point[0]) + ' ' + str(point[1]) + ' ' + str(point[2]) for arrayName in arrayNames: array = self.Mesh.GetPointData().GetArray(arrayName) for j in range(array.GetNumberOfComponents()): line = line + ' ' + str(array.GetComponent(i,j)) line = line + '\n' f.write(line) def Execute(self): if self.Mesh == None: if self.Input == None: self.PrintError('Error: no Mesh.') self.Mesh = self.Input extensionFormats = {'vtu':'vtkxml', 'vtkxml':'vtkxml', 'vtk':'vtk', 'xda':'xda', 'FDNEUT':'fdneut', 'lifev':'lifev', 'xml':'dolfin', 'msh':'fluent', 'tec':'tecplot', 'dat':'pointdata'} if self.OutputFileName == 'BROWSER': import tkFileDialog initialDir = '.' self.OutputFileName = tkFileDialog.asksaveasfilename(title="Output mesh",initialdir=initialDir) if not self.OutputFileName: self.PrintError('Error: no OutputFileName.') if self.GuessFormat and self.OutputFileName and not self.Format: import os.path extension = os.path.splitext(self.OutputFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if (self.Format == 'vtk'): self.WriteVTKMeshFile() elif (self.Format == 'vtkxml'): self.WriteVTKXMLMeshFile() elif (self.Format == 'xda'): self.WriteXdaMeshFile() elif (self.Format == 'fdneut'): self.WriteFDNEUTMeshFile() elif (self.Format == 'lifev'): self.WriteLifeVMeshFile() elif (self.Format == 'dolfin'): self.WriteDolfinMeshFile() elif (self.Format == 'fluent'): self.WriteFluentMeshFile() elif (self.Format == 'tecplot'): self.WriteTecplotMeshFile() elif (self.Format == 'pointdata'): self.WritePointDataMeshFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkcontribscripts.py0000664000175000017500000000077411757446472021474 0ustar lucaluca__all__ = [ 'vmtkboundarylayer2', 'vmtkdijkstradistancetopoints', 'vmtkdistancetospheres', 'vmtkgeodesicsurfaceresolution', 'vmtkmeshaddexternallayer', 'vmtkmeshclipcenterlines', 'vmtkmeshtetrahedralize2', 'vmtkmeshviewer2', 'vmtkmeshwriter2', 'vmtksurfaceresolution', 'vmtksurfacewriter2', 'vmtksurfaceextractinnercylinder', 'vmtkthreshold', 'vmtkmeshmerge', 'vmtkentityrenumber', ] for item in __all__: exec('from '+item+' import *') vmtk-1.0.1/vmtkScripts/contrib/vmtkentityrenumber.py0000664000175000017500000000661311757446472021476 0ustar lucaluca#!/usr/bin/env python import sys from vmtk import pypes import vtk vmtkentityrenumber = 'VmtkEntityRenumber' class VmtkEntityRenumber(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.SetScriptName(vmtkentityrenumber) self.SetScriptDoc('Renumber cell entity id array.') self.Mesh = None self.CellEntityIdsArrayName = "CellEntityIds" self.CellEntityIdOffset = 0 self.CellEntityIdRenumbering = [] self.InteriorFacetsOffset = 0 # Member info: name, cmdlinename, typename, num, default, desc[, defaultpipetoscript] self.SetInputMembers([ ['Mesh', 'i', 'vtkUnstructuredGrid', 1, '', 'the input mesh', 'vmtkmeshreader'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, 'CellEntityIds', 'name of the array where entity ids have been stored'], ['CellEntityIdOffset', 'offset', 'int', 1, '', 'offset added to cell entity ids that are not mapped explicitly', ''], ['CellEntityIdRenumbering', 'renumbering', 'int', -1, '', '[from1 to1] [from2 to2] ...', ''], ['InteriorFacetsOffset', 'interiorfacetsoffset', 'int', 1, '', 'offset added to ids of interior facets after renumbering mapping, to separate them from interior facets'], ]) self.SetOutputMembers([ ['Mesh', 'o', 'vtkUnstructuredGrid', 1, '', 'the output mesh', 'vmtkmeshwriter'], ['CellEntityIdsArrayName', 'entityidsarray', 'str', 1, 'CellEntityIds', 'name of the array where entity ids have been stored'], ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No Mesh.') if len(self.CellEntityIdRenumbering) % 2 != 0: self.PrintError('Renumbering must have even length.') renumbering = {} for i in range(len(self.CellEntityIdRenumbering)/2): a = self.CellEntityIdRenumbering[2*i] b = self.CellEntityIdRenumbering[2*i+1] renumbering[a] = b cellids = self.Mesh.GetCellData().GetScalars(self.CellEntityIdsArrayName) for i in range(cellids.GetNumberOfTuples()): v = cellids.GetValue(i) # Renumber or add offset v = renumbering.get(v, v + self.CellEntityIdOffset) # TODO: This is triangles/tets only volumeTypes = (vtk.VTK_TETRA,) faceTypes = (vtk.VTK_TRIANGLE,) # Add offset if cell is an interior facet if self.InteriorFacetsOffset: if self.Mesh.GetCell(i).GetCellType() in faceTypes: pIds = vtk.vtkIdList() cIds = vtk.vtkIdList() self.Mesh.GetCellPoints(i, pIds) self.Mesh.GetCellNeighbors(i, pIds, cIds) nIds = cIds.GetNumberOfIds() if nIds == 2: def getCellType(j): return self.Mesh.GetCell(cIds.GetId(j)).GetCellType() if all(getCellType(j) in volumeTypes for j in range(nIds)): v += self.InteriorFacetsOffset cellids.SetValue(i, v) if __name__ == '__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkdijkstradistancetopoints.py0000664000175000017500000003100611757446472023542 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkdijkstradistancetopoints.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This class computes the geodesic distance on the graph of a surface ## from a set of user-selected points on the surface using the Dijkstra algorithm. import vtk import sys import vtkvmtk import vtkvmtkcontrib import vmtkrenderer import pypes vmtkdijkstradistancetopoints = 'vmtkDijkstraDistanceToPoints' class vmtkDijkstraDistanceToPoints(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.DijkstraDistanceToPointsArrayName = 'DijkstraDistanceToPoints' self.DistanceOffset = 0. self.DistanceScale = 1. self.MinDistance = 0. self.MaxDistance = -1. self.SeedPoints = vtk.vtkPolyData() self.SeedIds = vtk.vtkIdList() self.vmtkRenderer = None self.OwnRenderer = 0 self.DisplayArray = False self.SurfaceMapper = None self.Opacity = 1. self.PointActor = None self.ScalarBarActor = None self.InteractionMode = 0 self.ExamineSurface = None self.ExamineSpheres = vtk.vtkPolyData() self.ExamineSpheresActor = None self.ExamineText = None self.SetScriptName('vmtkdijkstradistancetopoints') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['DijkstraDistanceToPointsArrayName','distancetopointsarray','str',1,'','array storing the distances'], ['DistanceOffset','offset','float',1,'','offset added to the distances'], ['DistanceScale','scale','float',1,'','scale applied to the distances'], ['MinDistance','mindistance','float',1,'','minimum value for the distances'], ['MaxDistance','maxdistance','float',1,'','maximum value for the distances'], ['Opacity','opacity','float',1,'(0.0,1.0)','object opacities in the scene'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','','vmtksurfacewriter'] ]) def DistanceParametersValidator(self,text): if not text: return 1 splitText = text.strip().split(' ') if len(splitText) not in range(1,5): return 0 try: for i in range(1,len(splitText)+1): float(splitText[i-1]) except ValueError: return 0 return 1 def ComputeDistances(self): dijkstraFilter = vtkvmtkcontrib.vtkvmtkPolyDataDijkstraDistanceToPoints() dijkstraFilter.SetInput(self.Surface) dijkstraFilter.SetSeedIds(self.SeedIds) dijkstraFilter.SetDistanceOffset(self.DistanceOffset) dijkstraFilter.SetDistanceScale(self.DistanceScale) dijkstraFilter.SetMinDistance(self.MinDistance) dijkstraFilter.SetMaxDistance(self.MaxDistance) dijkstraFilter.SetDijkstraDistanceToPointsArrayName(self.DijkstraDistanceToPointsArrayName) dijkstraFilter.Update() return dijkstraFilter.GetOutput() def InitializeSeeds(self): if (self.InteractionMode==0): self.SeedIds.Initialize() self.SeedPoints.Initialize() seedPoints = vtk.vtkPoints() self.SeedPoints.SetPoints(seedPoints) else: self.ExamineSpheres.Initialize() spherePoints = vtk.vtkPoints() self.ExamineSpheres.SetPoints(spherePoints) self.ExamineSpheres.GetPointData().Initialize() sphereRadii = vtk.vtkDoubleArray() self.ExamineSpheres.GetPointData().SetScalars(sphereRadii) def UndoCallback(self, obj): self.InitializeSeeds() self.SeedPoints.Modified() self.vmtkRenderer.RenderWindow.Render() def SpaceCallback(self,obj): picker = vtk.vtkCellPicker() picker.SetTolerance(1E-4 * self.Surface.GetLength()) eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition() #eventPosition = obj.GetEventPosition() result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer) if result == 0: return pickPosition = picker.GetPickPosition() pickedCellPointIds = self.Surface.GetCell(picker.GetCellId()).GetPointIds() minDistance = 1E10 pickedSeedId = -1 for i in range(pickedCellPointIds.GetNumberOfIds()): distance = vtk.vtkMath.Distance2BetweenPoints(pickPosition,self.Surface.GetPoint(pickedCellPointIds.GetId(i))) if distance < minDistance: minDistance = distance pickedSeedId = pickedCellPointIds.GetId(i) if pickedSeedId == -1: pickedSeedId = pickedCellPointIds.GetId(0) if (self.InteractionMode==0): self.SeedIds.InsertNextId(pickedSeedId) point = self.Surface.GetPoint(pickedSeedId) self.SeedPoints.GetPoints().InsertNextPoint(point) self.SeedPoints.Modified() else: point = self.Surface.GetPoint(pickedSeedId) self.ExamineSpheres.GetPoints().InsertNextPoint(point) length = 0. array = self.ExamineSurface.GetPointData().GetArray(self.DijkstraDistanceToPointsArrayName) if array: length = array.GetComponent(pickedSeedId,0) self.ExamineSpheres.GetPointData().GetScalars().InsertNextValue(length) self.ExamineSpheres.Modified() self.vmtkRenderer.RenderWindow.Render() def DisplayDistanceCallback(self,obj): self.DisplayArray = not self.DisplayArray if self.DisplayArray: newSurface = self.ComputeDistances() self.SurfaceMapper.SetInput(newSurface) newSurface.GetPointData().SetActiveScalars(self.DijkstraDistanceToPointsArrayName) array = newSurface.GetPointData().GetScalars() if array: self.SurfaceMapper.SetScalarRange(array.GetRange(0)) self.ScalarBarActor.VisibilityOn() else: self.SurfaceMapper.SetInput(self.Surface) self.ScalarBarActor.VisibilityOff() self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) self.vmtkRenderer.RenderWindow.Render() def AddCallback(self, obj): queryString = 'Please input new parameters :\nDistanceOffset('+str(self.DistanceOffset)+') [DistanceScale('+str(self.DistanceScale)+') MinDistance('+str(self.MinDistance)+') MaxDistance('+str(self.MaxDistance)+'): ' inputString = self.InputText(queryString,self.DistanceParametersValidator) splitInputString = inputString.strip().split(' ') if len(splitInputString) >= 1 and splitInputString[0] != '': self.DistanceOffset = float(splitInputString[0]) if len(splitInputString) >= 2: self.DistanceScale = float(splitInputString[1]) if len(splitInputString) >= 3: self.MinDistance = float(splitInputString[2]) if len(splitInputString) >= 4: self.MaxDistance = float(splitInputString[3]) def ExamineCallback(self, obj): #Switch beetween examien and interact mode if self.InteractionMode == 0: self.InteractionMode = 1 self.ExamineSurface = self.ComputeDistances() self.PointActor.VisibilityOff() self.ExamineSpheresActor.VisibilityOn() self.ExamineText.VisibilityOn() self.InitializeSeeds() else: self.InteractionMode = 0 #Compute the distances self.PointActor.VisibilityOn() self.ExamineSpheresActor.VisibilityOff() self.ExamineText.VisibilityOff() self.vmtkRenderer.RenderWindow.Render() def Execute(self): if self.Surface == None: self.PrintError('Error: No input surface.') if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) glyphs = vtk.vtkGlyph3D() glyphSource = vtk.vtkSphereSource() glyphSource.SetRadius(1) glyphs.SetInput(self.SeedPoints) glyphs.SetSource(glyphSource.GetOutput()) glyphs.SetScaleModeToDataScalingOff() glyphs.SetScaleFactor(self.Surface.GetLength()*0.01) glyphMapper = vtk.vtkPolyDataMapper() glyphMapper.SetInput(glyphs.GetOutput()) glyphMapper.ScalarVisibilityOff() self.PointActor = vtk.vtkActor() self.PointActor.SetMapper(glyphMapper) self.PointActor.GetProperty().SetColor(1.0,0.0,0.0) self.PointActor.GetProperty().SetOpacity(self.Opacity) self.PointActor.PickableOff() self.vmtkRenderer.Renderer.AddActor(self.PointActor) examineGlyphs = vtk.vtkGlyph3D() examineGlyphSource = vtk.vtkSphereSource() examineGlyphSource.SetRadius(1) examineGlyphs.SetInput(self.ExamineSpheres) examineGlyphs.SetSource(examineGlyphSource.GetOutput()) examineGlyphs.SetScaleModeToScaleByScalar() examineGlyphs.SetScaleFactor(1.) examineGlyphMapper = vtk.vtkPolyDataMapper() examineGlyphMapper.SetInput(examineGlyphs.GetOutput()) examineGlyphMapper.ScalarVisibilityOff() self.ExamineSpheresActor = vtk.vtkActor() self.ExamineSpheresActor.SetMapper(examineGlyphMapper) self.ExamineSpheresActor.GetProperty().SetColor(0.0,1.0,0.0) self.ExamineSpheresActor.GetProperty().SetOpacity(self.Opacity) self.ExamineSpheresActor.PickableOff() self.ExamineSpheresActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ExamineSpheresActor) #self.vmtkRenderer.RenderWindowInteractor.AddObserver("KeyPressEvent", self.KeyPressed) self.vmtkRenderer.AddKeyBinding('u','Undo.',self.UndoCallback) self.vmtkRenderer.AddKeyBinding('space','Pick points.',self.SpaceCallback) self.vmtkRenderer.AddKeyBinding('w','Examine mode.',self.ExamineCallback) self.vmtkRenderer.AddKeyBinding('d','Display Distance.',self.DisplayDistanceCallback) self.vmtkRenderer.AddKeyBinding('a','Add.',self.AddCallback) self.SurfaceMapper = vtk.vtkPolyDataMapper() self.SurfaceMapper.SetInput(self.Surface) self.SurfaceMapper.SetScalarVisibility(self.DisplayArray) surfaceActor = vtk.vtkActor() surfaceActor.SetMapper(self.SurfaceMapper) surfaceActor.GetProperty().SetOpacity(self.Opacity) self.vmtkRenderer.Renderer.AddActor(surfaceActor) self.ScalarBarActor = vtk.vtkScalarBarActor() self.ScalarBarActor.SetLookupTable(self.SurfaceMapper.GetLookupTable()) self.ScalarBarActor.GetLabelTextProperty().ItalicOff() self.ScalarBarActor.GetLabelTextProperty().BoldOff() self.ScalarBarActor.GetLabelTextProperty().ShadowOff() self.ScalarBarActor.SetLabelFormat('%.2f') self.ScalarBarActor.SetTitle('distances') self.ScalarBarActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.ScalarBarActor) self.ExamineText = vtk.vtkTextActor() self.ExamineText.SetInput("Examine Mode") self.ExamineText.GetPositionCoordinate().SetCoordinateSystemToNormalizedViewport() self.ExamineText.SetPosition(0.05,0.95) self.ExamineText.VisibilityOff() self.vmtkRenderer.Renderer.AddActor2D(self.ExamineText) self.InputInfo('Please position the mouse and press space to add points, \'u\' to undo\n') any = 0 while any == 0: self.InitializeSeeds() self.vmtkRenderer.Render() any = self.SeedIds.GetNumberOfIds() self.Surface = self.ComputeDistances() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if self.OwnRenderer: self.vmtkRenderer.Deallocate() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/contrib/vmtkmeshaddexternallayer.py0000664000175000017500000002717511757446472022635 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshaddexternallayer.py,v $ ## Language: Python ## Date: $$ ## Version: $$ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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 ## Tangui Morvan ## Kalkulo AS ## Simula Research Laboratory ## This class builds an external layer around a mesh. import vtk import vtkvmtk import sys import vmtkscripts import vmtkcontribscripts import pypes vmtkmeshaddexternallayer = 'vmtkMeshAddExternalLayer' class vmtkMeshAddExternalLayer(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.CellEntityIdsArrayName = 'CellEntityIds' #Id of the first wall (mesh surface) self.SurfaceCellEntityId = 1 #Id of the first openprofile in the walls self.InletOutletCellEntityId = 2 #Id of the surface cells to extrude self.ExtrudeCellEntityId = 1 self.ThicknessArrayName = '' self.Thickness = 1.0 self.ThicknessRatio = 0.1 self.MaximumThickness = 1E10 self.NumberOfSubLayers = 1 self.SubLayerRatio = 1.0 self.ConstantThickness = 1; self.IncludeSurfaceCells = 0 self.NegateWarpVectors = 0 self.IncludeExtrudedOpenProfilesCells = 1 self.IncludeExtrudedSurfaceCells = 1 self.IncludeOriginalSurfaceCells = 0 self.SetScriptName('vmtkmeshaddexternallayer') self.SetScriptDoc('create an external prismatic layer from the wall of a mesh and the normals on the wall.') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['CellEntityIdsArrayName','entityidsarray','str',1,''], ['SurfaceCellEntityId','surfacecellentityid','int',1,'','id of the first surface cells in the entityids list'], ['InletOutletCellEntityId','inletoutletcellentityid','int',1], ['ExtrudeCellEntityId','extrudecellentityid','int',1,'','id of the surface cells to extrude'], ['ThicknessArrayName','thicknessarray','str',1,'','name of the array where scalars defining boundary layer thickness are stored'], ['Thickness','thickness','float',1,'','value of constant boundary layer thickness'], ['ThicknessRatio','thicknessratio','float',1,'(0.0,)','multiplying factor for boundary layer thickness'], ['MaximumThickness','maximumthickness','float',1,'','maximum allowed value for boundary layer thickness'], ['NumberOfSubLayers','numberofsublayers','int',1,'(0,)','number of sublayers which the boundary layer has to be made of'], ['SubLayerRatio','sublayerratio','float',1,'(0.0,)','ratio between the thickness of two successive boundary layers'], ['ConstantThickness','constantthickness','bool',1,'','toggle constant boundary layer thickness'], ['IncludeSurfaceCells','includesurfacecells','bool',0,'','include all surface cells in output mesh'], ['IncludeExtrudedOpenProfilesCells','includeextrudedopenprofilescells','bool',1,'','include the cells from the open profiles extruded surface in output mesh'], ['IncludeExtrudedSurfaceCells','includeextrudedsurfacecells','bool',1,'','include the cells from the extruded surface in output mesh'], ['IncludeOriginalSurfaceCells','includeoriginalsurfacecells','bool',1,'','include the cells from the original surfacein output mesh'] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'], ]) def Execute(self): if self.Mesh == None: self.PrintError('Error: No input mesh.') if not self.CellEntityIdsArrayName: self.PrintError('Error: No input CellEntityIdsArrayName.') return cellEntityIdsArray = self.Mesh.GetCellData().GetArray(self.CellEntityIdsArrayName) #cut off the volumetric elements wallThreshold = vtk.vtkThreshold() wallThreshold.SetInput(self.Mesh) wallThreshold.ThresholdByUpper(self.SurfaceCellEntityId-0.5) wallThreshold.SetInputArrayToProcess(0,0,0,1,self.CellEntityIdsArrayName) wallThreshold.Update() meshToSurface = vmtkscripts.vmtkMeshToSurface() meshToSurface.Mesh = wallThreshold.GetOutput() meshToSurface.Execute() #Compute the normals for this surface, orientation should be right because the surface is closed #TODO: Add option for cell normals in vmtksurfacenormals normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(meshToSurface.Surface) normalsFilter.SetAutoOrientNormals(1) normalsFilter.SetFlipNormals(0) normalsFilter.SetConsistency(1) normalsFilter.SplittingOff() normalsFilter.ComputePointNormalsOff() normalsFilter.ComputeCellNormalsOn() normalsFilter.Update() surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = normalsFilter.GetOutput() surfaceToMesh.Execute() #Save the current normals wallWithBoundariesMesh = surfaceToMesh.Mesh savedNormals = vtk.vtkDoubleArray() savedNormals.DeepCopy(wallWithBoundariesMesh.GetCellData().GetNormals()) savedNormals.SetName('SavedNormals') wallWithBoundariesMesh.GetCellData().AddArray(savedNormals) #cut off the boundaries and other surfaces extrudeThresholdLower = vtk.vtkThreshold() extrudeThresholdLower.SetInput(wallWithBoundariesMesh) extrudeThresholdLower.ThresholdByLower(self.ExtrudeCellEntityId+0.5) extrudeThresholdLower.SetInputArrayToProcess(0,0,0,1,self.CellEntityIdsArrayName) extrudeThresholdLower.Update() extrudeThresholdUpper = vtk.vtkThreshold() extrudeThresholdUpper.SetInput(extrudeThresholdLower.GetOutput()) extrudeThresholdUpper.ThresholdByUpper(self.ExtrudeCellEntityId-0.5) extrudeThresholdUpper.SetInputArrayToProcess(0,0,0,1,self.CellEntityIdsArrayName) extrudeThresholdUpper.Update() meshToSurface = vmtkscripts.vmtkMeshToSurface() meshToSurface.Mesh = extrudeThresholdUpper.GetOutput() meshToSurface.Execute() #Compute cell normals without boundaries normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(meshToSurface.Surface) normalsFilter.SetAutoOrientNormals(1) normalsFilter.SetFlipNormals(0) normalsFilter.SetConsistency(1) normalsFilter.SplittingOff() normalsFilter.ComputePointNormalsOn() normalsFilter.ComputeCellNormalsOn() normalsFilter.Update() wallWithoutBoundariesSurface = normalsFilter.GetOutput() normals = wallWithoutBoundariesSurface.GetCellData().GetNormals() savedNormals = wallWithoutBoundariesSurface.GetCellData().GetArray('SavedNormals') math = vtk.vtkMath() #If the normal are inverted, recompute the normals with flipping on if normals.GetNumberOfTuples() > 0 and math.Dot(normals.GetTuple3(0),savedNormals.GetTuple3(0)) < 0: normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(meshToSurface.Surface) normalsFilter.SetAutoOrientNormals(1) normalsFilter.SetFlipNormals(1) normalsFilter.SetConsistency(1) normalsFilter.SplittingOff() normalsFilter.ComputePointNormalsOn() normalsFilter.ComputeCellNormalsOn() normalsFilter.Update() wallWithoutBoundariesSurface = normalsFilter.GetOutput() wallWithoutBoundariesSurface.GetPointData().GetNormals().SetName('Normals') wallWithoutBoundariesSurface.GetCellData().RemoveArray('SavedNormals') surfaceToMesh = vmtkscripts.vmtkSurfaceToMesh() surfaceToMesh.Surface = wallWithoutBoundariesSurface surfaceToMesh.Execute() #Offset to apply to the array wallOffset = 0 if self.IncludeSurfaceCells or self.IncludeOriginalSurfaceCells: wallOffset += 1 if self.IncludeSurfaceCells or self.IncludeExtrudedSurfaceCells: wallOffset+=1 boundaryLayer = vmtkcontribscripts.vmtkBoundaryLayer2() boundaryLayer.Mesh = surfaceToMesh.Mesh boundaryLayer.WarpVectorsArrayName = 'Normals' boundaryLayer.NegateWarpVectors = False boundaryLayer.ThicknessArrayName = self.ThicknessArrayName boundaryLayer.ConstantThickness = self.ConstantThickness boundaryLayer.IncludeSurfaceCells = self.IncludeSurfaceCells boundaryLayer.NumberOfSubLayers = self.NumberOfSubLayers boundaryLayer.SubLayerRatio = self.SubLayerRatio boundaryLayer.Thickness = self.Thickness boundaryLayer.ThicknessRatio = self.Thickness boundaryLayer.MaximumThickness = self.MaximumThickness boundaryLayer.CellEntityIdsArrayName = self.CellEntityIdsArrayName boundaryLayer.IncludeExtrudedOpenProfilesCells = self.IncludeExtrudedOpenProfilesCells boundaryLayer.IncludeExtrudedSurfaceCells = self.IncludeExtrudedSurfaceCells boundaryLayer.IncludeOriginalSurfaceCells = self.IncludeOriginalSurfaceCells boundaryLayer.LayerEntityId = self.SurfaceCellEntityId boundaryLayer.SurfaceEntityId = self.InletOutletCellEntityId + 1 if cellEntityIdsArray != None: #Append the new surface ids idRange = cellEntityIdsArray.GetRange() boundaryLayer.OpenProfilesEntityId = idRange[1] + wallOffset + 2 boundaryLayer.Execute() if cellEntityIdsArray != None: #offset the previous cellentityids to make room for the new ones arrayCalculator = vtk.vtkArrayCalculator() arrayCalculator.SetInput(self.Mesh) arrayCalculator.SetAttributeModeToUseCellData() arrayCalculator.AddScalarVariable("entityid",self.CellEntityIdsArrayName,0) arrayCalculator.SetFunction("if( entityid > " + str(self.InletOutletCellEntityId-1) +", entityid + " + str(wallOffset) + ", entityid)") arrayCalculator.SetResultArrayName('CalculatorResult') arrayCalculator.Update() #This need to be copied in order to be of the right type (int) cellEntityIdsArray.DeepCopy(arrayCalculator.GetOutput().GetCellData().GetArray('CalculatorResult')) arrayCalculator.SetFunction("if( entityid > " + str(self.SurfaceCellEntityId-1) +", entityid + 1, entityid)") arrayCalculator.Update() ##This need to be copied in order to be of the right type (int) cellEntityIdsArray.DeepCopy(arrayCalculator.GetOutput().GetCellData().GetArray('CalculatorResult')) appendFilter = vtkvmtk.vtkvmtkAppendFilter() appendFilter.AddInput(self.Mesh) appendFilter.AddInput(boundaryLayer.Mesh) appendFilter.Update() self.Mesh = appendFilter.GetOutput() if self.Mesh.GetSource(): self.Mesh.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmeshvectorfromcomponents.py0000664000175000017500000000446011757446472022131 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmeshvectorfromcomponents.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkmeshvectorfromcomponents = 'vmtkMeshVectorFromComponents' class vmtkMeshVectorFromComponents(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Mesh = None self.VectorArrayName = None self.ComponentsArrayNames = None self.RemoveComponentArrays = False self.SetScriptName('vmtkmeshvectorfromcomponents') self.SetScriptDoc('scale a mesh by an isotropic factor') self.SetInputMembers([ ['Mesh','i','vtkUnstructuredGrid',1,'','the input mesh','vmtkmeshreader'], ['VectorArrayName','vector','str',1,'',''], ['ComponentsArrayNames','components','str',-1,'',''], ['RemoveComponentArrays','removecomponents','bool',1,'',''] ]) self.SetOutputMembers([ ['Mesh','o','vtkUnstructuredGrid',1,'','the output mesh','vmtkmeshwriter'] ]) def Execute(self): if (self.Mesh == None): self.PrintError('Error: no Mesh.') numberOfComponents = len(self.ComponentsArrayNames) vectorArray = vtk.vtkDoubleArray() vectorArray.SetName(self.VectorArrayName) vectorArray.SetNumberOfComponents(numberOfComponents) vectorArray.SetNumberOfTuples(self.Mesh.GetNumberOfPoints()) for i in range(numberOfComponents): componentArray = self.Mesh.GetPointData().GetArray(self.ComponentsArrayNames[i]) vectorArray.CopyComponent(i,componentArray,0) if self.RemoveComponentArrays: self.Mesh.GetPointData().RemoveArray(self.ComponentsArrayNames[i]) self.Mesh.GetPointData().AddArray(vectorArray) if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkimagevoiselector.py0000664000175000017500000002013511757446472020316 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkimagevoiselector.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:35:13 $ ## Version: $Revision: 1.9 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import math import vtkvmtk import vmtkrenderer import pypes vmtkimagevoiselector = 'vmtkImageVOISelector' class vmtkImageVOISelector(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.CubeSource = vtk.vtkCubeSource() self.CubeActor = vtk.vtkActor() self.BoxActive = 0 self.BoxBounds = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] self.CroppedImage = vtk.vtkImageData() self.vmtkRenderer = None self.OwnRenderer = 0 self.PlaneWidgetX = None self.PlaneWidgetY = None self.PlaneWidgetZ = None self.BoxWidget = None self.Image = None self.Interactive = 1 self.SetScriptName('vmtkimagevoiselector') self.SetScriptDoc('select a cubical volume of interest and get rid of the rest of the image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['Interactive','interactive','bool',1,'','toggle interactivity'], ['BoxBounds','boxbounds','float',6,'','bounds of the cubical region of interest'], ['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer'] ]) self.SetOutputMembers([ ['Image','o','vtkImageData',1,'','the output image','vmtkimagewriter'] ]) def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def HideCube(self,object, event): self.CubeActor.VisibilityOff() def UpdateCube(self,object, event): polyData = vtk.vtkPolyData() object.GetPolyData(polyData) polyData.ComputeBounds() self.CubeSource.SetBounds(polyData.GetBounds()) self.CubeSource.Modified() self.CubeActor.VisibilityOn() def Display(self): wholeExtent = self.Image.GetWholeExtent() picker = vtk.vtkCellPicker() picker.SetTolerance(0.005) self.PlaneWidgetX.SetInput(self.Image) self.PlaneWidgetX.SetPlaneOrientationToXAxes() self.PlaneWidgetX.SetSliceIndex(wholeExtent[0]) self.PlaneWidgetX.DisplayTextOn() self.PlaneWidgetX.SetPicker(picker) self.PlaneWidgetX.KeyPressActivationOff() self.PlaneWidgetX.On() self.PlaneWidgetY.SetInput(self.Image) self.PlaneWidgetY.SetPlaneOrientationToYAxes() self.PlaneWidgetY.SetSliceIndex(wholeExtent[2]) self.PlaneWidgetY.DisplayTextOn() self.PlaneWidgetY.SetPicker(picker) self.PlaneWidgetY.KeyPressActivationOff() self.PlaneWidgetY.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) self.PlaneWidgetY.On() self.PlaneWidgetZ.SetInput(self.Image) self.PlaneWidgetZ.SetPlaneOrientationToZAxes() self.PlaneWidgetZ.SetSliceIndex(wholeExtent[4]) self.PlaneWidgetZ.DisplayTextOn() self.PlaneWidgetZ.SetPicker(picker) self.PlaneWidgetZ.KeyPressActivationOff() self.PlaneWidgetZ.SetLookupTable(self.PlaneWidgetX.GetLookupTable()) self.PlaneWidgetZ.On() self.BoxWidget.SetPriority(1.0) self.BoxWidget.SetHandleSize(5E-3) self.BoxWidget.SetInput(self.Image) self.BoxWidget.PlaceWidget() self.BoxWidget.RotationEnabledOff() self.BoxWidget.AddObserver("StartInteractionEvent", self.HideCube) self.BoxWidget.AddObserver("EndInteractionEvent", self.UpdateCube) self.BoxWidget.AddObserver("EnableEvent", self.UpdateCube) self.BoxWidget.AddObserver("DisableEvent", self.HideCube) polyData = vtk.vtkPolyData() self.BoxWidget.GetPolyData(polyData) polyData.ComputeBounds() self.CubeSource.SetBounds(polyData.GetBounds()) cubeMapper = vtk.vtkPolyDataMapper() cubeMapper.SetInput(self.CubeSource.GetOutput()) self.CubeActor.SetMapper(cubeMapper) self.CubeActor.GetProperty().SetColor(0.6,0.6,0.2) self.CubeActor.GetProperty().SetOpacity(0.25) self.CubeActor.VisibilityOff() self.vmtkRenderer.Renderer.AddActor(self.CubeActor) self.vmtkRenderer.Renderer.ResetCamera() self.vmtkRenderer.Render() self.vmtkRenderer.Renderer.RemoveActor(self.CubeActor) self.BoxActive = 0 if self.BoxWidget.GetEnabled() == 1: polyData = vtk.vtkPolyData() self.BoxWidget.GetPolyData(polyData) polyData.ComputeBounds() bounds = polyData.GetBounds() self.BoxBounds[0] = bounds[0] self.BoxBounds[1] = bounds[1] self.BoxBounds[2] = bounds[2] self.BoxBounds[3] = bounds[3] self.BoxBounds[4] = bounds[4] self.BoxBounds[5] = bounds[5] self.BoxActive = 1 self.BoxWidget.Off() def ExtractVOI(self): wholeExtent = self.Image.GetWholeExtent() origin = self.Image.GetOrigin() spacing = self.Image.GetSpacing() newVOI = [0,0,0,0,0,0] newVOI[0] = max(wholeExtent[0],int(math.ceil((self.BoxBounds[0]-origin[0])/spacing[0]))) newVOI[1] = min(wholeExtent[1],int(math.floor((self.BoxBounds[1]-origin[0])/spacing[0]))) newVOI[2] = max(wholeExtent[2],int(math.ceil((self.BoxBounds[2]-origin[1])/spacing[1]))) newVOI[3] = min(wholeExtent[3],int(math.floor((self.BoxBounds[3]-origin[1])/spacing[1]))) newVOI[4] = max(wholeExtent[4],int(math.ceil((self.BoxBounds[4]-origin[2])/spacing[2]))) newVOI[5] = min(wholeExtent[5],int(math.floor((self.BoxBounds[5]-origin[2])/spacing[2]))) extractVOI = vtk.vtkExtractVOI() extractVOI.SetInput(self.CroppedImage) extractVOI.SetVOI(newVOI) extractVOI.Update() self.CroppedImage.DeepCopy(extractVOI.GetOutput()) self.CroppedImage.Update() if self.CroppedImage.GetSource(): self.CroppedImage.GetSource().UnregisterAllOutputs() def InteractCallback(self): if self.BoxWidget.GetEnabled() == 1: self.BoxWidget.SetEnabled(0) else: self.BoxWidget.SetEnabled(1) def Execute(self): if self.Image == None: self.PrintError('Error: no Image.') self.CroppedImage.DeepCopy(self.Image) if self.Interactive == 1: if not self.vmtkRenderer: self.vmtkRenderer = vmtkrenderer.vmtkRenderer() self.vmtkRenderer.Initialize() self.OwnRenderer = 1 self.vmtkRenderer.RegisterScript(self) self.PlaneWidgetX = vtk.vtkImagePlaneWidget() self.PlaneWidgetX.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetY = vtk.vtkImagePlaneWidget() self.PlaneWidgetY.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.PlaneWidgetZ = vtk.vtkImagePlaneWidget() self.PlaneWidgetZ.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.BoxWidget = vtk.vtkBoxWidget() self.BoxWidget.SetInteractor(self.vmtkRenderer.RenderWindowInteractor) self.vmtkRenderer.AddKeyBinding('i','Interact.',self.InteractCallback) self.InputInfo("Press 'i' to activate interactor") self.Display() while (self.BoxActive == 1): self.ExtractVOI() self.Image = self.CroppedImage self.Display() else: self.ExtractVOI() if self.OwnRenderer: self.vmtkRenderer.Deallocate() self.Image = self.CroppedImage if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtksurfacenormals.py0000664000175000017500000000527511757446472020011 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtksurfacenormals.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:49:59 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import vtkvmtk import sys import pypes vmtksurfacenormals = 'vmtkSurfaceNormals' class vmtkSurfaceNormals(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Surface = None self.NormalsArrayName = 'Normals' self.ComputeCellNormals = 0 self.AutoOrientNormals = 1 self.FlipNormals = 0 self.Consistency = 1 self.SetScriptName('vmtksurfacenormals') self.SetScriptDoc('compute normals to a surface') self.SetInputMembers([ ['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'], ['NormalsArrayName','normalsarray','str',1,'','name of the array where normals have to be stored'], ['AutoOrientNormals','autoorientnormals','bool',1,'','try to auto orient normals outwards'], ['Consistency','consistency','bool',1,'','try to orient normals so that neighboring points have similar orientations'], ['ComputeCellNormals','cellnormals','bool',1,'','compute cell normals instead of point normals'], ['FlipNormals','flipnormals','bool',1,'','flip normals after computing them'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Surface == None: self.PrintError('Error: No Surface.') normalsFilter = vtk.vtkPolyDataNormals() normalsFilter.SetInput(self.Surface) normalsFilter.SetAutoOrientNormals(self.AutoOrientNormals) normalsFilter.SetFlipNormals(self.FlipNormals) normalsFilter.SetConsistency(self.Consistency) normalsFilter.SetComputeCellNormals(self.ComputeCellNormals) normalsFilter.SplittingOff() normalsFilter.Update() self.Surface = normalsFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if self.NormalsArrayName != '': self.Surface.GetPointData().GetNormals().SetName(self.NormalsArrayName) if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/vmtkScripts/vmtkmarchingcubes.py0000664000175000017500000000531411757446472017571 0ustar lucaluca#!/usr/bin/env python ## Program: VMTK ## Module: $RCSfile: vmtkmarchingcubes.py,v $ ## Language: Python ## Date: $Date: 2006/02/06 09:49:42 $ ## Version: $Revision: 1.7 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import vtk import sys import pypes vmtkmarchingcubes = 'vmtkMarchingCubes' class vmtkMarchingCubes(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.Image = None self.Surface = None self.ArrayName = '' self.Level = 0.0 self.Connectivity = 0 self.SetScriptName('vmtkmarchingcubes') self.SetScriptDoc('generate an isosurface of given level from a 3D image') self.SetInputMembers([ ['Image','i','vtkImageData',1,'','the input image','vmtkimagereader'], ['ArrayName','array','str',1,'','name of the array to work with'], ['Level','l','float',1,'','graylevel to generate the isosurface at'], ['Connectivity','connectivity','bool',1,'','only output the largest connected region of the isosurface'] ]) self.SetOutputMembers([ ['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter'] ]) def Execute(self): if self.Image == None: self.PrintError('Error: No Image.') extent = self.Image.GetWholeExtent() translateExtent = vtk.vtkImageTranslateExtent() translateExtent.SetInput(self.Image) translateExtent.SetTranslation(-extent[0],-extent[2],-extent[4]) translateExtent.Update() if (self.ArrayName != ''): translateExtent.GetOutput().GetPointData().SetActiveScalars(self.ArrayName) marchingCubes = vtk.vtkMarchingCubes() marchingCubes.SetInput(translateExtent.GetOutput()) marchingCubes.SetValue(0,self.Level) marchingCubes.Update() self.Surface = marchingCubes.GetOutput() if self.Connectivity == 1: connectivityFilter = vtk.vtkPolyDataConnectivityFilter() connectivityFilter.SetInput(self.Surface) connectivityFilter.SetExtractionModeToLargestRegion() connectivityFilter.Update() self.Surface = connectivityFilter.GetOutput() if self.Surface.GetSource(): self.Surface.GetSource().UnRegisterAllOutputs() if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/SuperBuild.cmake0000664000175000017500000001231411757446472014230 0ustar lucaluca############################################################################## # # Library: VMTK # ############################################################################## include( ExternalProject ) set( base "${CMAKE_BINARY_DIR}" ) set_property( DIRECTORY PROPERTY EP_BASE ${base} ) #set( shared ON ) #if ( BUILD_SHARED_LIBS ) # set( shared "${BUILD_SHARED_LIBS}" ) #endif() #set( testing OFF ) #set( examples OFF ) #set( build_type "Debug" ) #if( CMAKE_BUILD_TYPE ) # set( build_type "${CMAKE_BUILD_TYPE}" ) #endif() set( VMTK_DEPENDS "" ) set( gen "${CMAKE_GENERATOR}" ) ## ## Check if sytem ITK or superbuild ITK ## if( NOT USE_SYSTEM_ITK ) ## ## ITK ## set( proj ITK ) ExternalProject_Add( ${proj} GIT_REPOSITORY "${GIT_PROTOCOL}://github.com/Kitware/ITK.git" GIT_TAG "v3.20.1" SOURCE_DIR "${CMAKE_BINARY_DIR}/ITK" BINARY_DIR ITK-Build CMAKE_GENERATOR ${gen} CMAKE_ARGS -Dgit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/Install -DITK_USE_FLAT_DIRECTORY_INSTALL:BOOL=${ITK_USE_FLAT_DIRECTORY_INSTALL} -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DITK_USE_REVIEW:BOOL=ON -DITK_USE_OPTIMIZED_REGISTRATION_METHODS:BOOL=ON #INSTALL_DIR "Install/ITK" ) set( ITK_DIR "${base}/ITK-Build" ) set( VMTK_DEPENDS ${VMTK_DEPENDS} "ITK" ) endif( NOT USE_SYSTEM_ITK ) ## ## Check if sytem VTK or superbuild VTK ## if( NOT USE_SYSTEM_VTK ) ## ## VTK ## set( proj VTK ) ExternalProject_Add( VTK GIT_REPOSITORY "${GIT_PROTOCOL}://github.com/lantiga/VTK.git" GIT_TAG "v5.8.0-vmtk" SOURCE_DIR "${CMAKE_BINARY_DIR}/VTK" BINARY_DIR VTK-Build CMAKE_GENERATOR ${gen} CMAKE_ARGS -Dgit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/Install -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} -DVTK_WRAP_PYTHON:BOOL=${VTK_VMTK_WRAP_PYTHON} -DVTK_USE_TK:BOOL=OFF -DVTK_USE_CARBON:BOOL=${VTK_USE_CARBON} -DVTK_USE_COCOA:BOOL=${VTK_VMTK_USE_COCOA} -DVTK_USE_INFOVIS:BOOL=${VTK_USE_INFOVIS} -DVTK_USE_N_WAY_ARRAYS:BOOL=${VTK_USE_N_WAY_ARRAYS} -DVTK_USE_PARALLEL:BOOL=${VTK_USE_PARALLEL} -DVTK_USE_QT:BOOL=${VTK_USE_QT} -DVTK_USE_RENDERING:BOOL=${VTK_USE_RENDERING} -DVTK_USE_HYBRID:BOOL=${VTK_USE_HYBRID} -DVTK_USE_TEXT_ANALYSIS:BOOL=${VTK_USE_TEXT_ANALYSIS} -DVTK_USE_X:BOOL=${VTK_USE_X} -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DVTK_USE_GUISUPPORT:BOOL=OFF -DVTK_INSTALL_PYTHON_USING_CMAKE:BOOL=ON #INSTALL_DIR "Install/VTK" ) set( VTK_DIR "${base}/VTK-Build" ) set( VMTK_DEPENDS ${VMTK_DEPENDS} "VTK" ) endif( NOT USE_SYSTEM_VTK ) ## ## VMTK - Normal Build ## set( proj VMTK ) ExternalProject_Add( ${proj} DOWNLOAD_COMMAND "" SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" BINARY_DIR VMTK-Build CMAKE_GENERATOR ${gen} CMAKE_ARGS -DBUILDNAME:STRING=${BUILDNAME} -DSITE:STRING=${SITE} -DMAKECOMMAND:STRING=${MAKECOMMAND} -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS} -DBUILD_EXAMPLES:BOOL=${BUILD_EXAMPLES} -DBUILD_TESTING:BOOL=${BUILD_TESTING} -DBUILD_DOCUMENTATION:BOOL=${BUILD_DOCUMENTATION} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} -DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}/Install -DVTK_VMTK_WRAP_PYTHON:BOOL=${VTK_VMTK_WRAP_PYTHON} -DVMTK_USE_SUPERBUILD:BOOL=OFF -DVMTK_CONTRIB_SCRIPTS:BOOL=${VMTK_CONTRIB_SCRIPTS} -DVTK_VMTK_CONTRIB:BOOL=${VTK_VMTK_CONTRIB} -DVMTK_SCRIPTS_ENABLED:BOOL=${VMTK_SCRIPTS_ENABLED} -DVMTK_MINIMAL_INSTALL:BOOL=OFF -DVMTK_ENABLE_DISTRIBUTION:BOOL=${VMTK_ENABLE_DISTRIBUTION} -DVMTK_WITH_LIBRARY_VERSION:BOOL=OFF -DVMTK_BUILD_TETGEN:BOOL=${VMTK_BUILD_TETGEN} -DVTK_VMTK_USE_COCOA:BOOL=${VTK_VMTK_USE_COCOA} -DVMTK_BUILD_STREAMTRACER:BOOL=${VMTK_BUILD_STREAMTRACER} -DVTK_REQUIRED_OBJCXX_FLAGS:STRING=${VTK_REQUIRED_OBJCXX_FLAGS} -DITK_DIR:PATH=${ITK_DIR} -DVTK_DIR:PATH=${VTK_DIR} #INSTALL_DIR "Install/vmtk" DEPENDS ${VMTK_DEPENDS} ) vmtk-1.0.1/CMakeLists.txt0000664000175000017500000002113611757446472013712 0ustar lucalucaPROJECT(VMTK) CMAKE_MINIMUM_REQUIRED(VERSION 2.8) IF(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) ENDIF(COMMAND cmake_policy) # vmtk versions number SET(VMTK_VERSION_MAJOR 1) SET(VMTK_VERSION_MINOR 0) SET(VMTK_VERSION_PATCH 1) SET(VMTK_VERSION "${VMTK_VERSION_MAJOR}.${VMTK_VERSION_MINOR}.${VMTK_VERSION_PATCH}") # Append the library version information to the library target properties. OPTION(VMTK_WITH_LIBRARY_VERSION "Build with library version information" OFF) IF(VMTK_WITH_LIBRARY_VERSION) # This setting of SOVERSION assumes that any API change # will increment either the minor or major version number of vmtk. SET(VMTK_LIBRARY_PROPERTIES VERSION "${VMTK_VERSION}" SOVERSION "${VMTK_VERSION_MAJOR}.${VMTK_VERSION_MINOR}" ) ENDIF(VMTK_WITH_LIBRARY_VERSION) #----------------------------------------------------------------------------- # ITK Setup option( USE_SYSTEM_ITK "Exclude ITK from SuperBuild and use an existing build instead." OFF ) if( USE_SYSTEM_ITK ) find_package( ITK REQUIRED ) include( ${ITK_USE_FILE} ) endif( USE_SYSTEM_ITK ) #----------------------------------------------------------------------------- # VTK Setup option( USE_SYSTEM_VTK "Exclude VTK from SuperBuild and use an existing build instead." OFF ) if( USE_SYSTEM_VTK ) find_package( VTK REQUIRED ) include( ${VTK_USE_FILE} ) endif( USE_SYSTEM_VTK ) #----------------------------------------------------------------------------- # Superbuild setup option( VMTK_USE_SUPERBUILD "Build VMTK and the projects it depends on via SuperBuild.cmake." ON ) option( VMTK_BUNJEE_BUILD "Build VMTK and the projects it depends on ready for being linked from Bunjee." OFF ) if( APPLE ) set ( CMAKE_CXX_COMPILER "/usr/bin/g++" CACHE STRING "CXX compiler." FORCE) endif( APPLE ) if( VMTK_USE_SUPERBUILD ) if( NOT GIT_EXECUTABLE ) find_package( Git REQUIRED ) endif( NOT GIT_EXECUTABLE ) option( GIT_PROTOCOL_HTTPS "Use HTTPS for git access (useful if behind a firewall)" OFF ) if( GIT_PROTOCOL_HTTPS ) set( GIT_PROTOCOL "https" CACHE STRING "Https protocol for file transfer" FORCE ) else( GIT_PROTOCOL_HTTPS ) set( GIT_PROTOCOL "git" CACHE STRING "Git protocol for file transfer" FORCE ) endif( GIT_PROTOCOL_HTTPS ) mark_as_advanced( GIT_PROTOCOL ) if( VMTK_BUNJEE_BUILD ) set ( VTK_VMTK_WRAP_PYTHON OFF CACHE BOOL "" FORCE ) set ( VMTK_CONTRIB_SCRIPTS OFF CACHE BOOL "" FORCE ) set ( VMTK_ENABLE_DISTRIBUTION OFF CACHE BOOL "" FORCE ) #set ( VMTK_BUILD_TETGEN OFF CACHE BOOL "" FORCE ) set ( VMTK_SCRIPTS_ENABLED OFF CACHE BOOL "" FORCE ) set ( BUILD_EXAMPLES OFF CACHE BOOL "" FORCE ) set ( BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE ) set ( BUILD_TESTING OFF CACHE BOOL "" FORCE ) set ( VTK_USE_CARBON OFF ) set ( VTK_USE_COCOA ON ) set ( VTK_VMTK_USE_COCOA ON ) set ( VTK_USE_INFOVIS OFF ) set ( VTK_USE_N_WAY_ARRAYS OFF ) set ( VTK_USE_PARALLEL OFF ) set ( VTK_USE_QT OFF ) set ( VTK_USE_RENDERING ON ) set ( VTK_USE_TEXT_ANALYSIS OFF ) set ( VTK_USE_X OFF ) set ( VTK_WRAP_PYTHON OFF ) set ( VTK_WRAP_TCL OFF ) set ( ITK_USE_FLAT_DIRECTORY_INSTALL ON ) set ( CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE ) set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE ) set ( ITK_NO_LIBRARY_VERSION ON ) set ( VTK_NO_LIBRARY_VERSION ON ) set ( VMTK_WITH_LIBRARY_VERSION OFF ) set ( VTK_REQUIRED_OBJCXX_FLAGS "-fobjc-gc" CACHE STRING "" FORCE) else (VMTK_BUNJEE_BUILD) option ( VTK_VMTK_WRAP_PYTHON "Generate Python wrappings for C++ classes." ON ) option ( VMTK_CONTRIB_SCRIPTS "Install modules from the vmtkScripts/contrib directory." ON ) option ( VTK_VMTK_CONTRIB "Build and install classes in the vtkVmtk/Contrib directory." ON ) option ( VMTK_ENABLE_DISTRIBUTION "Enable distribution targets." OFF ) option ( VMTK_BUILD_TETGEN "Build TetGen and TetGen wrapper. Check TetGen license before you activate this." ON ) option ( VMTK_BUILD_STREAMTRACER "Build static temporal stream tracer." ON ) if (APPLE) option ( VTK_VMTK_USE_COCOA "Build with Cocoa support." ON ) set ( CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE ) endif (APPLE) set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE ) option ( BUILD_SHARED_LIBS "Build shared libraries." ON ) option ( VTK_USE_RENDERING "Build VTK rendering classes." ON ) option ( VTK_USE_HYBRID "Build VTK Hybrid classes." ON ) OPTION(VMTK_SCRIPTS_ENABLED "Build and install vmtkScripts and Pypes" ON) OPTION(VMTK_MINIMAL_INSTALL "Do not install individual scripts, only vmtk.py" OFF) endif (VMTK_BUNJEE_BUILD) include( "${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake" ) return() else( VMTK_USE_SUPERBUILD ) if ( NOT ITK_FOUND ) find_package( ITK REQUIRED ) include( ${ITK_USE_FILE} ) endif( NOT ITK_FOUND ) if ( NOT VTK_FOUND ) find_package( VTK REQUIRED ) include( ${VTK_USE_FILE} ) endif( NOT VTK_FOUND ) endif( VMTK_USE_SUPERBUILD ) OPTION(VMTK_SCRIPTS_ENABLED "Build and install vmtkScripts and Pypes" ON) MARK_AS_ADVANCED(VMTK_SCRIPTS_ENABLED) IF(VMTK_SCRIPTS_ENABLED) SUBDIRS( PypeS vtkVmtk vmtkScripts ) ELSE(VMTK_SCRIPTS_ENABLED) SUBDIRS( vtkVmtk ) ENDIF(VMTK_SCRIPTS_ENABLED) OPTION(VMTK_MINIMAL_INSTALL "Do not install individual scripts, only vmtk.py" OFF) SET(LIBRARY_OUTPUT_PATH ${VMTK_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") SET(EXECUTABLE_OUTPUT_PATH ${VMTK_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") MARK_AS_ADVANCED(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH) SET(VMTK_SRCS vmtk.py ) SET(VMTK_MODULE_SRCS __init__.py.in ) IF(NOT VMTK_INSTALL_BIN_DIR) #SET(VMTK_INSTALL_BIN_DIR ${VMTK_INSTALL_ROOT}/bin) SET(VMTK_INSTALL_BIN_DIR bin) ENDIF(NOT VMTK_INSTALL_BIN_DIR) IF(NOT VMTK_MODULE_INSTALL_LIB_DIR) #SET(VMTK_MODULE_INSTALL_LIB_DIR ${VMTK_SCRIPTS_INSTALL_ROOT}/lib/vmtk/vmtk) SET(VMTK_MODULE_INSTALL_LIB_DIR lib/vmtk/vmtk) ENDIF(NOT VMTK_MODULE_INSTALL_LIB_DIR) IF(VMTK_SCRIPTS_ENABLED) FOREACH (SCRIPT_FILE ${VMTK_SRCS}) CONFIGURE_FILE(${VMTK_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) ENDFOREACH (SCRIPT_FILE) CONFIGURE_FILE(${VMTK_SOURCE_DIR}/__init__.py.in ${VMTK_BINARY_DIR}/__init__.py COPYONLY) INSTALL(FILES __init__.py.in DESTINATION ${VMTK_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries RENAME __init__.py) IF (NOT WIN32) SET (STRIPPED_SCRIPTS_SRCS ) FOREACH (SCRIPT_FILE ${VMTK_SRCS}) CONFIGURE_FILE(${VMTK_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) STRING(REGEX REPLACE ".py" "" STRIPPED_SCRIPT_FILE ${SCRIPT_FILE}) CONFIGURE_FILE(${VMTK_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_BINARY_DIR}/${STRIPPED_SCRIPT_FILE} COPYONLY) SET (STRIPPED_SCRIPTS_SRCS ${STRIPPED_SCRIPTS_SRCS} ${VMTK_BINARY_DIR}/${STRIPPED_SCRIPT_FILE}) ENDFOREACH (SCRIPT_FILE) #INSTALL_PROGRAMS(${VMTK_INSTALL_BIN_DIR} FILES ${STRIPPED_SCRIPTS_SRCS}) INSTALL(PROGRAMS ${STRIPPED_SCRIPTS_SRCS} DESTINATION ${VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables) ELSE (NOT WIN32) FOREACH (SCRIPT_FILE ${VMTK_SRCS}) CONFIGURE_FILE(${VMTK_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) STRING(REGEX REPLACE ".py" "-exe.py" STRIPPED_SCRIPT_FILE ${SCRIPT_FILE}) CONFIGURE_FILE(${VMTK_SOURCE_DIR}/${SCRIPT_FILE} ${VMTK_BINARY_DIR}/${STRIPPED_SCRIPT_FILE} COPYONLY) SET (STRIPPED_SCRIPTS_SRCS ${STRIPPED_SCRIPTS_SRCS} ${VMTK_BINARY_DIR}/${STRIPPED_SCRIPT_FILE}) ENDFOREACH (SCRIPT_FILE) #INSTALL_PROGRAMS(${VMTK_INSTALL_BIN_DIR} FILES ${STRIPPED_SCRIPTS_SRCS}) INSTALL(PROGRAMS ${STRIPPED_SCRIPTS_SRCS} DESTINATION ${VMTK_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables) ENDIF (NOT WIN32) OPTION(VMTK_ENABLE_DISTRIBUTION "Enable distribution targets." OFF) IF(VMTK_ENABLE_DISTRIBUTION) ADD_SUBDIRECTORY(distribution) ENDIF(VMTK_ENABLE_DISTRIBUTION) # Export Build settings and library dependencies # INCLUDE(CMakeExportBuildSettings) # # CMAKE_EXPORT_BUILD_SETTINGS( # ${VMTK_BINARY_DIR}/VMTKBuildSettings.cmake # ) # # EXPORT_LIBRARY_DEPENDENCIES( # ${VMTK_BINARY_DIR}/VMTKLibraryDepends.cmake # ) CONFIGURE_FILE( ${VMTK_SOURCE_DIR}/CMakeInput/VMTKConfig.cmake.in ${VMTK_BINARY_DIR}/VMTKConfig.cmake @ONLY IMMEDIATE ) CONFIGURE_FILE( ${VMTK_SOURCE_DIR}/CMakeInput/VMTKUse.cmake.in ${VMTK_BINARY_DIR}/VMTKUse.cmake @ONLY IMMEDIATE ) ENDIF(VMTK_SCRIPTS_ENABLED) vmtk-1.0.1/distribution/0000775000175000017500000000000011757446472013666 5ustar lucalucavmtk-1.0.1/distribution/bundle/0000775000175000017500000000000011757446472015137 5ustar lucalucavmtk-1.0.1/distribution/bundle/vmtk-startup0000664000175000017500000000115011757446472017540 0ustar lucaluca#!/bin/sh if [ "$BASH_SOURCE" == "$0" ];then BUNDLE=`echo "$0" | sed -e 's/\/Contents\/MacOS\/.*//'` else BUNDLE=`echo "$BASH_SOURCE" | sed -e 's/\/Contents\/MacOS\/.*//'` fi RESOURCES=$BUNDLE/Contents/Resources echo "BUNDLE: $BUNDLE" echo "RESOURCES: $RESOURCES" VMTKHOME=$RESOURCES export PATH=$VMTKHOME/bin:$PATH export DYLD_LIBRARY_PATH=$VMTKHOME/lib/vtk-5.8:$VMTKHOME/lib/InsightToolkit:$VMTKHOME/lib/vmtk:$DYLD_LIBRARY_PATH export PYTHONPATH=$VMTKHOME/bin/Python:$VMTKHOME/lib/vtk-5.8:$VMTKHOME/lib/vmtk:$PYTHONPATH if [ "$BASH_SOURCE" == "$0" ];then exec "/usr/bin/python" "$RESOURCES/bin/vmtk" fi vmtk-1.0.1/distribution/bundle/vmtk.icns0000664000175000017500000007305211757446472017005 0ustar lucalucaicnsv*is32ÜÿŒþÿþŒûâj‰mlpÝM‰POSÜL„O€PQONRÛDKJJ€KMLEEDBLGLÚ?9=:8674QPdm1CGÙ:aŠŽ­ Ñœ¬„C@Ú'¡å޲±´¶¥¥wÿ )>Ø%QÐAy‹p±‡–¡:3Ö*+%,*€+(//%+.1Òí¤‰¦¥¨ÿþŒüÿŒþÿþŒü鉎‘äs‰vuyãp†sttsrvâgm€l€mKhhffnimà`[_[ZXYVpnƒUdfÞZ yœ ¹¯ ¯Ö­µ—_]ßG±èž¾»¿À±°ÿªHZÝAkÔZŸ‰š‚»—¢­RNÛDE@FE BIH@EHJ×/4534€34335417©¨ªÿþŒýÿþŒý憎¬«®ê•‰—–™é„‘’‘“臊€‹K†‡……‹ˆ‹æ~z}zyxxvŒˆššuƒäy±‘®²Å½¯ÀÛ½Á©{{ågÀë­ÊÆÊÉ¿»£ÿµgvã^…Ús¯›¢«–Ũ±¹ljà_`\a` ^dc\aceÝMQQ‚PQOOQPNTí¤‰¦¥¨ŽÿŒþs8mkPPPPPPPPPPPPPPPPÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüüüüüüüüüüüüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþþþþþþþþþþþþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4444444444444444il32ŸÞÿœýžÿÏ×ÅÆÁØÿnIQ–PRE‰ÿuSZ–Y[OÿqNV–UWJŒÿnJR–QSFŠÿmHP–OQDˆÿiDM–KM@†ÿhBKIJLJIL>„ÿe>G…E FEEFFEECDFB7AF€EH9‚ÿc.zÿY3)¦úÿdOÿw=ÿ‰2ÿ¤3ÿž iÿøÿc&;:+xÿV..Yüýá-Yÿ€Gÿ‘=ÿ¢;ÿµ-hÿ°îÖ137'vÿT)4+Çÿ•Zÿ{CÿŒ8ÿ£%ÓÿÑgÿeyÿ‘&6$tÿQ&0,;M4+3L80L:/K>(5`R4L8+JI-1!rÿO#-,(#*,)#(*#(+$'1,) #)#),$$+.pÿL *()*)()*)(*)(*)()**)*((*)(+nÿI&–$'kÿI&–$'kÿǹ½–¼½¸Òÿ›ýþýÿÞÿ›ýþžÿÚÑ—ÓÔÐáÿtz–y{q¥ÿ•z€–w©ÿtz–y{q¥ÿqw–vxm£ÿŠms–rti ÿ‡ho–npežÿƒdkŒjkkjkmkjla›ÿahŒgefhd[dh€gi^™ÿ}]eedceedeedeededeji`x±w`fcceY–ÿzY^TZ`VV]USWXSVYWkö¦@ÿOU\`aU“ÿxN}Õ‰N±½yʵ޼’ÞÌa´ÿï¶Šÿ€ÜŒT_Q‘ÿuNfþË[ÿ½wÿÜÒÿàÍÿš•ÿÜ”‰ÿ ðß^V[NÿqPHºö¢ÿqqÿ}_ÿ‘Wÿ¥Uÿ¥.‡ÿøÿqHWVIŒÿmKJwÿþßExÿ†fÿ˜^ÿ¢\ÿ¸H…ÿµõÔJPSE‰ÿjENJÔÿ›7wÿ€aÿ“Yÿ£EÞÿÏ~ÿm“ÿ—BQA‡ÿhBKGUcLGOcPKcSJcVDQtfNcPGb_HFL>„ÿd>FFB>DFC>CD>BE?BFC;>C>DE>?EH9‚ÿa:CABCBABCAACBACBABCCBCAACBAD5ÿ^6?–=@1|ÿ]4>–<?0|ÿÄ´¸–·¸³Ïÿûšúüžÿœþ½ÿÞÿœþžÿäݘÞÜéÿ¬˜–œ–¼ÿ¯› –Ÿ ™¾ÿª•š–™š“ºÿ§‘––•–ޏÿ£’–‘“еÿ ‰Ž–†²ÿ„ЉŠ‹‚‰‹‚¯ÿš€†‹…„ƒ„†‚{ƒ…‡}­ÿ–|ƒƒ‚ƒ‚ƒƒ‚‚ƒ‚ƒƒ†…•À„ƒyªÿ“x{sy~uv{trvvsuwuŒü¯b¬ÿžpt{}u§ÿ‘n˜Ý™oÃÄ’ÔÃäŨåÑ|Èÿð¿¤ÿ›âœs|q¥ÿl„ÿÌzÿÀ•ÿßÜÿã×ÿ¦®ÿߣ¥ÿ¯÷ßxtwl¢ÿ‰nhÍóµÿ‚‘ÿŒ€ÿžzÿ©zÿ«Q£ÿûþƒhsshŸÿ…hf“ÿÿß`–ÿ’ƒÿ£ÿ§}ÿ½e ÿÀûÓemncœÿ‚biiáÿ¤V“ÿ~ÿžyÿ¨eçÿÑ™ÿ~¬ÿ¡`l_šÿ_gcq{gck{jh|lg{n`lŠ{j|jd{wd)g[—ÿ{Zaa][``_[__Z^`[^a^X[_Z_aZ\`bV”ÿxV]\]]€\]\\]\\]]\]^]\]\\]]\^R‘ÿtRY–XZNÿsQX–WYMŽÿ·¥©–¨©£Äÿõ™óò÷žÿœþ½ÿl8mk''''''''''''''''''''''''''''''''ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØit32)ƒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØÿ{hmòlneæÿþ€ÿhSXòWYOãÿþ€ÿmX]ò\^Täÿþ€ÿkV[òZ\Rãÿþ€ÿkV[òZ\Rãÿþ€ÿjUZòY[Qãÿþ€ÿiTYòXZPãÿþ€ÿhSXòWYOãÿþ€ÿgRWòVXNãÿþ€ÿgRWòVXNãÿþ€ÿfQVòUWMâÿþ€ÿfQVòUWMâÿþ€ÿePUòTVLâÿþ€ÿdNTòSUJâÿþ€ÿdMSòRTIâÿþ€ÿcLRòQSHâÿþ€ÿbKQòPRGâÿþ€ÿbKQòPRGâÿþ€ÿbKQòPRGâÿþ€ÿ`IOòNPEáÿþ€ÿ`IOòNPEáÿþ€ÿ_HNòMODáÿþ€ÿ^GMòLNCáÿþ€ÿ]FLòKMBáÿþ€ÿ]FLòKMBáÿþ€ÿ\EKòJLAáÿþ€ÿ[DJòIK@àÿþ€ÿ[DJòIK@àÿþ€ÿ[CIòHJ?àÿþ€ÿZBHòGI>àÿþ€ÿYAGòFH=àÿþ€ÿYAGòFH=àÿþ€ÿW?EòDF;àÿý€ÿW?EÐDE‚GF˜DF;àÿý€ÿW?EÏDE?7€87:C—DF;àÿý€ÿU=CÁBE‚FEƒB C>`•ŽŽ“ƒHAC•BD9ßÿý€ÿU=CÁB6327C‚B D:—ÿüÿýÿåY=D•BD9ßÿý€ÿU=CÀB @{‹‰‰ˆŒv>CB D:™ÿûþüÿâW=D•BD9ßÿý€ÿS;A¿@ A:èÿþÿýÿ×4C@ B8˜ÿüÿýÿâU;B•@B7ßÿý€ÿR:@¿? @9ÙÿúûùÿÌ3B? A7—ÿüÿýÿáT:A•?A5ßÿý€ÿR:@„?„A…?„A€?ƒA??@A€?@A@‚?A@€?@Aƒ? B;ÜÿþÿýÿÏ5D€A@A7—ÿüÿýÿáT:A??@„A@Š?A5ßÿý€ÿR9?ƒ>=7ƒ5?„>6‚57>><‚56>A@48€=78A> =6/ÚÿþÿýÿË(8€5;@6•ÿüÿýÿáR9@>?=ƒ54:?‰>@4ßÿý€ÿQ8>ƒ=?[eb€cb=<‚=@^d€ceY<@28b•ÀÇÈ’S1>==>9Dd‚cdN;>ˆ=?3Þÿý€ÿQ8>=1>=?Æÿüÿÿþÿe7>==?4möÿþÿþÿË:7nÿþÿþÿòc}æÿþÿÿþÿ×d63c»ü€ÿ þÿð6>>7dÿþ‰ÿ‡67•ÿüÿýÿàQ8?>8±ÿýÿÿþÿô_8>ˆ=?3Þÿý€ÿP7=‚<<@+—ÿúþþüÿ‚67pÿýþþÿ÷ÚøÿüýþþýüÿçO‹÷ÿ€ý þþüýÿ€1@6kÿý„ÿ‚þƒ55“ÿüÿýÿßP7A2Œÿü€þüÿˆ2>‰<>2Þÿý€ÿO6<‚; =6Víÿþÿþÿâ€;<9FÏÿýÿþÿïM65oÿþ‚ÿüüþþÿýÿøûÿú€þ€ÿýÿéJ66iÿü„ÿ‚ý€44“ÿüÿýÿßO92`ûÿþÿÿüÿ¨4<Š;=1Þÿý€ÿN5;ƒ:=,Àÿþÿþÿü{0=<1\ÿþÿÿûÿ£2=4mÿþ€ÿþüþ€ÿþÿþÿüþ€ÿþÿüÿƒ45iÿþ‰ÿ‡23’ÿüÿýÿßP1OæÿýÿÿüÿÀ::<Š:<0Þÿý€ÿN5;ƒ:;5qÿüÿª)>;6–ÿýÿþÿÿp-?3mÿþ‚ÿö×Ïë…ÿüáÌáýÿ*þÿ¬68FŠíÿþÿþÿ㇊‹U82’ÿüÿýÿßN7ÈÿüÿÿýÿÔA5;‹:<0Þÿý€ÿM4:ƒ9:6BæÿþÿýÿÜK5:5ÜÿþÿýÿÏ::;2lÿþÿ&ÁU46:ÊÿþÿÿþÿÛo382ŸÿýÿÿþÿÄ6973,ÙÿþÿýÿÊ%5€26;0‘ÿüÿýÿà>šÿýÿÿýÿåJ1<Œ9;/Þÿý€ÿL39„8 :1“ÿüÿÿýÿk,7Zú€ÿ4þÿ—);91kÿþÿþÿóZ*;;,nÿüÿÿûÿ‹';:0VíÿþÿþÿÐ688:3ÚÿþÿýÿÌ-<9:/ÿüÿýÿщùÿþÿþÿ÷f-<8:.Þÿý€ÿL39„8E;-aûÿþÿüÿ¥9)¤ÿþÿþÿóF6891kÿþÿþÿôg2::-eÿþþÿûÿ–1:98=ØÿýÿþÿÍ68892ÚÿþÿýÿÌ,;8:/ÿü€ÿóõƒÿ€/:Ž8:.Þÿý€ÿK28„7E884Âÿüÿþÿê?0Ðÿýÿþÿº27780jÿþÿþÿóc/99/Xñÿþÿûÿ”.9878ÖÿýÿþÿÍ57781ÚÿþÿýÿÌ+:79.ÿûÿþ‚ÿõL38Ž79-Ýÿý€ÿJ17…6:&‡ÿþÿ;`dùÿþÿýÿg.867/iÿþÿþÿób.88.Xòÿþÿûÿ“-8768ÖÿýÿþÿÍ46670ÙÿþÿýÿË*968-Žÿûÿýý€ÿýÿÀ-8768,Ýÿý€ÿI06…5D64Bçÿþÿþÿ¨…ÿûÿýÿÙB1656.hÿþÿþÿóa-77-Wñÿþÿûÿ’,7657ÖÿýÿþÿÍ3556/ÙÿþÿýÿË)857,Žÿû€ÿþÿÿþ€ÿþÿ„*857+Ýÿý€ÿI06†5\7,®ÿþÿþÿëÖÿýÿûÿ•'8556.gÿþÿþÿò`-77-Wñÿþÿûÿ‘+7655ÕÿýÿþÿÌ3556/ÙÿþÿýÿÉ(855657+Œÿûÿÿþÿä±ÿþÿÿþÿïP/6Œ57+Ýÿý€ÿH.4†34-Vÿþ„ÿPþÿðZ+5334,gÿþÿþÿò^+55+Uñÿþÿûÿ‘*5434ÕÿýÿþÿË1334-ÛÿþÿýÿÕ0967135*Œÿûÿþÿûj-ÙÿýÿÿýÿÄ04Œ35)Ýÿý€ÿH.4†3417ÏÿýÿÿþýÿÿýÿÂ$7€3I4,fÿþÿþÿò^+55+Uðÿþÿûÿ)5434ÕÿýÿþÿË1334,ÀÿþÿþÿðR'$:55)ŒÿûÿýÿÛE&jùÿþÿÿýÿŽ'7‹35)Ýÿý€ÿH.4‡36(…ÿû…ÿz*5€3J4,eÿþÿþÿò],55+Tðÿþÿûÿ)5433ÔÿýÿþÿË1334,»ÿþÿÿýÿÕ‚~œÊg.+‹ÿûÿýÿÚE2(©ÿýÿÿþÿïT*6Š35)Ýÿý€ÿF,2‡13)Rëÿýÿþÿé9/1)2*dÿþÿþÿò\)33)Sðÿþÿûÿ'3212ÔÿýÿþÿÊ/112*™ÿý†ÿ{*)ŠÿûÿýÿÚC-0<ßÿþÿÿüÿÈ5‹13'Üÿý€ÿF,2ˆ14'¶ÿûþüÿ˜+21C2*dÿýþýÿð[*33)RîÿýþúÿŽ'3212ÓÿüþýÿÉ/112+M÷ÿýþÿÿüüþûût+)ŠÿúþüÿÙC-5'kÿý€þüÿŽ"3‰13'Üÿý€ÿF,2ˆ1 4&rýÿþÿÿþþÿV'31"2*cÿþÿþÿó_)33(Uóÿþÿûÿ’(3211ÔÿýÿþÿÍ/€12+ƒþÿþ„ÿz*)ŠÿûÿýÿÜE,33(ªÿüÿÿþÿ÷`*3ˆ13'Üÿý€ÿD*0‰/ 0.Íïèééæó¶5.0/"0)\ðèéèìÝV(11(NÛìèéåø%100,Àóçéèï²-€/0-,YÃòý€ÿüöêi*(÷æéçðÇ?+01)BÕîèééæö°&1ˆ/1%Üÿý€ÿC)/Š.-…*-….-ƒ*-.-ƒ*,‚.+‚*+‚./.(%>t‚|oV0+/.,‚*+./,)ƒ*+Š.0$Üÿý€ÿC)/Š.//ƒ./­. //+$""#%)-Œ./’.0$Üÿý€ÿB'.Å-.‚0.£-/#Üÿý€ÿB'.ò-/#Üÿý€ÿA&-ò,."Üÿý€ÿA%,ò+- Ûÿý€ÿ?#*ò)+Ûÿý€ÿ?#*ò)+Ûÿý€ÿ?#*ò)+Ûÿý€ÿ>")ò(*Ûÿý€ÿ=!(ò')Ûÿý€ÿ=!(ò')Ûÿý€ÿ;&ò%'Úÿý€ÿ;&ò%'Úÿý€ÿ:%ò$&Úÿý€ÿ9$ò#%Úÿý€ÿ9$ò#%Úÿý€ÿ:%ò$&Úÿý€ÿ2òÙÿý€ÿO6<ò;=1Þÿý€ÿÓÍôÎÌ÷‚ÿÜ×ôØÖø‚ÿÛÖô×Õø‚ÿÙÔôÕÓø‚ÿùöøþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØÿšŒó‰ìÿþ€ÿ}ò€zêÿþ€ÿ€„òƒ„}êÿþ€ÿŽ~‚ò‚{êÿþ€ÿŽ~‚ò‚{êÿþ€ÿŒ|€ò€yéÿþ€ÿ‹{ò~xéÿþ€ÿŠz~ò}~wéÿþ€ÿ‰y}ò|}uéÿþ€ÿ‰y}ò|}uéÿþ€ÿ‡w{òz{séÿþ€ÿ‡uzòyzrèÿþ€ÿ‡uzòyzrèÿþ€ÿ…sxòwxpèÿþ€ÿ…sxòwxpèÿþ€ÿ„rwòvwoèÿþ€ÿ‚puòtumèÿþ€ÿ‚puòtumèÿþ€ÿ€nsòrskçÿþ€ÿ€nsòrskçÿþ€ÿmròqrjçÿþ€ÿ~lqòpqiçÿþ€ÿ~kpòophçÿþ€ÿ~kpòophçÿþ€ÿ|inòmofæÿþ€ÿ|inòmofæÿþ€ÿzglòkmdæÿþ€ÿyfkòjlcæÿþ€ÿyfkòjlcæÿþ€ÿwdiòhj`æÿþ€ÿwdiòhj`æÿþ€ÿvchògi_åÿþ€ÿvbgòfh^åÿþ€ÿuafÐeg‚hg˜eg]åÿþ€ÿt`eÐd^Y€ZY^e—df\åÿþ€ÿs_dÁcƒfe„c bˆ¤Ÿ Ÿ¥‰_d–ce[åÿþ€ÿr^cÁbV‚U[cƒb cÈÿýÿüÿÊ\c–bdZåÿþ€ÿq]bÀac–ž€œž…^bƒaÅÿýÿüÿË\b–acYäÿþ€ÿp\a¾` a^kñÿþÿþÿÊWbƒ`ÄÿýÿüÿË[a–`bXäÿþ€ÿo[`¿_ ^gìÿúûúÿÁWaƒ_ÄÿýÿüÿÊZ`–_aWäÿþ€ÿnZ_„^ƒ`_…^ƒ`_^^_ƒ`^^_`€^_`ƒ^`_€^`_‚^ __fïÿþÿþÿÃWb€`€^ÃÿýÿüÿÊY_€^_„`‹^`Väÿþ€ÿmY^ƒ]\‚VUW„][‚VUY]]ZU‚V^aXV[\\YU^_]]`]UY€\VZ`] [T_ïÿþÿþÿ¾MX€V€] ÁÿýÿüÿÉW^]]_[U‚VU\Š]_Uäÿþ€ÿmX]‚\[`y|€{}u^‚\ [cz|{{z~m[[j~€{(|y\Oo‘¼ÊÊ­|YW]_R^~­ÈÎÇ–fU^\\[f}~ñÿþÿþÿËs}€{_[\ÁÿýÿüÿÉW]\^Wcz€{|{_Š\^Täÿþ€ÿmX]\]Xpèÿþ€ÿ÷gX]\\_O˜ÿþÿÿþÿªXW£ÿþÿýÿÝ^¦ï‚ÿþÈdYR…Òÿ þÿä…R^]V ÿþˆÿømY\ÀÿýÿüÿÈV^][\Òÿýÿÿþÿê_Š\^Täÿþ€ÿkV[‚Z$\P»ÿûþþýÿ“V[ZZ[U½ÿûþþýÿzUV¤ÿýþþÿðÙÿþý€þ ýýÿÒ^µüÿýý€þ üÿù…R]T¡ÿýƒÿþÿþþÿ÷nWZÀÿýÿüÿÈU[]U¹ÿýþþýþøU[‰Z\Rãÿþ€ÿjUZ‚Y\O‰üÿþÿþÿÑO[YZTmïÿþÿýÿÑ\XT¤ÿþ‚ÿüýþþÿýüöÿþüþþÿûÿÐ\YTÿü„ÿ€ýÿölVYÀÿýÿüÿÈS^N”ÿþÿÿþýÿK[ŠY[Qãÿþ€ÿjUZƒYZWßÿþÿþÿîgXZ[R‰ÿýÿÿüÿšL]S¢ÿþ€ÿþüÿþÿþÿýþ…ÿþÿ{ST¤ÿþˆÿømVY¿ÿýÿüÿÇURtòÿþÿÿþÿ©P[‹Y[Qãÿþ€ÿhSXƒWYO§ÿþÿÿþÿ¡JZWUÈÿþÿþÿèlSYQ¡ÿþ‚ÿôØÖò…ÿøÞÏë‚ÿýÿ‹QVnœ¡÷€ÿþÿÕš˜™˜\VW¾ÿýÿüÿÈOfâÿýÿÿýÿÂUWYOãÿþ€ÿhSX„WTfü€ÿüÿÃMZV^ó€ÿ ýÿÁHZXQ¡ÿþ€ÿ'ù²_RRhêÿþÿÿýÿÐrSTXÅÿýÿÿþÿ¦RXTPWîÿþÿþÿ¹HS€QWWV½ÿýÿüÿÆMÊÿýÿÿýÿÖ\TXŒWYOãÿþ€ÿgRW…V WÃÿýÿþÿñrQP”‚ÿ3üQWWP ÿþÿýÿâNTWWNœÿüÿÿüÿ„DYYI‡ÿÿþÿþÿ°RWWV]îÿþÿþÿ¾NY€WVVU½ÿýÿüÿ¸ÿþÿÿýÿç_QYVXNãÿþ€ÿfQV„UEXJ‡ÿüÿÿüÿŒLKÈÿýÿþÿäTUUVO ÿþÿþÿå\UVWLŒÿüÿÿüÿŽJXVQpíÿþÿþÿ®QVUT[îÿþÿþÿ¼LW‚UT½ÿýÿþÿòô‚ÿötLXŽUWMâÿþ€ÿePU„TEUQaÞÿýÿýÿÌShèÿýÿýÿ˜NUTUNžÿþÿþÿäXTUVJ€ÿýÿÿüÿŒGWUPkêÿþÿþÿ­PUTSZîÿþÿþÿ¼KV‚TS»ÿýÿþ€ÿþÿáTUTVLâÿþ€ÿdNT…SWE³ÿüÿ;Vÿýÿþÿ÷hMTSTMÿþÿþÿäWSTUI~ÿýÿÿüÿ‹FVUNkëÿþÿþÿ¬OTSRYîÿþÿþÿ»JU‚SR»ÿýÿüü€ÿþÿ«GVŽSUJâÿþ€ÿdMS…RSMsôÿþ€ÿ;¯ÿüÿüÿºOSRRSLœÿþÿþÿäURSTH}ÿýÿÿüÿ‹EUSNiêÿþÿþÿ«NSRQXîÿþÿþÿ»IT‚RQºÿý€ÿ þþÿþÿÿþÿøzJURTIâÿþ€ÿcLR†QSG×ÿþ€ÿTåçÿþÿþÿŠDTQQRKœÿþÿþÿäTQRSG|ÿýÿÿüÿŠDTSLhêÿþÿþÿªMRQPWîÿþÿþÿ·ISQQRQQPºÿýÿÿþÿÒÊÿþÿÿýÿÚVORŒQSHâÿþ€ÿbKQ†PQKŒÿþ„ÿPýÿÝSPQPPQJ›ÿþÿþÿãSPQRF|ÿýÿÿüÿŠCSRKgêÿþÿþÿªLQQOYîÿþÿþÿÁEVSSOQPO¹ÿýÿþÿëa_òÿþÿÿýÿ­ISŒPRGâÿþ€ÿbKQ†PQL]óÿþþÿÿþÿ°DS€PAQJšÿþÿþÿãSPQRF|ÿýÿÿüÿŠCSQLféÿþÿýÿ©KQPQKãÿþÿþÿáKBDEUOPO¸ÿýÿüÿ¿HF•ÿýÿü|ES‹PRGâÿþ€ÿ`IO‡NOJ­ÿü„ÿúfKO€NJOHšÿþÿþÿãQNOPDzÿýÿÿüÿˆAQPJeêÿþÿýÿ¨IONOHáÿþÿÿþÿÍ‘±ËYLM¸ÿýÿüÿÃHQMÍÿýÿÿýÿßWLOŠNPEáÿþ€ÿ_HN‡MPB{ÿþþÿþÿÍJ‚M)NG™ÿþÿýÿãPMNOCyÿýÿÿüÿˆ@POIdéÿþÿýÿ§HNMNGËÿþ…ÿøaJL·ÿýÿüÿÂEPHaøÿüÿ³EOŠMODáÿþ€ÿ_HN‡MNMOÑÿûþûÿ…EOMCNG—ÿýþýÿâPMNOCyÿüþþûÿ‡@PNIcèÿýþüÿ¦HNMNG}ÿüþþÿÿüýýþô_JL¶ÿüþûÿÁFOOC›ÿü€þýÿzCO‰MODáÿþ€ÿ]FLˆKO<¢ÿþ€ÿýÿæ]FLK#LE˜ÿþÿýÿâNKLM@yÿýÿÿûÿˆ=NMFcêÿþÿýÿ¨FL€KG¬ÿþ„ÿ÷^HJ·ÿýÿüÿÁDMLKMÍÿýÿÿþÿë^HLˆKMBáÿþ€ÿ]FLˆK LI[àïëììéùŸ?N‚KLLFòëìëóÒMKKMBrñëììêò{@MLH]×ñëìëó˜GLKKLIG×õþÿÿýú÷åWIJªõêìéø´DMKNAqçíëììëõž?NˆKMBáÿþ€ÿ\EKŠJH„FG†JHƒF‚JIƒFIJIƒFH‚JKJDE_Š‘‡{eIIJJG‚FGJKHEƒF‹JLAáÿþ€ÿ[CIŠH†I‡HƒIƒHƒIƒH„I„H IIE?>?@AEIHƒI‚H…I‹HJ?àÿþ€ÿ[CIÆH‚JI£HJ?àÿþ€ÿZBHòGI>àÿþ€ÿYAGòFH=àÿþ€ÿX@FòEG<àÿý€ÿV>DòCE:ßÿý€ÿV>DòCE:ßÿý€ÿU=CòBD9ßÿý€ÿT@4ßÿý€ÿQ8>ò=?3Þÿý€ÿQ8>ò=?3Þÿý€ÿP7=ò<>2Þÿý€ÿO6<ò;=1Þÿý€ÿO6<ò;=1Þÿý€ÿH.4ò35)Ýÿý€ÿ`IOòNPEáÿþ€ÿÎÇóÈÉÅö‚ÿÔÎôÏÍ÷‚ÿÒÌôÍË÷‚ÿÏÉóÊËÇö‚ÿ÷ööýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØÿ´ªó¬­¨ñÿþ€ÿ«Ÿó¡¢œïÿþ€ÿ¬¡ó£¤žðÿþ€ÿ«Ÿó¡¢œïÿþ€ÿ«Ÿó¡¢œïÿþ€ÿ©œóŸ šïÿþ€ÿ©œóŸ šïÿþ€ÿ§šóž˜ïÿþ€ÿ¦™óœ—îÿþ€ÿ¦™óœ—îÿþ€ÿ¤—󚛕îÿþ€ÿ£–󙚔îÿþ€ÿ¢•󘙓îÿþ€ÿ¢”ó—˜’îÿþ€ÿ¡“ó–—‘íÿþ€ÿ ’ó•–íÿþ€ÿŸ‘ó”•íÿþ€ÿžó“”Žíÿþ€ÿœŽó‘’Œíÿþ€ÿœŽó‘’Œíÿþ€ÿ›ó‘Šìÿþ€ÿšŒó‰ìÿþ€ÿ™‹óŽˆìÿþ€ÿ™Šóއìÿþ€ÿ˜‰óŒ†ìÿþ€ÿ—ˆó‹Œ…ëÿþ€ÿ–‡‹òŠ‹„ëÿþ€ÿ•†Šò‰Šƒëÿþ€ÿ”…‰òˆ‰‚ëÿþ€ÿ’ƒ‡ò†‡€ëÿþ€ÿ’ƒ‡ò†‡€ëÿþ€ÿ‘‚†ò…†êÿþ€ÿ…ò„…~êÿþ€ÿ€„Ѓ„‚…„˜ƒ„}êÿþ€ÿƒÐ‚|‚z~ƒ—‚ƒ|êÿþ€ÿŽ~‚À‚ƒƒ‚„ ‚¦²¯°¯²˜}‚–‚{êÿþ€ÿ}À€~ƒv|ƒ€ ~†êÿþÿýÿÆuƒ–€zêÿþ€ÿŒ|€¿~‰­°€¯°}‚ }…èÿþÿýÿÅt‚–€yéÿþ€ÿ‹{¾~y¢ü‚ÿ³y~ |„èÿþÿýÿÄs–~xéÿþ€ÿ‰y}¾|}wŸùý€üþ¯w}| z‚èÿþÿýÿÃp–|}uéÿþ€ÿ‰y}„|ƒ}†|ƒ}|ƒ}||}‚|}ƒ|}||{|}ƒ|}x û‚ÿ°x~€} |z‚çÿþÿýÿÃp€|…}‹|}uéÿþ€ÿ‡w{ƒzyƒtwƒz{xƒtxzzv‚tv{|utxyyvt|{zz}xtwyyxty|zyn˜û‚ÿªouttuzx€çÿþÿýÿÂn}zz{xsƒt‹z{séÿþ€ÿ‡w{‚zy“’•ˆyz{x‚”“•ƒyy‰”€“ ”vsŽªÊÒͳux{{r¾ÐÖË¡|u{zzy‰®ü‚ÿº”“”zx€æÿþÿýÿÂn}z{x…–’“‘‹z{séÿþ€ÿ‡uzy {s•ýÿþÿþÿà|w€y{pºÿýÿÿþÿžuvÐÿþÿþÿÕ{Ä÷‚ÿúÄwuq¦åÿþÿÿþÿÛŽszztÊÿþ†ÿþÿïzwæÿþÿýÿÂm|ztëÿþÿÿþÿØvz‰yzrèÿþ€ÿ…sxwxv{Ûÿü€þÿŽsxwxu€áÿüþýÿð†tsÐÿýþþÿñåÿþý€þýýÿÅ‚Ðÿÿýþ ýÿêŠsyrÍÿþƒÿþÿïxu}æÿþÿýÿÁkzwvÔÿýþþýÿì‰tx‰wxpèÿþ€ÿ…sx‚wzk²ÿþÿÿþÿ½qxwxq“ÿþÿÿüÿÀqysÐÿþ‚ÿýýþÿþþüöÿýýþþÿûÿÀozrËÿýƒÿþýýüÿíxu}æÿþÿýÿÀk{q¿ÿýÿÿþÿõ’oyŠwxpèÿþ€ÿƒqv‚uvs…ðÿþÿþÿæsvuurºÿþÿþÿý™mxqÐÿþ€ÿþýÿþÿþÿýÿþ€ÿþÿó…rpÑÿþˆÿõws{åÿþÿýÿ¿lp¥ÿþÿÿþÿÿŸkx‹uvnèÿþ€ÿƒqvƒuwmÒÿþÿþÿø•pvtuéÿþÿýÿÝsvvqÐÿþÿþñÚàú…ÿößÛó‚ÿþÿot‘¦¾ý‚ÿɤ¨¦ª¢us{åÿþÿýÿÁbõÿþÿÿýÿµnwŒuvnèÿþ€ÿ‚puƒtup—ÿýÿ¿iwpü‚ÿ²kvupÏÿþ€ÿõ¯wqn•øƒÿÊqp{àÿýÿÿþÿ™nurj‘ú‚ÿ£jp€otrzäÿþÿýÿ¼pèÿþÿÿýÿÇqŽtumèÿþ€ÿ€ns„rpuçÿþÿýÿßysiÂÿþ€ÿ+ö{qrsmÎÿþÿþÿ×atsrnÌÿþÿþÿù‹iuve¨ÿüÿÿýÿ mstn—ú‚ÿ¨nt€srpxäÿþÿýÿ»ÂÿýÿÿþÿÚtpsrskçÿþ€ÿ€ns„r=sm°ÿýÿÿþÿ”juàÿýÿþÿÊmrrsmÎÿþÿþÿÛktrsoºÿýÿþÿù’lttjþÿþÿýÿžlssm–ú‚ÿ§msrpxäÿþ€ÿöù€ÿþÿå{nsŽrskçÿþ€ÿmr„q=sj‹øÿþÿýÿ·d—ûÿþÿþÿ”krqrlÎÿþÿþÿÚhsqrj¥ÿýÿþÿùjssišýÿþÿýÿkrrl•ú‚ÿ¦lrqowäÿþÿþ€ÿþÿÇgsqrjçÿþ€ÿ~lq…p CFBundleDevelopmentRegion en CFBundleExecutable vmtk CFBundleGetInfoString @VMTK_VERSION@, Copyright (C) 2004-2009, Luca Antiga, David Steinman CFBundleIdentifier org.vmtk.vmtk CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleShortVersionString @VMTK_VERSION@ CFBundleSignature vmtk CFBundleVersion @VMTK_VERSION@ CFBundleIconFile vmtk.icns LSMinimumSystemVersion 10.5 vmtk-1.0.1/distribution/bundle/CustomVolumeIcon.icns0000664000175000017500000011170311757446472021273 0ustar lucalucaicns“Ãis32½ÿÿý‡ûþ€ÿ öÌäãåæçéëìîíá€ÿä¾ñëíîðñòôö÷ÎüÿÿÞÇñëíïðòóõöúÓøÿÿÖÌòíïñòóõö÷þÕóÿÿÏÓóîðòóõöøùÿÙîÿÿÈÛóðòóõöøúúÿÞèÿÿÃâóòóõöøúûûÿãâÿÿÁéôóõöøúûüüÿéÝÿû¿ïôôö÷ùúûýýÿïÙÿö"Àõõ÷øúûüýþÿÿõÖÿïÀïíïñòóôôõõ÷ñÑÿçÉÿþ†ÿþÓýçÍŸ…º¸ÍÑúçÄ‹ouƒtun¤Ëú÷°¦†¨©£Éÿÿÿý‡ûþ€ÿ öÌäãåæçéëìîíá€ÿä¾ñëíîðñòôö÷ÎüÿÿÞÇñëíïðòóõöúÓøÿÿÖÌòíïñòôõö÷þÕóÿÿÏÓóîðòóõöøùÿÙîÿÿÈÛóðòôõöøúúÿÞèÿÿÃâóòóõöøúûûÿãâÿÿÁéôóõöøúûüüÿéÝÿû¿ïôôöøùûûüýÿïÙÿö"Àõõ÷øúûüýþÿÿõÖÿïÀïíïðòóôôõõ÷ñÑÿçÉÿþ†ÿþÓýçÍŸ…º¸ÍÑúçÄ‹ouƒtun¤Ëú÷°¦†¨©£Éÿÿÿý‡ûþ€ÿ öÌäãåæçéëìîíá€ÿä¾ñëíîðñòôö÷ÎüÿÿÞÇñëíïðòóõöúÓøÿÿÖÌòíïñòôõö÷þÕóÿÿÏÓóîðòóõöøùÿÙîÿÿÈÛóðòóõöøúúÿÞèÿÿÃâóòóõöøúûûÿãâÿÿÁéôóõöøúûüüÿéÝÿû¿ïôôöøùúûüýÿïÙÿö"Àõõ÷øúûüýþÿÿõÖÿïÀïíïðòóôôõõ÷ñÑÿçÉÿþ†ÿþÓýçÍŸ…º¸ÍÑúçÄ‹ouƒtun¤Ëú÷°¦†¨©£Éÿs8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿil32 ì€ÿþ“ÿþ†ÿîè€éêëìíðüƒÿþÿÒ²ÞÜÝÞßàáâãäåæçèêêëìíòãȃÿþÿ«¸ïêì€íîîïððñòóóôôõöùï¯ù„ÿ¦Âîêëëììíîîïðññòòóôõö÷õ²ñÿþÿSý¡Êïêëììíîîïðñòòóôõõöö÷ú´êÿþÿÿþÿõœÒïêìííîîïðññòóôõõöö÷øý¹áÿþÿÿþÿí›Ùîëííîîððññòóôõõöö€ø|ÿ¿ÖÿþÿÿþÿåœàîìíîîððññòóôõõööøøùùÿÆÐÿýÿÿýÿÙŸæïíîïððññòóôôõö÷øøùúúÿÏÆÿþÿÿýÿÏ£êîíïððññòóôôõö÷øøùúûúÿØ¿ÿþÿÿýÿŪíïîððññòóôôõö÷øøùú€û ÿàºÿþÿÿýÿº²ïï€ðñòóôôõö÷øøùúûûüûÿé´þ€ÿþÿ²ºòïðññòóôôõö÷÷øùúûû€üÿð³û‚ÿ3ªÃóïðñòóôôõö÷÷øùúûûüüýýÿ÷³òÿþÿÿý¤Ìóðñòóôôõö÷÷øùúûûüü€ýÿüµëÿþÿÿ÷ Ôôñòóôôõö÷÷øùúûûüüýý€þÿ¹äÿþÿÿîžÛôñóóôõö÷÷øùúúû€ü ýýþþýÿ¿ÙÿþÿÿçŸâõòóôõö÷÷øùúúûûüüýý€þýÿÆÒÿýÿÿÜ¢èõóôõö÷÷øùúúûûüüýýþýÿÎÉÿþÿÿÒ§ìôóôõö÷÷øùú€ûüýýþýýÿ×ÁÿþÿÿÉ­ò÷öøøùúûüüýýþþ…ÿ þÿà½ÿþÿÿ¼³€êëììíî€ïð€ñƒòóñöÞ¶þ€ÿ ¹¼íîîïðñóôõööˆ÷öúè²ú€ÿ¬Ä÷÷øúûýþŒÿ þÿ÷³òÿþú«Ýøõ÷€øù‡úùùøù÷¼éÿþô¿ÕÓ×Ó‹Ô‚Ó ÕÕÔÃåÿþó¹ÎÀk^a` ^§Ô¸âÿþõ¸Ð¶^` bX–Ö¶äÿþýºÄÕÍÄÅ ÄÈÔͱðÿþÿÒ’–˜™‰š™˜—ºý€ÿôß“›œµê€ÿ€ÿþ“ÿþ†ÿîè€éêëìíðüƒÿþÿÒ²ÞÜÝÞßàáâãäåæçèêêëìíòãȃÿþÿ«¸ïêì€íîîïððñòóóôôõöùï¯ù„ÿ ¦Âîêëëììíîîïðñ€ò óôõö÷õ²ñÿþÿSý¡Êïêëììíîîïðñòòóôõõöö÷ú´êÿþÿÿþÿõœÒïêìííîîïðññòóôõõöö÷øý¹áÿþÿÿþÿí›Ùîëííîîððññòóôõõöö€ø|ÿ¿ÖÿþÿÿþÿåœàîìíîîððññòóôõõööøøùùÿÆÐÿýÿÿýÿÙŸæïíîïððññòóôôõö÷øøùúúÿÏÆÿþÿÿýÿÏ£êîíïððññòóôôõö÷øøùúûúÿØ¿ÿþÿÿýÿŪíïîððññòóôôõö÷øøùú€û ÿàºÿþÿÿýÿº²€ïðññòóôôõö÷øøúúûûüûÿé´þ€ÿþÿ²ºòïððñòóôôõö÷øøúúûû€üÿð³û‚ÿ3ªÃóïðñòóôôõö÷÷øúúûûüüýýÿ÷³òÿþÿÿý¤Ìóðñòóóôõö÷÷øùúûûüü€ýÿüµëÿþÿÿ÷ Ôôñòóóôõö÷÷øùúúûüü€ýþþÿ¹äÿþÿÿîžÛôñóóôõö÷÷øùúúûüü€ýþþýÿ¿ÙÿþÿÿçŸâôòóôõö÷÷øùúúûûüüýý€þýÿÆÒÿýÿÿÜ¢èõóôõö÷÷øùúúûûüüýýþýÿÎÉÿþÿÿÒ§ìôóôõö÷÷ø€úûûüýýþýýÿ×ÁÿþÿÿÉ­ò÷öøùùúûüüýýþþ…ÿ þÿà½ÿþÿÿ¼³€êëìííî€ïð€ñƒòóñöÞ¶þ€ÿ ¹¼íîîïðñóôõööˆ÷öúè²ú€ÿ¬Ä÷÷øúûýþŒÿ þÿ÷³òÿþú«Ýøõ÷€øù‡úùùøù÷¼éÿþô¿ÕÓ×Ó‹Ô‚Ó ÕÕÔÃåÿþó¹ÎÀk^a` ^§Ô¸âÿþõ¸Ð¶^` bX–Ö¶äÿþýºÄÕÍÄÅ ÄÈÔͱðÿþÿÒ’–˜™‰š™˜—ºý€ÿôß“›œµê€ÿ€ÿþ“ÿþ†ÿîè€éêëìíðüƒÿþÿÒ²ÞÜÝÞßàáâãäåæçèêêëìíòãȃÿþÿ«¸ïëì€íîîïððñòóóôôõöùï¯ù„ÿ¦Âîêëëììíîîïðñòòóóôõö÷õ²ñÿþÿSý¡Êïêëììíîîïðññòóôõõöö÷ú´êÿþÿÿþÿõœÒïêìííîîïðññòóôõõöö÷øý¹áÿþÿÿþÿí›Ùîëííîîððññòòôõõöö€ø|ÿ¿ÖÿþÿÿþÿåœàîìíîîððññòóôõõööøøùùÿÆÐÿýÿÿýÿÙŸæïíîïððññòóôôõö÷øøùúúÿÏÆÿþÿÿýÿÏ£êîíïððññòóôôõö÷øøùúûúÿØ¿ÿþÿÿýÿŪíîïððññòóôôõö÷øøùú€û#ÿàºÿþÿÿýÿº²ïïððññòóôôõö÷øøùúûûüûÿé´þ€ÿþÿ²ºòïðññòóôôõö÷øøùúûû€üÿð³û‚ÿ3ªÃóïðñòóôôõö÷÷øúúûûüüýüÿ÷³òÿþÿÿý¤Ìóðñòóôôõö÷÷øùúûûüü€ýÿüµëÿþÿÿ÷ Ôôñòóóôõö÷÷øùúúû€ü?ýýþþÿ¹äÿþÿÿîžÛôòóóôõö÷÷øùúúûûüüýýþþýÿ¿ÙÿþÿÿçŸâõòóôõö÷÷øùúúûûüüýý€þýÿÆÒÿýÿÿÜ¢èõóôõö÷÷øùúúûûüüýýþýÿÎÉÿþÿÿÒ§ìôóôõö÷÷øùúûûüüýýþýýÿ×ÁÿþÿÿÉ­ò÷öøùùúûüüýýþþ…ÿ þÿà½ÿþÿÿ¼³€êëììíî€ïð€ñƒòóñöÞ¶þ€ÿ ¹¼íîîïðñóôõööˆ÷öúè²ú€ÿ¬Ä÷÷øúûýþŒÿ þÿ÷³òÿþú«Ýøõ÷€øù‡úùùøù÷¼éÿþô¿ÕÓ×Ó‹Ô‚Ó ÕÕÔÃåÿþó¹ÎÀk^a` ^§Ô¸âÿþõ¸Ð¶^` bX–Ö¶äÿþýºÄÕÍÄÅ ÄÈÔͱðÿþÿÒ’–˜™‰š™˜—ºý€ÿôß“›œµê€ÿl8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿit32Aîÿÿÿÿÿÿÿÿÿÿƒÿã¼±°‹±Ÿ²³´´³³†´·¿â¥ÿ柭ÈÞæå€æç€èé€êëë‚ìí€îïððñòóó‚ôõõö÷÷øøùøùù€úûüûÿÿɤæ¢ÿÖ’´ºÂÕƒÛÜ܂݀Þ߀àá‚âããäå傿çèèéêê‚ëììíîïïðñðøÿàÇŸÖ ÿï…¤«·Ä؂ۀÜÝ€Þ‚ßààá‚âããä€åæçèèé€êëììíîïïð€ñõÿß¾¶“ïŸÿ œ«·Æâè‡ç€è„é‚êëêêëìí„î‚ï€ðƒñ‚ò…ó€ôõõ÷ÿâ¾®¦¦Ÿÿ~¬¹Èåê„éê…ë†ì‚íî†ï‚ð€ñ„ò„óƒôõõöÿæÀ®§Šžÿüwž®ºËçê„é€ê…ë‡ì‚íî…ïð€ñ…ò…óô€õ‚öþëð§†ýÿñv‘ ¯¼Îè„é€ê…ë‡ìíƒî„ïðñ„ò„ó‚ô€õƒöþïÆ²§ˆóÿàt’¢±½Ðƒé€ê‡ë…ì‚í‚î…ïðñ„ò„óôõ„öþóɳ¨‰äÿÑu“£²¾Óêé€ê‡ë…ì‚í‚î„ï‚ðñ„ò„óôõƒö÷öüö͵¨Õÿ À|•¥´ÀÖêééê‡ë…ìí„îƒïð‚ñ…òƒóôõ„ö÷÷üùж©“Åÿ ¯–§µÁÙëééêêˆë…ìíƒî„ïðƒñ„ò‚óô‚õ„ö€÷ûûÕ¸ª™´ÿ¡†˜¨¶ÂÜë€êˆë„ì‚í„îƒïð‚ñ…ò‚óôõ…ö÷úýغ«Ÿ§ÿ ‰šª¸ÄÞëêêˆë„ì‚íƒîƒï‚ð‚ñ…ò‚óô‚õ„ö‚÷ùþݼ­¢™ÿ†Œœ¬¹Æáëêˆë„ìí…î‚ïðƒñ„ò‚ó‚ô‚õ„öƒ÷ùÿá¾®¥‘ÿ}Žž­ºÈäëê‡ë„ìí…î‚ïðƒñ…òóôƒõ„ö‚÷øøùÿæÀ°¦‹œÿüwŸ¯¼Êæˆëƒì‚í…î‚ïð„ñ„òóô„õ„ö÷øÿêñ§‡þ›ÿòv‘¡°½Ìèì‡ë‚ì‚í…îï‚ð„ñ„òóôƒõ„ö÷‚øùÿîÆ²¨ˆõ›ÿãt’£²¾Ïê‡ë‚ì‚í†î€ï‚ð„ñ„òóôƒõ„ö÷‚øùùþòÈ´©‰ç›ÿÔu”¤³¿Ò‡ë‚ì‚í…îïð…ñ„ò€ó‚ô„õ„ö€÷øùþõ̵©ŒØ›ÿÃz•¦´ÁÔì…ëìƒí†î€ï‚ð…ñƒò€óô…õƒö÷ø‚ùýøÏ·ª’É›ÿ²€—¨¶Â×ì„ëìƒí…îïð†ñƒò€ó‚ô„õƒö€÷‚øƒùüûÔ¹«™¸›ÿ£†˜©·ÃÛíƒëìƒí…î€ïƒð„ñ„ò€ó‚ô…õƒö÷÷‚ø„ùüü׺¬žª›ÿ”‰›«¹ÄÝí‚ëìƒí†îïïƒð„ñ„òóó‚ô„õ…ö÷÷‚øƒùúúûþܼ®¢›ÿˆŒœ­ºÆàí‚ëìì„í…î€ïƒð…ñƒòóóƒô„õ„ö÷÷‚øƒù€úûÿྯ¥’›ÿŽž®»Èãìëìì„í…î€ï„ðƒñ„òóóƒô„õ„ö÷ƒøƒùúûÿäÀ°§Œšÿ þx °½Êåìëë€ì†íƒî€ïƒð…ñƒòóóƒô„õƒö÷÷„ø‚ùúûûÿéñ¨‡šÿ ôv’¢±¾Ìçìë€ì…í„î€ïƒð…ñƒòóóƒô„õƒö÷÷ƒøƒù€úûÿíų©ˆ÷™ÿçu“£³¿Ïè€ì†í„î€ïƒð…ñƒòóóƒô„õƒö÷÷„øùú‚ûÿðȵ©‰é™ÿ×t”¥´ÀÐê€ì…í„îïï„ð…ñ‚ò€ó„ô„õ‚ö÷÷„øùúƒûþô˶ªŒÚ™ÿÈz–§¶ÂÓëì†íƒî€ï„ð†ñòóó…ôƒõ‚ö€÷„øùú„ûþ÷ϸª‘Ì™ÿ¶€—¨·ÃÖ†í„î€ï…ð„ñ‚ò€ó„ô„õö÷÷…øùú„ûüþùÒ¹«˜»™ÿ¦…™ª¸ÄÙî…íƒî€ï…ð„ñ‚ò€ó„ô„õö€÷„øùú„ûüüýü×»­­™ÿ—‰›¬ºÆÜî„íƒî€ï„ð…ñ‚ò€ó„ô…õ€ö€÷„ø€ùú†ûüüýýÚ¼®¢ ™ÿŠŒœ­»Çßïƒíƒî€ï…ð„ñ‚òóƒô„õö€÷…øùù‚ú„û‚üþÞ¾°¥“™ÿ‚Ÿ¯¼Èáï‚íƒî€ï†ð„ñò€ó„ô„õö€÷„ø€ù‚ú…û‚üÿãÀ±§Ž™ÿy °¾Êäî‚í‚îï„ð„ñòó„ô„õö÷ƒø€ù‚ú„û„üÿ粨ˆ˜ÿ÷v’¢²¿Ìæîíîï…ð„ñò‚óƒô„õö÷ƒø€ù‚ú…û„üÿëÅ´©ˆù—ÿ êu”¤´ÀÎèîíí‚îï…ð„ñòó…ôƒõö€÷…øùùƒú„û…üÿïȶª‰ì—ÿ Ûu•¦µÂÐêîí‚î‚ï…ðƒñò‚ó„ôƒõ€ö‚÷ƒø€ù‚ú…û…üýÿòË·ª‹Ý—ÿËx–§·ÃÓìƒîï†ðƒñò‚ó„ôƒõ€ö‚÷„øùù‚ú…û…üýýÿöι«Î—ÿº˜©¸ÄÕì‚î‚ï…ðƒñò‚ó„ô‚õö‚÷ƒøùùƒú…û†üýýÿøÑº¬—¾—ÿ©…™«¹ÆØ‚î‚ï†ð‚ñò‚ó„ô‚õö‚÷ƒøùù„ú„û…üýþûÕ»®¯—ÿš‰œ¬»ÇÚï€îï‡ð‚ñò‚ó„ô‚õö‚÷ƒø€ù‚ú…û…ü‚ýþüؽ¯¢¡—ÿŒŒ®¼ÈÝïîƒï„ð„ñò‚ó„ô‚õö‚÷ƒøùù„ú…û…ü‚ýþþÜ¿±¥•—ÿƒŸ°¾Éà„ï…ðƒñò‚ó„ô‚õö‚÷ƒøùù„ú„û†ü„ýÿáÁ²§—ÿ{‘¡±¿Ëãð‚ï…ð‚ñ‚ò‚ó„ô‚õö‚÷ƒøùù„ú„û…ü†ýÿåô©‰–ÿùw“£³ÀÌåðï…ð‚ñ‚ò‚ó„ô‚õöƒ÷‚ø€ùƒú…û…ü…ýþÿéŵª‡ú•ÿív”¤´ÂÎèð€ï…ð‚ñò„óƒô‚õöƒ÷‚øùù„ú…û…ü†ýþÿìȶ«‰ï•ÿ Ýv•¦¶ÃÐêðïï…ð‚ñòƒó…ôõöƒ÷‚øùùƒú†û…ü…ý€þÿñʸ«Šà•ÿ Ïx–¨·ÄÒëðïï…ðñ‚ò‚ó…ôõöƒ÷ƒøù„ú†û„ü†ý€þÿô͹¬Ò•ÿ ¾~˜ª¹ÅÔíðï„ð‚ñò„ó„ôõöƒ÷‚ø€ùƒú…û†ü…ýþÿ÷л­—Á•ÿ¬„š¬ºÇ×î…ð‚ñò„ó„ôõöƒ÷‚øùù…ú„û…ü†ý‚þÿùÔ¼®±•ÿž‰œ­¼ÈÚï„ð‚ñò„óƒô‚õö„÷ø€ù„ú„û†ü…ýƒþÿüؾ°¢¥•ÿŒž¯½ÉÜ„ð‚ñò„ó„ôõöƒ÷‚ø€ù„ú…û…ü†ýƒþÿýÛ¿±¥—•ÿ…Ÿ±¾ËÞñƒðñò„ó„ôõö„÷ø€ù„ú…û…ü†ý…þÿßÁ³¨•ÿ}‘¢²ÀÌáñ‚ðñ‚òƒó„ôõö„÷ø€ù…ú„û…ü…ý‡þÿäÄ´©Š”ÿûx“£´ÂÍäñ€ð‚ñò„ó„ôõö„÷ø€ù„ú…û…ü†ý‡þÿçŶªˆü“ÿ ðw”¥µÃÏæñðð‚ñò„ó„ôõö„÷ø€ù„ú„û†ü†ýˆþÿëÇ·«‰ñ“ÿ áv–§·ÄÑéñð‚ñ‚òƒó„ôõö„÷ø€ù„ú…û…ü…ýŠþÿïʹ¬‹ã“ÿÒx—©¹ÅÒëƒñ‚òƒó„ôõö„÷ø€ù…ú„û…ü†ýŠþÿòͺ­Ô“ÿÁ}™ªºÇÔìòñ‚ò„óƒôõö„÷øù„ú„û…ü‡ýŠþÿõϼ­–Ä“ÿ°ƒ›¬¼ÈÖîò€ñ‚ò„óƒôõ‚öƒ÷øù„ú„û…ü†ýŒþÿøÓ½¯œ´“ÿ ¡ˆœ®½ÉØðòññ‚ò…ó‚ôõ‚öƒ÷‚øùù…ú„û†ü…ýþÿúÖ¾°¢§“ÿ’Œž°¾ËÛññƒò„óƒôõ‚öƒ÷‚øùù…ú…û„ü†ýŽþÿüÚÀ²¥™“ÿ‡ ±ÀÌÞòñ‚ò…ó‚ôõ‚ö„÷ø€ù„ú„û†ü…ý‘þݳ¨‘“ÿ’¢³ÁÍàƒò„óƒôõ‚ö„÷ø€ù„ú…û…ü†ýþÿâõª‹’ÿýx“¤´ÃÎâóò„óƒôõ‚ö„÷ø€ù…ú„û…ü…ý’þÿæÆ·«‡ý‘ÿów•¦¶ÄÐåóòƒóƒôõ‚ö„÷ø€ù„ú…û…ü†ý‘þÿÿéȸ¬‰ô‘ÿ äv–¨¸ÅÑçóòò…ó‚ôõ‚ö„÷ø€ù„ú…û…ü†ý’þÿÿíʹ¬Šå‘ÿ Õw˜©¹ÆÒêóò†óô‚õöƒ÷‚øù„ú„û†ü…ý“þÿÿðÌ»­Ž×‘ÿ Å|™«»ÈÕìóò„ó‚ô‚õö„÷ø€ù…ú„û…ü†ý“þ€ÿôϼ®”È‘ÿ³‚›­¼É×î…ó‚ô‚õö…÷€øù„ú…û„ü‡ý’þÿöÒ¾°›¶‘ÿ¥ˆ¯¾ËØïôƒó‚ô‚õö„÷øù„ú…û„ü…ý”þ‚ÿùÕÀ±¡©‘ÿ•ŒŸ°ÀÌÚñô‚óƒôõ‚ö„÷ø€ù„ú…û…ü…ý“þƒÿûØÁ³¥œ‘ÿ‰¡²ÁÍÝò‚óƒôõö…÷ø€ù„ú„û…ü†ý’þ…ÿýÜô¨’‘ÿ’¢´ÂÎß‚óƒôõ‚öƒ÷‚ø€ù„ú…û…ü†ý’þ†ÿàŶªÿþz”¥µÄÏáôó‚ôõ‚ö„÷ø€ù…ú„û…ü†ý“þ†ÿ䯷«ˆþÿõx•§·ÅÑäô€ó‚ôõ‚ö„÷ø€ù…ú„û…ü†ý“þ‡ÿçȹ¬ˆöÿ èw–¨¹ÆÒçôóƒôõ‚ö„÷ø€ù„ú…û…ü†ý’þÿþ‡ÿëʺ­‹éÿ Øw˜ªºÈÔèôó‚ôõƒöƒ÷øù„ú…û„ü‡ý‘þŠÿî̼®ŽØÿÈ{š¬¼ÉÕëõ‚ôõ‚ö„÷ø€ù„úûú„û„ü†ý“þŠÿòϾ¯“Éþÿ þ¶‚›®½Ê×íõôõ‚ö…÷€ø€ù…ú„û†ü…ý“þ‹ÿõÑ¿°›¹þÿ þ¦ˆ¯¾ËÙñø÷ø‚ù„úû€ü„ý…þ²ÿúÔÀ± ©þÿý–‹®ÀÍÓۊ܄݆Þ݌ޟßÞ‰ß ÞÞßâçÓ¿°£œýþ‹ÿ þýˆ‹¡½ÄÄÈÐÐσЂф҄ÓÔÓ‚ÔƒÕւׂ؅قچÛÜØÍ¾±¤‘üþ‹ÿ þü~™º·»ÊÚïôó€ôõõ€ö÷øùù€ú€û€üýý€þ¸ÿýÑ·¶©Šûþ‹ÿþû}²¥±ÅÑßñôõõôõööõöö÷÷ø÷€øùúúùúúûüüûüýüýýþþÿþºÿäÁ®±ˆûý‹ÿ ý󎙤ºÇÒàòôõöö÷øøùúúûüýýþºÿè˵§óý‹ÿ ýå‚“¬¼ÉÓâó€ôõöö÷øøùúúûüýýþ»ÿëͽ¨ŒåüþŠÿü×u›­½ÊÕä€ôõöö÷øø‚ùúûüýýþ¼ÿïο¯‡Öüþ‰ÿ þûÉx¯¾ËÖæõôõöö÷€øùúúûüýþ½ÿòÑÀ²ŽÊûþ‰ÿ þú¶€Ÿ±ÀÌ×è‚õöö‚÷øøùúúûüýýþ½ÿôÓ³˜¸úý‰ÿ ýù¥‡ ²ÁÍ×êö€õöö‚÷øøùúúû€üýý€þÀÿøÖõŸ¨ùý‰ÿ ýø—Œ¢³ÃÓàîƒôõöõ‚ö‚÷ƒø‡ù‡ú®ûýùÚĶ¥œøý‰ÿ ü÷Š¥½Óäñú‚ûÆüû úõïãθ©öü‰ÿüö•´Ïàìüßÿ ýïèÝÇ®‰õûþ‡ÿ þûõx¨ÈÛæéé„è‰éêƒé¥êƒéê‰é„è éèæÞÒ½…óûþ‡ÿ þûï~½ÓÝØÑÍ’ÌµÍ’Ì ÍÑØÜÒĉïúþ‡ÿþúåˆÅÓÑÌÌáÍÌÌÑÒÅŒäùþ‡ÿþùãˆÆÎÌÌ…ÍÎÎÏÏËÎÏÏÎÎ…ÍÌÌÎÆ‡ãøý‡ÿýøê~Á‡ÌÐÑËÈÍÉÈÊÏÑ͆ÌÁ~é÷ý‡ÿý÷ì|»†Ìе‚hdÍedfx§ÎÍ…Ì»}êöý‡ÿýöë}¸Ë̓ÌТPDÑGDH‰ÎÍ‚ÌÍ˸}éõü‡ÿýöꀳÉÍ‚ÌÏ¿UGÓLJG§Ñ‚ÌÍɳ€èõü‡ÿýö鉮ÈÌ‚ËÒžDLKÓLC~Ò‚ËÌÈ®ˆçôü‡ÿýöê‘§ÇÌ‚ËÒ›DNQSÏUTRNDzÒ‚ËÌǧ‘èõü‡ÿýö랟ÅË€ÊËËϹQYdjÏlkf]JÒËË€ÊËÅŸ›éõý‡ÿý÷ì«—Ä˃ÊÒ•fy~Ð{k}ÍË‚ÊËÄ—©êöý‡ÿþøí·ŒÂ˃ÊËÓª„Ð}|€Î̓ÊË·ë÷ý‡ÿþùîËÃË…ÊÔÌ·Ï­²ÆÕÍɃÊËÀÊìøý‡ÿþùïàr¼ÌÉɃÊÉÌÑÓ¡Ô…Ó¢ÔÒ΄ÊÉÉ̼qÞîøþ‡ÿþúðâ©~ËÍ„ÉÊÊÑÉÊ…ÉÍË~§ßïùþ‡ÿ þûòäуƒÆÎË“Ê³Ë“Ê ÌÎÆ‚Îâðúþˆÿ ûóæÔ½€h¤ÂÊË•Ì«Í•Ì Ëɤh}»Òåòûþˆÿ üõêÙÄ®‘a^v‡ÛŒ ‡v]`¬Á×èôü‰ÿ ýøîà͸¥–‡uheÙd ehu†”£µÊÝì÷ý‰ÿ þúòæÖIJ¢–Šˆ††Õ… ††‡ŠŽ•¡¯ÁÔåñùý‰ÿ þüöîáÑÁ²¥œ–“‘× ‘“–›¤°¿ÏßìöûþŠÿ ýúôëßÒĸ¯¨£¡ ÕŸ  ¡£§®·ÂÐÝêóùýþŠÿ þüùóëá×ÍĽ¹¶´Õ³ ´µ¸¼ÃËÕàêòøüþŒÿ þüùôîçßÙÓÏÍÌÖË ÍÏÓØÞæíóøüþŽÿ þüú÷òîéåâáàÕß àáâåéíòöúüþ‹ÿÿÿÿÿÿÿÿÿÿÿƒÿã¼±°‹±Ÿ²³´´³³†´·¿â¥ÿ柭ÈÞæå€æç€èé€êëë‚ìí€îïððñòóó‚ôõõö÷÷øøùøùù€úûüûÿÿɤæ¢ÿÖ’´ºÂÕƒÛÜ܂݀Þ߀àá‚âããäå傿çèèéêê‚ëììíîïïðñðøÿàÇŸÖ ÿï…¤«·Ä؂ۀÜÝ€Þ‚ßààá‚âããä€åæçèèé€êëììíîïïð€ñõÿß¾¶“ïŸÿ œ«·Æâè…çèç€èƒéêéêëêêëì€íîíƒî‚ï€ðƒñ„ò‚óôõõ÷ÿâ¾®¦¦Ÿÿ~¬¹Èåêéêééê…ë†ìƒí€î…ïƒð€ñ„ò„ó‚ô€õöÿæÀ®§Šžÿüwž®ºËçê„é€ê†ë†ì‚íî„ï‚ðñ„ò„ó‚ô€õ‚öþëð§†ýÿñv‘ ¯¼Îè„é€ê†ë†ìíî†ïðñ„ò„ó‚ô€õƒöþïÆ²§ˆóÿàt’¢±½Ð„éêê‡ë…ì‚í‚î„ï‚ðñ„ò…ó€ôõ„öþóɳ¨‰äÿÑu“£²¾Óêé€ê‡ë…ì‚í‚î„ï‚ðñ„ò„óô€õ…ö÷üö͵¨ÕÿÀ|•¥´ÀÖê€é€êˆë„ìíƒî„ïð‚ñ…òƒóôõ„ö÷÷üùж©“Åÿ¯–§µÁÙëé€êˆë…ìíƒî„ïð‚ñ„òƒóô‚õƒö÷ûûÕ¸ª™´ÿ¡†˜¨¶ÂÜëé€êˆëƒì‚í„îƒïðƒñƒòƒóô‚õƒö‚÷úýغ«Ÿ§ÿ ‰šª¸ÄÞëêê‰ëƒì‚í„î‚ï‚ðƒñ„ò‚óô‚õ„ö‚÷ùþݼ­¢™ÿ†Œœ¬¹Æáëê‰ëƒìí…î‚ïð„ñƒò‚ó‚ô‚õ„öƒ÷ùÿá¾®¥‘ÿ}Žž­ºÈä‰ë„ìí…î‚ïðƒñ…òóô„õƒö‚÷øøùÿæÀ°¦‹œÿüwŸ¯¼Êæì‡ëƒì‚í…î‚ïðƒñ†ò€óôƒõ…ö÷€øùÿêñ§‡þ›ÿòv‘¡°½Íè‡ëƒì‚í…îï‚ðƒñ…òóôƒõ…ö€÷‚øùÿîÆ²¨ˆõ›ÿãt’£²¾Ïêì†ë‚ì‚í„î‚ï‚ðƒñ…òóôƒõ…ö€÷ø€ùþòÈ´©‰ç›ÿÔu”¤³¿Ò‡ë‚ì‚í…îï‚ð„ñ„ò€ó‚ô„õƒö÷øùþõ̵©ŒØ›ÿÃz•¦´ÁÔì…ëìƒí…îïð…ñ„ò€óô„õ„ö÷ø‚ùýøÏ·ª’É›ÿ²€—¨¶Â×ì„ëìƒí…î€ïƒð„ñ…òóó‚ô„õ„ö÷÷‚øƒùüûÔ¹«™¸›ÿ£†˜©·ÃÛíƒëìƒí†îïïƒð„ñ„ò€óô…õ„ö÷÷‚ø„ùüü׺¬žª›ÿ”‰›«¹ÄÝíƒë€ìƒí…î€ïƒð„ñ„òóóƒô„õƒö€÷‚ø„ùúûþܼ®¢›ÿˆŒœ­ºÆàíë€ì„í…î€ïƒð„ñ„òóóƒô„õƒö€÷‚øƒù€úûÿྯ¥’›ÿŽž®»Èãì€ë€ì…í„î€ïƒð…ñƒòóóƒô„õƒö÷÷„ø‚ùúûÿäÀ°§Œšÿþx °½Êåì€ëìì„í…î€ïƒð…ñƒòóóƒô…õƒö÷ƒøƒùúûûÿéñ¨‡šÿ ôv’¢±¾Ìçìë€ì„í…îïï…ð„ñƒòóóƒô…õ‚ö÷÷ƒøƒù€úûÿíų©ˆ÷™ÿçu“£³¿Ïèì…í„îïï„ð…ñ‚ò€ó„ôƒõöõö÷÷ƒø‚ùú‚ûÿðȵ©‰é™ÿ ×t”¥´ÀÐêìì‡íƒîïï„ð…ñ‚ò€ó„ôƒõƒö÷÷„øùúƒûþô˶ªŒÚ™ÿÈz–§¶ÂÓìì†í„îïï„ð…ñ‚ò€ó„ôƒõ‚ö€÷…ø€ùú„ûþ÷ϸª‘Ì™ÿ¶€—¨·ÃÖ‡íƒî€ï…ð…ñò€ó„ô„õö€÷„øùú…ûþùÒ¹«˜»™ÿ¦…™ª¸ÄÙî…íƒî€ï…ð„ñ‚ò€óƒô…õö€÷„øùú„ûüüýü×»­­™ÿ—‰›¬ºÆÜî„íƒî€ï…ð…ñò€ó„ô„õö€÷„ø€ù‚ú„û€üýýÚ¼®¢ ™ÿŠŒœ­»Çßïƒíƒî€ï…ð„ñ‚ò€ó„ô„õö€÷…øùù‚ú„û‚üþÞ¾°¥“™ÿ‚Ÿ¯¼Èáïƒí‚îï„ð„ñ‚ò€ó„ô„õö€÷„ø€ù‚ú„ûƒüÿãÀ±§Ž™ÿy °¾Êäîíƒî€ï†ðƒñòó…ôƒõö€÷…øùù‚ú„û„üÿ粨ˆ˜ÿ÷v’¢²¿Ìæî€í‚î‚ï„ð„ñòó…ôƒõö€÷…øùù‚ú…û„üÿëÅ´©ˆù—ÿêu”¤´ÀÎèî€íîï…ð„ñò‚ó„ôƒõö÷ƒø€ù‚ú…û…üÿïȶª‰ì—ÿ Ûu•¦µÂÐêîí‚î‚ï…ðƒñò‚óƒô„õ€ö÷…øùùƒú„û…üýÿòË·ª‹Ý—ÿËx–§·ÃÓìƒî‚ï…ðƒñòó…ôƒõ€ö‚÷ƒø€ù‚ú†û„üýýÿöι«Î—ÿº˜©¸ÄÕí‚î‚ï…ðƒñò‚ó„ô‚õö‚÷ƒø€ùƒú„û…ü€ýÿøÑº¬—¾—ÿ©…™«¹ÆØ‚î‚ï…ðƒñòó…ô‚õö‚÷„øù„ú…û„üýþûÕ»®¯—ÿš‰œ¬»ÇÚï€î‚ï…ðƒñò‚ó„ô‚õö‚÷ƒøùù„ú„û…ü‚ýþüؽ¯¢¡—ÿ ŒŒ®¼ÈÝïîî‚ï…ðƒñò‚ó„ô‚õö‚÷ƒøùù„ú„û†üƒýþÜ¿±¥•—ÿƒŸ°¾Éà„ï…ðƒñòƒó„ôõöƒ÷‚ø€ùƒú„û‡üƒýÿáÁ²§—ÿ{‘¡±¿Ëãð‚ï…ð‚ñ‚ò‚ó„ô‚õöƒ÷‚øùù…úƒû†ü„ýþÿåô©‰–ÿùw“£³ÀÌåðï†ðñ‚ò‚ó„ô‚õö‚÷ƒøùù„ú…û„ü†ýþÿéŵª‡ú•ÿív”¤´ÂÎçð€ï†ðñ‚ò‚ó…ôõöƒ÷‚øùù„ú„û†ü…ýþþÿìȶ«‰ï•ÿÝv•¦¶ÃÐêð€ï„ð‚ñò„ó„ôõöƒ÷‚ø€ùƒú…û„ü‡ýþþÿñʸ«Šà•ÿ Ïx–¨·ÄÒëðï†ðñò„ó„ôõöƒ÷‚øùù…ú„û…ü†ý€þÿô͹¬Ò•ÿ ¾~˜ª¹ÅÔíðï…ðñ‚òƒó„ôõöƒ÷‚øùù„ú…û†ü…ýþÿ÷л­—Á•ÿ¬„š¬ºÇ×î…ð‚ñò„ó„ôõö„÷ø€ùƒú…û†ü…ý‚þÿùÔ¼®±•ÿž‰œ­¼ÈÙï…ðñ‚òƒó„ôõöƒ÷‚ø€ù„ú…û…ü…ýƒþÿüؾ°¢¥•ÿŒž¯½ÉÜ„ð‚ñò„ó„ôõöƒ÷‚ø€ù„ú†û„ü…ý„þÿýÛ¿±¥—•ÿ…Ÿ±¾Ëßñ‚ð‚ñò…óƒôõö„÷ø€ù„ú…û…ü†ý…þÿßÁ³¨•ÿ}‘¢²ÀÌáñð‚ñò„ó„ôõö„÷ø€ù„ú„û†ü…ý‡þÿäÄ´©Š”ÿûx“£´ÂÍäñ€ð‚ñò„ó„ôõö„÷ø€ù„ú…û…ü…ýˆþÿçŶªˆü“ÿ ðw”¥µÃÏæñðð‚ñ‚òƒó„ôõöƒ÷‚ø€ù„ú…û„ü‡ýˆþÿëÇ·«‰ñ“ÿ áv–§·ÄÑéñð‚ñ‚ò…ó‚ôõö„÷ø€ù…ú„û…ü†ý‰þÿïʹ¬‹ã“ÿ Òx—©¹ÅÒëñðñ‚ò„óƒôõö„÷ø€ù…ú…û„ü†ýŠþÿòͺ­Ô“ÿÁ}™ªºÇÔìòñò…óƒôõö„÷ø€ù…ú…û…ü„ýŒþÿõϼ­–Ä“ÿ°ƒ›¬¼ÈÖîò€ñò…óƒôõ‚öƒ÷ø€ù…ú…û„ü†ýŒþÿøÓ½¯œ´“ÿ ¡ˆœ®½ÉØðòññ‚ò„óƒôõ‚ö„÷ø€ù„ú„û…ü†ýþÿúÖ¾°¢§“ÿ’Œž°¾ËÛññƒò„óƒôõ‚öƒ÷‚ø€ùƒú†û…ü…ýŽþÿüÚÀ²¥™“ÿ‡ ±ÀÌÞññ‚ò„óƒôõ‚ö„÷ø€ùƒú…û†ü†ýŽþÿþݳ¨‘“ÿ’¢³ÁÍàƒò„óƒôõ‚öƒ÷‚ø€ù„ú„û†ü„ý’þÿâõª‹’ÿýx“¤´ÃÎâó‚òƒóƒôõ‚öƒ÷‚ø€ù…ú„û…ü†ý‘þÿæÆ·«‡ý‘ÿów•¦¶ÄÐåó€ò„óƒôõ‚ö„÷ø€ù„ú…û†ü„ý“þÿéȸ¬‰ô‘ÿäv–¨¸ÅÑçó€ò„ó‚ôõ‚ö„÷ø€ù„ú†û„ü†ý“þÿíʹ¬Šå‘ÿ Õw˜©¹ÆÒêóò…ó‚ô‚õö„÷ø€ù„ú…û…ü†ý‘þ ÿþÿÿðÌ»­Ž×‘ÿ Å|™«»ÈÕìóò„ó‚ô‚õö„÷øù„ú„û…ü‡ý’þ€ÿôϼ®”È‘ÿ³‚›­¼É×í†óô‚õ‚öƒ÷ø€ù…ú„û…ü†ý“þÿöÒ¾°›¶‘ÿ¥ˆ¯¾ËØï„ó‚ô‚õö„÷ø€ù…ú…û„ü†ý“þ‚ÿùÕÀ±¡©‘ÿ•ŒŸ°ÀÌÚñô‚óƒôõö„÷‚ø€ù„ú…û…ü…ý“þƒÿûØÁ³¥œ‘ÿ‰¡²ÁÍÝò‚óƒôõ‚öƒ÷‚ø€ù„ú…û…ü…ý”þƒÿýÜô¨’‘ÿ’¢´ÂÎ߃ó‚ôõ‚ö„÷ø€ù…ú„û…ü†ý’þ†ÿàŶªÿþz”¥µÄÏáôó‚ôõ‚ö„÷ø€ù…ú„û…ü†ý“þ†ÿ䯷«ˆþÿõx•§·ÅÑäô€ó‚ôõ‚ö„÷ø€ù…ú„û…ü†ý’þˆÿçȹ¬ˆöÿ èw–¨¹ÆÒçôóó‚ôõ‚ö„÷øù„ú…û„ü†ý“þˆÿëʺ­‹éÿ Øw˜ªºÈÔèôó‚ôõ‚ö„÷øù„ú„û…ü†ý’þŠÿî̼®ŽØÿÈ{š¬¼ÉÕëõ‚ôõƒöƒ÷ø€ù…úƒûüû…ü…ý“þŠÿòϾ¯“Éþÿ þ¶‚›®½Ê×íõôõ‚ö„÷ø€ù…ú„û†ü…ý“þ‹ÿõÑ¿°›¹þÿ þ¦ˆ¯¾ËÙñø÷ø‚ùƒú‚û€ü„ý„þ³ÿúÔÀ± ©þÿý–‹®ÀÍÓÛŠÜ„ÝÞÝ‚Þ݆ÞßÞßÞ­ß ÞÞßâçÓ¿°£œýþ‹ÿ þýˆ‹¡½ÄÄÈÐÐσЂф҄ÓÔÓ‚ÔƒÕւׂ؅قچÛÜØÍ¾±¤‘üþ‹ÿ þü~™º·»ÊÚïôó€ôõõ€ö÷øùù€ú€û€üýý€þ¸ÿýÑ·¶©Šûþ‹ÿþû}²¥±ÅÑßñôõõôõööõöö÷÷ø÷€øùúúùúúûüüûüýüýýþþÿþºÿäÁ®±ˆûý‹ÿ ý󎙤ºÇÒàòôõöö÷øøùúúûüýýþºÿè˵§óý‹ÿ ýå‚“¬¼ÉÓâó€ôõöö÷øøùúúûüýýþ»ÿëͽ¨ŒåüþŠÿü×u›­½ÊÕä€ôõöö÷øø‚ùúûüýýþ¼ÿïο¯‡Öüþ‰ÿ þûÉx¯¾ËÖæõôõöö÷€øùúúûüýþ½ÿòÑÀ²ŽÊûþ‰ÿ þú¶€Ÿ±ÀÌ×è‚õöö‚÷øøùúúûüýýþ½ÿôÓ³˜¸úý‰ÿ ýù¥‡ ²ÁÍ×êö€õöö‚÷øøùúúû€üýý€þÀÿøÖõŸ¨ùý‰ÿ ýø—Œ¢³ÃÓàîƒôõöõ‚ö‚÷ƒø‡ù‡ú®ûýùÚĶ¥œøý‰ÿ ü÷Š¥½Óäñú‚ûÆüû úõïãθ©öü‰ÿüö•´Ïàìüßÿ ýïèÝÇ®‰õûþ‡ÿ þûõx¨ÈÛæéé„è‰éêƒé¥êƒéê‰é„è éèæÞÒ½…óûþ‡ÿ þûï~½ÓÝØÑÍ’ÌµÍ’Ì ÍÑØÜÒĉïúþ‡ÿþúåˆÅÓÑÌÌáÍÌÌÑÒÅŒäùþ‡ÿþùãˆÆÎÌÌ…ÍÎÎÏÏËÎÏÏÎÎ…ÍÌÌÎÆ‡ãøý‡ÿýøê~Á‡ÌÐÑËÈÍÉÈÊÏÑ͆ÌÁ~é÷ý‡ÿý÷ì|»†Ìе‚hdÍedfx§ÎÍ…Ì»}êöý‡ÿýöë}¸Ë̓ÌТPDÑGDH‰ÎÍ‚ÌÍ˸}éõü‡ÿýöꀳÉÍ‚ÌÏ¿UGÓLJG§Ñ‚ÌÍɳ€èõü‡ÿýö鉮ÈÌ‚ËÒžDLKÓLC~Ò‚ËÌÈ®ˆçôü‡ÿýöê‘§ÇÌ‚ËÒ›DNQSÏUTRNDzÒ‚ËÌǧ‘èõü‡ÿýö랟ÅË€ÊËËϹQYdjÏlkf]JÒËË€ÊËÅŸ›éõý‡ÿý÷ì«—Ä˃ÊÒ•fy~Ð{k}ÍË‚ÊËÄ—©êöý‡ÿþøí·ŒÂ˃ÊËÓª„Ð}|€Î̓ÊË·ë÷ý‡ÿþùîËÃË…ÊÔÌ·Ï­²ÆÕÍɃÊËÀÊìøý‡ÿþùïàr¼ÌÉɃÊÉÌÑÓ¡Ô…Ó¢ÔÒ΄ÊÉÉ̼qÞîøþ‡ÿþúðâ©~ËÍ„ÉÊÊÑÉÊ…ÉÍË~§ßïùþ‡ÿ þûòäуƒÆÎË“Ê³Ë“Ê ÌÎÆ‚Îâðúþˆÿ ûóæÔ½€h¤ÂÊË•Ì«Í•Ì Ëɤh}»Òåòûþˆÿ üõêÙÄ®‘a^v‡ÛŒ ‡v]`¬Á×èôü‰ÿ ýøîà͸¥–‡uheÙd ehu†”£µÊÝì÷ý‰ÿ þúòæÖIJ¢–Šˆ††Õ… ††‡ŠŽ•¡¯ÁÔåñùý‰ÿ þüöîáÑÁ²¥œ–“‘× ‘“–›¤°¿ÏßìöûþŠÿ ýúôëßÒĸ¯¨£¡ ÕŸ  ¡£§®·ÂÐÝêóùýþŠÿ þüùóëá×ÍĽ¹¶´Õ³ ´µ¸¼ÃËÕàêòøüþŒÿ þüùôîçßÙÓÏÍÌÖË ÍÏÓØÞæíóøüþŽÿ þüú÷òîéåâáàÕß àáâåéíòöúüþ‹ÿÿÿÿÿÿÿÿÿÿÿƒÿã¼±°‹±Ÿ²³´´³³†´·¿â¥ÿ柭ÈÞæå€æç€èé€êëë‚ìí€îïððñòóó‚ôõõö÷÷øøùøùù€úûüûÿÿɤæ¢ÿÖ’´ºÂÕƒÛÜ܂݀Þ߀àá‚âããäå傿çèèéêê‚ëììíîïïðñðøÿàÇŸÖ ÿï…¤«·Ä؂ۀÜÝ€Þ‚ßààá‚âããä€åæçèèé€êëììíîïïð€ñõÿß¾¶“ïŸÿ œ«·Æâè†çèƒéƒêë€ê€ëìí„î‚ï€ðƒñ‚òóò„ó ôôõõ÷ÿâ¾®¦¦Ÿÿ~¬¹Èåêƒé‚ê…ë…ìíì‚í€î†ï‚ð€ñƒò…óƒôõõöÿæÀ®§Šžÿüwž®ºËçêƒéê…ë‡ì‚íî„ï‚ðñ„ò„ó‚ôõõƒöþëð§†ýÿñv‘ ¯¼Îè„é€ê†ë†ìí‚î…ïðñ„ò„ó‚ôõõ„öþïÆ²§ˆóÿàt’¢±½Ð„éêê†ë†ì‚í‚î…ïðñ„ò„óôõ„öýóɳ¨‰äÿÑu“£²¾Óêé€ê‡ë…ì‚í‚î„ï‚ðñ…òƒóôõƒö÷÷üö͵¨ÕÿÀ|•¥´ÀÖê€é€ê†ë†ìíƒî„ïð‚ñ„òƒó‚ôõ„ö÷÷üùж©“Åÿ ¯–§µÁÙëééêêˆë…ìí„îƒïð‚ñ„òƒóô‚õ„ö€÷ûûÕ¸ª™´ÿ ¡†˜¨¶ÂÜëéêêˆë„ì‚í„îƒïðƒñ„ò‚óôƒõ„ö€÷úýغ«Ÿ§ÿ ‰šª¸ÄÞëêêˆë„ì‚í„î‚ï‚ðƒñƒòƒóô‚õ„ö‚÷ùþݼ­¢™ÿ †Œœ¬¹Æáëêê‡ë„ìí…î‚ïð„ñ„òó‚ôõ…öƒ÷ùÿá¾®¥‘ÿ }Žž­ºÈäìëê†ë„ìí…î‚ïð„ñ„òóôƒõ…ö÷øøùÿæÀ°¦‹œÿüwŸ¯¼Êæìˆë‚ì‚í…î‚ïð„ñ„òóôƒõ„ö‚÷€øùÿêñ§‡þ›ÿòv‘¡°½Íèìˆëì‚í†î€ï‚ð„ñ„òóôƒõ…ö€÷‚øùÿîÆ²¨ˆõ›ÿãt’£²¾Ïê†ëƒì‚í…îï‚ð„ñ…ò€óô„õ„ö€÷ø€ùþòÈ´©‰ç›ÿÔu”¤³¿Ò‡ë‚ì‚í…îï‚ð„ñ„ò€óô…õ„ö€÷øùþõ̵©ŒØ›ÿÃz•¦´ÁÔì‡ëììƒí†î€ï‚ð„ñ„ò€ó‚ô„õƒö÷ø‚ùýøÏ·ª’É›ÿ²€—¨¶ÂØì„ëìƒí…î€ïƒð„ñ„ò€ó‚ô„õ„ö÷÷‚øƒùüûÔ¹«™¸›ÿ£†˜©·ÃÛíƒëìƒí†îïïƒð„ñ„ò€ó‚ô„õ„ö÷÷ƒøƒùüü׺¬žª›ÿ”‰›«¹ÄÝí‚ëìƒí†îïïƒð„ñ…òóƒô„õƒö€÷‚øƒùúúûþܼ®¢›ÿˆŒœ­ºÆàí‚ëìì„í…î€ïƒð…ñƒòóóƒô„õƒö€÷ƒø‚ù€úûÿྯ¥’›ÿŽž®»Èãì€ë€ì„í…î€ïƒð„ñ„òóóƒô„õƒö÷÷ƒøƒùúûÿäÀ°§Œšÿ þx °½Êåìëë€ì„í…î€ïƒð…ñƒòóóƒô„õƒö÷÷„ø‚ùúûûÿéñ¨‡šÿ ôv’¢±¾Ìçìë€ì„í…îïï„ð…ñƒòóóƒô…õ‚ö÷÷„øùúûÿíų©ˆ÷™ÿçu“£³¿Ïèì†íƒîïï„ð…ñ‚ò€óƒô„õƒö÷÷ƒø‚ùú‚ûÿðȵ©‰é™ÿ ×t”¥´ÀÐêìì†í„îïï…ð…ñòóó…ô„õ‚ö÷÷„øùúƒûþô˶ªŒÚ™ÿÈz–§¶ÂÓìì†íƒî€ï…ð„ñ‚ò€ó„ô„õö€÷„øùú„ûþ÷ϸª‘Ì™ÿ¶€—¨·ÃÖ‡íƒî€ï…ð„ñ‚ò€ó„ôƒõ‚ö€÷…ø€ùú„ûüþùÒ¹«˜»™ÿ¦…™ª¸ÄÙî…íƒî€ï…ð„ñ‚òóó…ô„õö€÷„øùú„ûüüýü×»­­™ÿ—‰›¬ºÆÜî„íƒî€ï„ð…ñ‚ò€ó„ô„õö€÷„ø€ù‚ú…ûüüýýÚ¼®¢ ™ÿŠŒœ­»ÇÞïƒíƒî€ï…ð„ñ‚ò€ó„ô„õö€÷…øùù‚ú…ûüþÞ¾°¥“™ÿ‚Ÿ¯¼Èáïƒí‚îï„ð„ñ‚ò€ó„ôƒõ‚ö÷ƒø€ù‚ú„ûƒüÿãÀ±§Ž™ÿy °¾Êäîíƒî€ï…ð„ñòó…ôƒõö÷„øùùƒúƒû„üÿ粨ˆ˜ÿ÷v’¢²¿Ìæîíîï…ð„ñòó„ô„õö÷ƒø€ù‚ú„û…üÿëÅ´©ˆù—ÿ êu”¤´ÀÎèîíí‚î‚ï„ð„ñò‚ó„ô‚õ‚ö÷ƒø€ù‚ú…û…üÿïȶª‰ì—ÿ Ûu•¦µÂÐêîííî‚ï„ð„ñò‚ó„ô‚õ‚ö€÷„ø€ù‚ú„û†üýÿòË·ª‹Ý—ÿËx–§·ÃÓìƒî‚ï…ðƒñò‚ó„ôƒõ€ö‚÷ƒø€ù‚ú…û…üýýÿöι«Î—ÿº˜©¸ÄÕí‚î‚ï…ðƒñò‚ó…ôõö÷„øùù„ú„û…ü€ýÿøÑº¬—¾—ÿ©…™«¹ÆØ‚î‚ï…ðƒñò‚ó„ô‚õö‚÷ƒøùù„ú„û…üýþûÕ»®¯—ÿš‰œ¬»ÇÚï€îï†ðƒñò‚óƒôƒõö‚÷ƒø€ùƒú„û…ü‚ýþüؽ¯¢¡—ÿ ŒŒ®¼ÈÝïîî‚ï„ðñð‚ñò‚ó„ô‚õöƒ÷‚øùù„ú…û…ü‚ýþþÜ¿±¥•—ÿƒŸ°¾Éà„ï…ð‚ñ‚ò‚ó„ô‚õö‚÷„øùùƒú…û„üýüƒýÿáÁ²§—ÿ{‘¡±¿Ëâðƒï„ð‚ñ‚òƒó„ôõöƒ÷‚øùù„ú†û„ü…ýÿåô©‰–ÿùw“£³ÀÌåð‚ï„ð‚ñ‚ò‚ó„ô‚õö‚÷ƒøùù„ú„û†ü…ýþÿéŵª‡ú•ÿív”¤´ÂÎèð€ï†ðñ‚òƒó„ôõöƒ÷‚ø€ùƒú…û†ü„ýþþÿìȶ«‰ï•ÿÝv•¦¶ÃÐêð€ï„ð‚ñò„ó„ôõö‚÷ƒøùù…ú„û…ü…ý€þÿñʸ«Šà•ÿ Ïx–¨·ÄÒëðïï…ðñòƒó…ôõöƒ÷‚øùù„ú…û…ü…ýþÿô͹¬Ò•ÿ ¾~˜ª¹ÅÔíðï…ðñò„ó„ôõöƒ÷‚øùù…ú„û…ü†ýþÿ÷л­—Á•ÿ¬„š¬ºÇ×î†ðñò„ó„ôõöƒ÷‚øùù…ú…û…ü…ý‚þÿùÔ¼®±•ÿž‰œ­¼ÈÙï…ðñò„ó„ôõöƒ÷‚øùù…ú…û„ü†ýƒþÿüؾ°¢¥•ÿŒž¯½ÉÜ…ðñò„ó„ôõöƒ÷‚ø€ù„ú„û†ü…ý„þÿýÛ¿±¥—•ÿ…Ÿ±¾ËÞñƒðñ‚òƒó„ôõö„÷ø€ù„ú…û„ü‡ý…þÿßÁ³¨•ÿ}‘¢²ÀÌáñ‚ðñò…óƒôõö„÷ø€ù„ú…û…ü†ý†þÿäÄ´©Š”ÿûx“£´ÂÍäñðñ‚ò„óƒôõöƒ÷‚ø€ù„ú†û„ü…ýˆþÿçŶªˆü“ÿ ðw”¥µÃÏæñðð‚ñ‚òƒó„ôõö„÷ø€ù„ú†û„ü†ýˆþÿëÇ·«‰ñ“ÿ áv–§·ÄÑéñð‚ñ‚ò„óƒôõö„÷ø€ù…ú„û†ü…ý‰þÿïʹ¬‹ã“ÿ Òx—©¹ÅÒëñðñ‚ò„óƒôõö„÷øù„ú„û…ü†ýŠþÿòͺ­Ô“ÿÁ}™ªºÇÔìòñ‚ò„óƒôõö„÷øù„ú„û†ü…ý‹þÿõϼ­–Ä“ÿ°ƒ›¬¼ÈÖîò€ñ‚ò„óƒôõ‚öƒ÷‚øùù„ú…û…ü†ýŒþÿøÓ½¯œ´“ÿ ¡ˆœ®½ÉØðòññò…óƒôõ‚öƒ÷‚ø€ù„ú…û…ü…ýþÿúÖ¾°¢§“ÿ’Œž°¾ËÛ€ñ‚ò„óƒôõ‚ö„÷ø€ù„ú…û„ü†ýŽþÿüÚÀ²¥™“ÿ‡ ±ÀÌÞòñ‚ò„óƒôõ‚ö„÷ø€ù„ú…û…ü…ýþÿþݳ¨‘“ÿ’¢³ÁÍàƒò…ó‚ôõ‚ö„÷ø€ù„ú…û…ü†ýþÿâõª‹’ÿýx“¤´ÃÎãóò„óƒôõ‚öƒ÷‚ø€ù„ú…û…ü…ý’þÿæÆ·«‡ý‘ÿów•¦¶ÄÐåó€ò„óƒôõ‚ö„÷ø€ù„ú…û…ü†ý‘þÿÿéȸ¬‰ô‘ÿäv–¨¸ÅÑçó€ò„ó‚ôõ‚öƒ÷‚ø€ù„ú…û†ü„ý“þÿÿíʹ¬Šå‘ÿ Õw˜©¹ÆÒêóòòƒóƒô‚õö„÷ø€ù…ú„û…ü†ý’þ€ÿðÌ»­Ž×‘ÿ Å|™«»ÈÕìóò„ó‚ô‚õö„÷øù„ú„û…ü†ý“þ€ÿôϼ®”È‘ÿ³‚›­¼É×î…ó‚ô‚õö„÷øù„ú…û„ü†ý“þÿöÒ¾°›¶‘ÿ¥ˆ¯¾ËØïôƒó‚ô‚õö„÷ø€ù…ú„û…ü†ý”þÿùÕÀ±¡©‘ÿ•ŒŸ°ÀÌÚñôƒó‚ôõ‚öƒ÷‚ø€ù„ú…û…ü†ý’þƒÿûØÁ³¥œ‘ÿ‰¡²ÁÍÝò‚óƒôõö„÷‚øùù…ú„û†ü…ý“þ„ÿýÜô¨’‘ÿ’¢´ÂÎß‚óƒôõ‚ö„÷ø€ù„ú…û…ü†ý’þ†ÿàŶªÿþz”¥µÄÏáô€óƒôõ‚ö„÷ø€ù…ú„û…ü†ý“þ†ÿ䯷«ˆþÿõx•§·ÅÑäô€ó‚ôõ‚ö„÷ø€ù…ú„û…ü…ý“þˆÿçȹ¬ˆöÿ èw–¨¹ÆÒæôóó‚ôõ‚ö„÷ø€ù…ú„û…ü†ý’þ‰ÿëʺ­‹éÿ Øw˜ªºÈÔéôó‚ôõ‚ö„÷ø€ù…ú„û†ü…ý“þ‰ÿî̼®ŽØÿ È{š¬¼ÉÕëôóôõƒöƒ÷ø€ù…ú…û…ü…ý“þŠÿòϾ¯“Éþÿ þ¶‚›®½Ê×íõôõ‚ö„÷‚øùù…ú…û„ü…ý”þ‹ÿõÑ¿°›¹þÿ þ¦ˆ¯¾ËÙñø÷ø‚ù„úû€ü„ý…þ²ÿúÔÀ± ©þÿý–‹®ÀÍÓÛŠÜ„ÝÞÝÝÞÝŒÞßÞŸßÞÞˆß ÞÞßâçÓ¿°£œýþ‹ÿ þýˆ‹¡½ÄÄÈÐÐσЂф҄ÓÔÓ‚ÔƒÕւׂ؅قچÛÜØÍ¾±¤‘üþ‹ÿ þü~™º·»ÊÚïôó€ôõõ€ö÷øùù€ú€û€üýý€þ¸ÿýÑ·¶©Šûþ‹ÿþû}²¥±ÅÑßñôõõôõööõöö÷÷ø÷€øùúúùúúûüüûüýüýýþþÿþºÿäÁ®±ˆûý‹ÿ ý󎙤ºÇÒàòôõöö÷øøùúúûüýýþºÿè˵§óý‹ÿ ýå‚“¬¼ÉÓâó€ôõöö÷øøùúúûüýýþ»ÿëͽ¨ŒåüþŠÿü×u›­½ÊÕä€ôõöö÷øø‚ùúûüýýþ¼ÿïο¯‡Öüþ‰ÿ þûÉx¯¾ËÖæõôõöö÷€øùúúûüýþ½ÿòÑÀ²ŽÊûþ‰ÿ þú¶€Ÿ±ÀÌ×è‚õöö‚÷øøùúúûüýýþ½ÿôÓ³˜¸úý‰ÿ ýù¥‡ ²ÁÍ×êö€õöö‚÷øøùúúû€üýý€þÀÿøÖõŸ¨ùý‰ÿ ýø—Œ¢³ÃÓàîƒôõöõ‚ö‚÷ƒø‡ù‡ú®ûýùÚĶ¥œøý‰ÿ ü÷Š¥½Óäñú‚ûÆüû úõïãθ©öü‰ÿüö•´Ïàìüßÿ ýïèÝÇ®‰õûþ‡ÿ þûõx¨ÈÛæéé„è‰éêƒé¥êƒéê‰é„è éèæÞÒ½…óûþ‡ÿ þûï~½ÓÝØÑÍ’ÌµÍ’Ì ÍÑØÜÒĉïúþ‡ÿþúåˆÅÓÑÌÌáÍÌÌÑÒÅŒäùþ‡ÿþùãˆÆÎÌÌ…ÍÎÎÏÏËÎÏÏÎÎ…ÍÌÌÎÆ‡ãøý‡ÿýøê~Á‡ÌÐÑËÈÍÉÈÊÏÑ͆ÌÁ~é÷ý‡ÿý÷ì|»†Ìе‚hdÍedfx§ÎÍ…Ì»}êöý‡ÿýöë}¸Ë̓ÌТPDÑGDH‰ÎÍ‚ÌÍ˸}éõü‡ÿýöꀳÉÍ‚ÌÏ¿UGÓLJG§Ñ‚ÌÍɳ€èõü‡ÿýö鉮ÈÌ‚ËÒžDLKÓLC~Ò‚ËÌÈ®ˆçôü‡ÿýöê‘§ÇÌ‚ËÒ›DNQSÏUTRNDzÒ‚ËÌǧ‘èõü‡ÿýö랟ÅË€ÊËËϹQYdjÏlkf]JÒËË€ÊËÅŸ›éõý‡ÿý÷ì«—Ä˃ÊÒ•fy~Ð{k}ÍË‚ÊËÄ—©êöý‡ÿþøí·ŒÂ˃ÊËÓª„Ð}|€Î̓ÊË·ë÷ý‡ÿþùîËÃË…ÊÔÌ·Ï­²ÆÕÍɃÊËÀÊìøý‡ÿþùïàr¼ÌÉɃÊÉÌÑÓ¡Ô…Ó¢ÔÒ΄ÊÉÉ̼qÞîøþ‡ÿþúðâ©~ËÍ„ÉÊÊÑÉÊ…ÉÍË~§ßïùþ‡ÿ þûòäуƒÆÎË“Ê³Ë“Ê ÌÎÆ‚Îâðúþˆÿ ûóæÔ½€h¤ÂÊË•Ì«Í•Ì Ëɤh}»Òåòûþˆÿ üõêÙÄ®‘a^v‡ÛŒ ‡v]`¬Á×èôü‰ÿ ýøîà͸¥–‡uheÙd ehu†”£µÊÝì÷ý‰ÿ þúòæÖIJ¢–Šˆ††Õ… ††‡ŠŽ•¡¯ÁÔåñùý‰ÿ þüöîáÑÁ²¥œ–“‘× ‘“–›¤°¿ÏßìöûþŠÿ ýúôëßÒĸ¯¨£¡ ÕŸ  ¡£§®·ÂÐÝêóùýþŠÿ þüùóëá×ÍĽ¹¶´Õ³ ´µ¸¼ÃËÕàêòøüþŒÿ þüùôîçßÙÓÏÍÌÖË ÍÏÓØÞæíóøüþŽÿ þüú÷òîéåâáàÕß àáâåéíòöúüþ‹ÿt8mk@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿicnV Bðvmtk-1.0.1/distribution/scripts/0000775000175000017500000000000011757446472015355 5ustar lucalucavmtk-1.0.1/distribution/scripts/getbuildvmtk.py0000664000175000017500000002265111757446472020436 0ustar lucaluca#!/usr/bin/env python """ Simple build script for VTK, ITK, and vmtk. """ import os import sys import platform import urllib import tarfile import atexit from stat import S_IRUSR, S_IWUSR, S_IXUSR BUILD_TYPE = "Release" OSX_ARCHITECTURES = "i386" # "i386;x86_64" MINGW = False WORK_DIR = os.path.abspath(os.path.curdir) VTK_BUILD_DIR = os.path.join(WORK_DIR, 'vtk-build') ITK_BUILD_DIR = os.path.join(WORK_DIR, 'itk-build') VMTK_BUILD_DIR = os.path.join(WORK_DIR, 'vmtk-build') PARALLEL_JOBS = 3 VERBOSE = True LOGFILE = True log_file = None def log(msg): if VERBOSE: print msg if LOGFILE: global log_file if not log_file: log_file = open(os.path.join(WORK_DIR, 'logfile.log'), 'w+') def log_close(): if log_file is not None: log_file.close() atexit.register(log_close) log_file.write(msg) def on_windows(): return platform.system() == 'Windows' def on_osx(): return platform.system() == 'Darwin' def on_linux(): return platform.system() == 'Linux' def on_x86(): return platform.architecture()[0] == '32bit' def on_x64(): return platform.architecture()[0] == '64bit' def download(url, filename): log("Downloading %s..." % filename) urllib.urlretrieve(url, filename) def tarextract(filename, path='.'): tar = tarfile.open(filename) log("Extracting %s..." % filename) tar.extractall(path) def getstatusoutput(cmd): """Return (status, output) of executing cmd in a shell.""" if on_windows(): pipe = os.popen(cmd + ' 2>&1', 'r') else: pipe = os.popen('{ ' + cmd + '; } 2>&1', 'r') text = pipe.read() sts = pipe.close() if sts is None: sts = 0 if text[-1:] == '\n': text = text[:-1] return sts, text def create_do_configure(build_dir, cmd): """Create a do-configure(.bat) for later possible tweaking.""" do_configure = os.path.join(build_dir, 'do-configure') if on_windows(): do_configure += '.bat' lines = ' ^\n '.join(cmd.split()) else: lines = "#!/bin/bash \n\n" lines += ' \\\n '.join(cmd.split()) lines += '\n' file(do_configure, 'w').writelines(lines) if not on_windows(): os.chmod(do_configure, S_IRUSR|S_IWUSR|S_IXUSR) def build_cmake_project(build_dir, source_dir, options="", install=False): if not os.path.isdir(build_dir): os.mkdir(build_dir) os.chdir(build_dir) cmd = "cmake" if MINGW: cmd += ' -G "MinGW Makefiles"' cmd += " %s %s" % (options, source_dir) create_do_configure(build_dir, cmd) log("Running %s..." % cmd) failure, output = getstatusoutput(cmd) log(output) if failure: msg = "Unable to run '%s'\nError message: %s" % (cmd, output) raise Exception(msg) log(output) if on_windows(): cmd = "nmake" else: cmd = "make -j%s" % PARALLEL_JOBS log("Running %s in %s..." % (cmd, build_dir)) failure, output = getstatusoutput(cmd) log(output) if failure: msg = "Unable to run '%s'\nError message: %s" % (cmd, output) raise Exception(msg) if install: cmd = cmd + "install" log("Running %s in %s..." % (cmd, build_dir)) failure, output = getstatusoutput(cmd) log(output) if failure: msg = "Unable to run '%s'\nError message: %s" % (cmd, output) raise Exception(msg) os.chdir(WORK_DIR) def build_vtk(): filename = "vtk-5.6.0.tar.gz" url = "http://www.vtk.org/files/release/5.6/" + filename source_dir = os.path.join(WORK_DIR, 'VTK') install_dir = os.path.join(WORK_DIR, 'vtk-bin') if not os.path.exists(filename): download(url, filename) if not os.path.isdir(source_dir): tarextract(filename) # minor fix for installing VTK Python Wrappers (avoid using setuptools) setup_py = os.path.join(source_dir, 'Wrapping', 'Python', 'setup.py.in') lines = file(setup_py, 'r').readlines() newlines = [] for line in lines: newlines.append(line) if 'has_setup_tools = 1' in line: newlines.append('has_setup_tools = 0\n') os.chmod(setup_py, S_IRUSR|S_IWUSR) # make the file read/writable file(setup_py, 'w').writelines(newlines) options = ['-DCMAKE_BUILD_TYPE:STRING=' + BUILD_TYPE, '-DCMAKE_INSTALL_PREFIX:PATH=' + repr(install_dir)[1:-1], '-DBUILD_TESTING:BOOL=OFF', '-DBUILD_SHARED_LIBS:BOOL=ON', '-DVTK_WRAP_PYTHON:BOOL=ON', '-DVTK_WRAP_TCL:BOOL=OFF', '-DVTK_INSTALL_PYTHON_USING_CMAKE:BOOL=ON', ] if on_osx(): options.extend(['-DCMAKE_OSX_ARCHITECTURES:STRING="%s"' % OSX_ARCHITECTURES, '-DCMAKE_OSX_SYSROOT:PATH=/Developer/SDKs/MacOSX10.6.sdk', '-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.5', '-DVTK_USE_TK:BOOL=ON', ]) if on_windows(): py_ver_major, py_ver_minor = sys.version_info[0:2] python_inc_dir = os.path.join(os.path.dirname(sys.executable), 'include') if MINGW: options.append('-DCMAKE_USE_PTHREADS:BOOL=OFF') python_lib = 'libpython%d%d.a' % (py_ver_major, py_ver_minor) else: python_lib = 'python%d%d.lib' % (py_ver_major, py_ver_minor) python_lib = os.path.join(os.path.dirname(sys.executable), 'libs', python_lib) options.extend(['-DVTK_USE_TK:BOOL=OFF', '-DPYTHON_EXECUTABLE:FILEPATH=' + sys.executable, '-DPYTHON_INCLUDE_DIR:PATH=' + python_inc_dir, '-DPYTHON_LIBRARY:FILEPATH=' + python_lib]) options = ' '.join(options) build_cmake_project(VTK_BUILD_DIR, source_dir, options) def build_itk(): filename = "InsightToolkit-3.18.0.tar.gz" url = "http://downloads.sourceforge.net/project/itk/itk/3.18/" + filename source_dir = os.path.join(WORK_DIR, 'InsightToolkit-3.18.0') install_dir = os.path.join(WORK_DIR, 'itk-bin') if not os.path.exists(filename): download(url, filename) if not os.path.isdir(source_dir): tarextract(filename) options = ['-DCMAKE_BUILD_TYPE:STRING=' + BUILD_TYPE, '-DCMAKE_INSTALL_PREFIX:PATH=' + repr(install_dir)[1:-1], '-DBUILD_TESTING:BOOL=OFF', '-DBUILD_SHARED_LIBS:BOOL=ON', ] if on_osx(): options.extend(['-DCMAKE_OSX_ARCHITECTURES:STRING="%s"' % OSX_ARCHITECTURES, '-DCMAKE_OSX_SYSROOT:PATH=/Developer/SDKs/MacOSX10.6.sdk', '-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.5', ]) if on_windows() and MINGW: options.append('-DCMAKE_USE_PTHREADS:BOOL=OFF') options = ' '.join(options) build_cmake_project(ITK_BUILD_DIR, source_dir, options) def build_vmtk(): source_dir = os.path.join(WORK_DIR, 'vmtk-packaging') install_dir = os.path.join(WORK_DIR, 'vmtk-bin') if not os.path.isdir(source_dir): cmd = "bzr branch lp:vmtk-packaging" failure, output = getstatusoutput(cmd) log(output) if failure: msg = "Unable to run '%s'\nError message: %s" % (cmd, output) raise Exception(msg) options = ['-DCMAKE_BUILD_TYPE:STRING=' + BUILD_TYPE, '-DCMAKE_INSTALL_PREFIX:PATH=' + repr(install_dir)[1:-1], '-DBUILD_SHARED_LIBS:BOOL=ON', '-DITK_DIR:PATH=' + repr(ITK_BUILD_DIR)[1:-1], '-DVTK_DIR:PATH=' + repr(VTK_BUILD_DIR)[1:-1], '-DVTK_VMTK_WRAP_PYTHON:BOOL=ON', '-DVTK_VMTK_WRAP_TCL:BOOL=OFF', '-DVTK_VMTK_BUILD_TETGEN:BOOL=ON', '-DVMTK_WITH_LIBRARY_VERSION:BOOL=ON', '-DVMTK_ENABLE_DISTRIBUTION:BOOL=ON', ] if on_osx(): options.extend(['-DCMAKE_OSX_ARCHITECTURES:STRING="%s"' % OSX_ARCHITECTURES, '-DCMAKE_OSX_SYSROOT:PATH=/Developer/SDKs/MacOSX10.6.sdk', '-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.5', ]) if on_windows(): options.extend(['-DVMTK_INSTALL_PYTHON:BOOLD=ON',]) if not MINGW: vcredist_x86 = os.path.abspath(os.path.join(WORK_DIR, "vcredist_x86.exe")) vcredist_x64 = os.path.abspath(os.path.join(WORK_DIR, "vcredist_x64.exe")) if on_x86(): if not os.path.isfile(vcredist_x86): download("http://download.microsoft.com/download/d/d/9/dd9a82d0-52ef-40db-8dab-795376989c03/vcredist_x86.exe") options.append('-DVCREDIST_EXE:FILEPATH=' + vcredist_x86) if on_x64(): if not os.path.isfile(vcredist_x64): download("http://download.microsoft.com/download/2/d/6/2d61c766-107b-409d-8fba-c39e61ca08e8/vcredist_x64.exe") options.append('-DVCREDIST_EXE:FILEPATH=' + vcredist_x64) options = ' '.join(options) build_cmake_project(VMTK_BUILD_DIR, source_dir, options) def generate_package(generator=None): os.chdir(VMTK_BUILD_DIR) cmd = "cpack" if generator is not None: cmd += " -G %s" % generator failure, output = getstatusoutput(cmd) log(output) if failure: msg = "Unable to run '%s'\nError message: %s" % (cmd, output) raise Exception(msg) os.chdir(WORK_DIR) def build_all(): build_vtk() build_itk() build_vmtk() if __name__ == '__main__': build_all() generate_package() vmtk-1.0.1/distribution/CMakeLists.txt0000664000175000017500000001776611757446472016447 0ustar lucalucaINCLUDE(InstallRequiredSystemLibraries) SET(CPACK_PACKAGE_NAME "vmtk") SET(CPACK_PACKAGE_VENDOR "vmtk.org") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "vmtk - the Vascular Modeling Toolkit") SET(CPACK_RESOURCE_FILE_LICENSE "${VMTK_SOURCE_DIR}/Copyright.txt") SET(CPACK_PACKAGE_VERSION_MAJOR ${VMTK_VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MINOR ${VMTK_VERSION_MINOR}) SET(CPACK_PACKAGE_VERSION_PATCH ${VMTK_VERSION_PATCH}) SET(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS};${VMTK_BINARY_DIR};VMTK;ALL;/") IF(EXISTS "${VTK_DIR}/CMakeCache.txt") SET(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS};${VTK_DIR};VTK;ALL;/") ENDIF(EXISTS "${VTK_DIR}/CMakeCache.txt") IF(EXISTS "${ITK_DIR}/CMakeCache.txt") SET(CPACK_INSTALL_CMAKE_PROJECTS "${CPACK_INSTALL_CMAKE_PROJECTS};${ITK_DIR};ITK;ALL;/") ENDIF(EXISTS "${ITK_DIR}/CMakeCache.txt") SET(CPACK_COMPONENTS_ALL Development RuntimeLibraries RuntimeExecutables) SET(CPACK_COMPONENT_RUNTIMEEXECUTABLES_DISPLAY_NAME "Application files") SET(CPACK_COMPONENT_RUNTIMEEXECUTABLES_DESCRIPTION "The vmtk application and required components.") set(CPACK_COMPONENT_RUNTIMEEXECUTABLES_DEPENDS RuntimeLibraries) SET(CPACK_COMPONENT_RUNTIMELIBRARIES_DISPLAY_NAME "Runtime libraries") SET(CPACK_COMPONENT_RUNTIMELIBRARIES_DESCRIPTION "Runtime libraries and Python modules.") SET(CPACK_COMPONENT_DEVELOPMENT_DISPLAY_NAME "Development files") SET(CPACK_COMPONENT_DEVELOPMENT_DESCRIPTION "Static libraries and header files needed to build applications against vmtk.") SET(CPACK_COMPONENT_DEVELOPMENT_DISABLED ON) IF(EXISTS "${VTK_DIR}/Wrapping/Python/vtk") INSTALL(DIRECTORY "${VTK_DIR}/Wrapping/Python/vtk" DESTINATION lib/site-packages USE_SOURCE_PERMISSIONS COMPONENT RuntimeLibraries ) ENDIF(EXISTS "${VTK_DIR}/Wrapping/Python/vtk") IF(APPLE) # Use the bundle-generator on osx ... SET(CPACK_GENERATOR "Bundle") SET(CPACK_BUNDLE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/bundle/vmtk.icns") SET(CPACK_BUNDLE_NAME "vmtk") CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/bundle/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist @ONLY) SET(CPACK_BUNDLE_PLIST "${CMAKE_CURRENT_BINARY_DIR}/bundle/Info.plist") SET(CPACK_BUNDLE_STARTUP_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/bundle/vmtk-startup") ##SET(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/bundle/CustomVolumeIcon.icns") #IF(${CMAKE_OSX_ARCHITECTURES} STREQUAL "i386" OR ${CMAKE_OSX_ARCHITECTURES} STREQUAL "x86_64") SET(CPACK_PACKAGE_FILE_NAME "vmtk-${VMTK_VERSION}-darwin-${CMAKE_OSX_ARCHITECTURES}") #ELSE(${CMAKE_OSX_ARCHITECTURES} STREQUAL "i386" OR ${CMAKE_OSX_ARCHITECTURES} STREQUAL "x86_64") # SET(CPACK_PACKAGE_FILE_NAME "vmtk-${VMTK_VERSION}-darwin-universal") #ENDIF(${CMAKE_OSX_ARCHITECTURES} STREQUAL "i386" OR ${CMAKE_OSX_ARCHITECTURES} STREQUAL "x86_64") ENDIF(APPLE) IF(WIN32) # Use the nsis-generator on Windows ... SET(CPACK_GENERATOR "NSIS") SET(CPACK_NSIS_HELP_LINK "http://www.vmtk.org/Main/Installation") SET(CPACK_NSIS_URL_INFO_ABOUT "http://www.vmtk.org") SET(CPACK_NSIS_MENU_LINKS "http://www.vmtk.org/Main/Documentation" "vmtk documentation") SET(CPACK_NSIS_CONTACT "vmtk-users@lists.sourceforge.net") #SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\MyExecutable.exe") #SET(CPACK_NSIS_MUI_ICON "installer.ico") SET(CPACK_NSIS_MODIFY_PATH "OFF") SET(CPACK_NSIS_CREATE_ICONS "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\PypePad.lnk' '\$INSTDIR\\\\vmtk-startup.bat' '' '' '' SW_SHOWMINIMIZED") SET(CPACK_NSIS_DELETE_ICONS_EXTRA "Delete '\$SMPROGRAMS\\\\$MUI_TEMP\\\\PypePad.lnk'") INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/nsis/vmtk-startup.bat" DESTINATION . COMPONENT RuntimeExecutables ) # Find and install Python OPTION(VMTK_INSTALL_PYTHON "Include Python in the vmtk installer" OFF) IF(VTK_VMTK_WRAP_PYTHON AND VMTK_INSTALL_PYTHON) FIND_PROGRAM(VMTK_PYTHON_COMMAND python.exe PATHS "C:/Python26" DOC "Path to the installed python.exe." ) IF(EXISTS ${PYTHON_DIR}) SET(VMTK_PYTHON_COMMAND "${PYTHON_DIR}/python.exe") ENDIF(EXISTS ${PYTHON_DIR}) IF(NOT VMTK_PYTHON_COMMAND) MESSAGE(SEND_ERROR "Could not locate python.exe.") ENDIF(NOT VMTK_PYTHON_COMMAND) GET_FILENAME_COMPONENT(VMTK_PYTHON_PATH ${VMTK_PYTHON_COMMAND} PATH) INSTALL(DIRECTORY ${VMTK_PYTHON_PATH}/ DESTINATION lib/Python USE_SOURCE_PERMISSIONS COMPONENT RuntimeExecutables ) ENDIF(VTK_VMTK_WRAP_PYTHON AND VMTK_INSTALL_PYTHON) IF(MINGW) SET(CPACK_PACKAGE_FILE_NAME "vmtk-${VMTK_VERSION}-mingw32") # Install mingwm10.dll FIND_PROGRAM(VMTK_MINGW_GCC mingw32-gcc.exe PATHS ${MINGW_DIR} "C:/mingw/bin" DOC "Path to the MinGW GCC command." ) GET_FILENAME_COMPONENT(VMTK_MINGW_PATH ${VMTK_MINGW_GCC} PATH) INSTALL(FILES ${VMTK_MINGW_PATH}/mingwm10.dll DESTINATION bin COMPONENT RuntimeExecutables ) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/nsis/mingw-postinst.bat DESTINATION . COMPONENT RuntimeExecutables ) SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS} ExecWait '\\\"$INSTDIR\\\\mingw-postinst.bat\\\"' Delete \\\"$INSTDIR\\\\mingw-postinst.bat\\\"" ) ENDIF(MINGW) IF(MSVC) #macro(_FIND_MSVC_REDIST) message(STATUS "Looking for MSVC Redistributable Executable for MSVC Version ${MSVC_VERSION}") set(SDKVERS "2.0") if(${MSVC_VERSION} EQUAL 1400) set(SDKVERS "2.0") set(VCVERS "8") endif() if(${MSVC_VERSION} EQUAL 1500) set(SDKVERS "3.5") set(VCVERS "9") endif() if(${MSVC_VERSION} EQUAL 1600) set(SDKVERS "3.5") set(VCVERS "10") endif() IF(${MSVC_VERSION}) FIND_PROGRAM(MSVC_REDIST NAMES vcredist_${CMAKE_MSVC_ARCH}/vcredist_${CMAKE_MSVC_ARCH}.exe PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\${VCVERS}.0;InstallDir]/../../SDK/v${SDKVERS}/BootStrapper/Packages/" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${VCVERS}.0;InstallDir]/../../SDK/v${SDKVERS}/BootStrapper/Packages/" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\${VCVERS}.0;InstallDir]/../../SDK/v${SDKVERS}/BootStrapper/Packages/" ) GET_FILENAME_COMPONENT(vcredist_name "${MSVC_REDIST}" NAME) INSTALL(PROGRAMS ${MSVC_REDIST} COMPONENT SupportFiles DESTINATION bin) SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\bin\\\\${vcredist_name}\\\"'") message(STATUS "MSVC_REDIST: ${MSVC_REDIST}") ENDIF(${MSVC_VERSION}) #endmacro() #IF(${CMAKE_MSVC_ARCH} STREQUAL "amd64") # SET(VCREDIST_EXECUTABLE "vcredist_x64.exe") #ELSE(${CMAKE_MSVC_ARCH} STREQUAL "amd64") # SET(VCREDIST_EXECUTABLE "vcredist_x86.exe") #ENDIF(${CMAKE_MSVC_ARCH} STREQUAL "amd64") #FIND_PROGRAM(VCREDIST_EXE # ${VCREDIST_EXECUTABLE} # PATHS # DOC "Path to the Visual Studio C++ redistributable" # ) #IF(NOT VCREDIST_EXE) # MESSAGE(SEND_ERROR "Could not locate ${VCREDIST_EXECUTABLE}.") #ENDIF(NOT VCREDIST_EXE) #INSTALL(FILES # ${VCREDIST_EXE} # DESTINATION redist # COMPONENT RuntimeExecutables # ) #SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS # "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS} # ExecWait '\\\"$INSTDIR\\\\redist\\\\${VCREDIST_EXECUTABLE}\\\"'") ENDIF(MSVC) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/nsis/postinst.bat DESTINATION . COMPONENT RuntimeExecutables ) SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "${CPACK_NSIS_EXTRA_INSTALL_COMMANDS} ExecWait '\\\"$INSTDIR\\\\postinst.bat\\\"' Delete \\\"$INSTDIR\\\\postinst.bat\\\"" ) SET(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS "${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS} MessageBox MB_YESNO|MB_ICONQUESTION 'Do you want to completely remove the directory $INSTDIR and all of its contents?' IDNO NoDelete RMDir /r \\\"$INSTDIR\\\" ; skipped if no NoDelete:" ) ENDIF(WIN32) INCLUDE(CPack) vmtk-1.0.1/distribution/nsis/0000775000175000017500000000000011757446472014642 5ustar lucalucavmtk-1.0.1/distribution/nsis/postinst.bat0000664000175000017500000000104411757446472017214 0ustar lucaluca@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 vmtk-1.0.1/distribution/nsis/vmtk-icon.tiff0000664000175000017500000002401611757446472017426 0ustar lucalucaII*º€?à@$ „BaP¸d6ˆDbQ8¤V-ŒFcQ¸äv=HbÐ'üŠM'”JeR¹d¶]/˜LcI”Öm7œNgS¹äö/4ŸPhT:%G›P!%ä*–‘O¨TjU:¤D{-ÂéP‚êIU°XlV;% F|.V p¢åzËo¸\nW8º’Ñj’Ûj;¥öýÀXT‡Òíâ[A(°8¼f76RŸ‹ØhV#ÌfsY¸¾G' ­ÁËHsM§Ôi”ÇòþRZ@(5;=¦Öè¦@5ЂÉÿe¶àpxU:u µÂw©þ7ÏœñL;¸9`üžèv{]¹:¡bêAŠçÔïsÍçôE(3.€?à@$ W>§`иd6ˆDbQ8¤V-ŒFcQ¸äv=HdR9$–©A˜áð'ü<¬|NI¦S9¤Öm7œNgS¹äíT„2Jàpâ±í7=¤RiTºe6O¨CUHS- [D=&ª5ºåv½_°Xdʤ1š­*ž“6+e¶Ýo¸\fÊ´1žÏ*S+åöýÀ[ˆsEÞT<^ð8¼f7+Xt²S<%ò¼æw=ŒV¢ 8haHî–ÏêuZ½e=\‰5i!e#¶£[·ÜnwRr+c•¡ÃJ'T®ïÇär`ŠôY¯eá¥9]>§W7Ì6sॢO­ßðxmêôa·µ(Ò^/g·ÝMX#MÞp?Õïü~S5Ëè'ŽD‹÷À*0X‘Ãz€€€?à@$ N9$`иd6ˆDbQ8¤V-ŒFcQ¸äv=HdR9$–²Gáð'ü<œpHI¦S9¤Öm7œNgS¹äíd8JàpâiÁ=¤RiTºe6O¨CVi [&Õåv½_°XlRe¢@åV‡“ õ»¶Ýo¸\nSU¢FÏ–ZMÈÛöýÀ`m«D‘ÎÑ%›‘˜,f7ÈHV©#¦J6"ò9¼æw=[%¹hfaŸÔjuZº~„í¤…’z}f×m·ÜHÉ]}⇠$šÑ;ž'Ç‚-Ò§}„jDr:]>¦mp–Jàpâ)•=¤RiTºe6O¨CWi³í ["Uåv½_°XlReâpýV‡ëV;e¶ÝoƒÅCS©@~¿" PÕb ]1ž÷ ZöÍh‡Ìh&7¸ I¦Á@?}+O¨t³›!<^§Oøˆi Ä€ÏêuZºP”Ž]LÄq§º˜ø‰N絓eê{Q–CÈZ}ßIŒUhÒxN4ñl-J(¦\LF.& M¢—o¹ãÌ×Ûí$0‚aÑø}^¹hv´B‘q§«mtLC1d‚R1u4,»ˆÉîRdA8Ý=‰~O±Ž††ˆ«ª6 …#‚¡¶\‰d)ˆýˆâù76…ôC<²>` <«Âü'GÊ |9D$F‘µÂñ6-±HóAÒ2`1’à¡Â¾ ÉÒÌtÃ$€‘£'¡´\ ‘HÂù8-É(ÉìQ1–†â0¢a@1†!ø}@ èñôx§È—"Xî?ählÐ0ÂíÁ7± K¢àñF‹aN³{£@{ƒÉ#²¬79 ò¡tøòš„b`ÀOŠá::r‚é*a#àÁ$N ᆲ˜$‰ >™‡šˆ¼X½Ç#'™02ƘŠ+"¸b$§Y0:‘Å6"…€ÃÈ1 ¡ø?°$'¡¸bŒ„ i&¢Oƪ±L:dÇv…ô7QIþ¡?ë¢cq@Š€ø †Éz,…圱\ä:€€€?à@$ =-ž иd6¨T&1‚±SÈcÂõåŒ I«óàî- ‡=Z¦2»‘Ì*ðžQz;@À :o?‡>\'C]’"(O.Oƒ>+Ò)éw ˜Ìæµ åìž: “îhmfi6®Wì69@üÄlBÕØ[±¤`7©¥÷Kåц¥DCàOøxðµ ¾ÏÊǹ¸jº> ‚" t'›NçQÎBºâ^' IæäŸ¤FüºÊyøpáøò[«0ÄQ 1{/Ì)äJd$²‰£1D-“ P|”cúLCˆ`G-K’òžz“ƒ‘OΨ0&DC¸{"1&6DñÛ7=&)NEFì$r,G“pZ, DÀ A¥°†>²é¸š6Àv .†I4AÉ'š°#Ërë¼|œÇÎvž‡à‚Àø0ŸBÍqÜpgqîà¸: À`àϳûކ h|ƒ`Aò{ÀpAŒ!¤¢ ;@úO @ ¸ 籦eT ˜Ö³Ò>OËb -ÃàÖX‹á¸]Âùµg™Æj%hSTz ƒQ&+éú_d(øbÖIø"–„¸©V+‡™¤Vä1’ïæùÎw “c‰@h¤3“"´Ú¾žf±j#²ØŒ,c]*‡‡"¸éÅA@‹á2œ®™É8ÑÏPœaö˜®FAB'‘æš~ƒTå”#€ÿ:(š1‚çfºfظ.+ÚnD‰&ƒšºi”„`ÌY $–¤¸Ÿ¶*)b#&éZv=ú z“CHþO‚)tCˆàkub ÚTœ¼¤,c•$gCœˆsr€4…t©‘Bà ‡Ò®C‚hlaè½Âž>E8xBHo”Dƒ¥ o˜§A4í›á@ ô])çäWG Ö aŒN£"€¨~`ЗA¤ôC8³_D‚‹U=Š…ñè?a]"L8 `~"H.>qð¸$EÓúG¯ðF¿òB´@`LŠ ë‹ æáXFÆ~ 4eÅ@u `Œke'àˆ#ÅHP ™ áüPD8ˆÇ„ÈZæFèjSä$†‡ÂŒEĪٞÀ™  Ÿ1«ß ß“0ŠCÄ‘è>@h åôxŠð ‘ŒbKãUFV,¥ˆh8 ¡Ê]`ÎÄD’etf ± ÓV €¤% 9’éÊ€ÑRaœWIø<ƒ ¦ ²´›ÈÜ¡I@b8O‡°uÊxøÁh.‰Èm ç✄ÜhŠ!'ž°=Âd(ÊBo)…xE4àAùÃ8åÐû¢”ˆ›.“Èb:3ÀnC ø^ £ Ê€÷ÂÜ xì8}€úƒÊB¨Œ¥òbp pÊ á€— ÁöF•&#Äø|åt| P³=g¹7¡Ôú Ñ¢(DHf“x”|-ÄÕ+£Ìj ðˆ Fª§´þŒè'ƒ°}0v¶ Á’*Ä}!`Ü*R0ƒËa es“ñÒ Âàˆ‹„IŠî §?C@WQ C …S ÕT¨A.j$Ž$HG úì‰?©¡d.Ojx=›.•^¬½HU@„ØRety K+BëU°¶UÔwŒÐ E%¢®¦¬dŠÊó/Èx6 a¾ºÁðÊ*8,.ƒ(L‡ÀØ6ÁøÅl.h È‚fð®Ýk±vŠåž aìOÕÂn}¦t¢x@°ÄÝQ%ºìÛ1@",B…U|N;vW-è­B¦'k¯nX‚ìL!05ðÉÀB´H×¢ ‚•Ô¹`QŠàÚjŠx÷‚ÄEŽh‚Xm£D+°êè]G ¢§ YÔÈÅ Ê"ó¬P‡ày ø\- ¼~MòCÈ¥@h ñôï±X3[Á©„ƒö8g"_ú>ÇÁ:òÔÁDƒ¸”b„ÄŒ¡]‰n¡H7b³27t~±ö.u&ãxW‰ ®(Í)}!3  Ñ›¡(• AèPfAQÅÉõ0j`´&²¹(ÓzwO—AŸ—žžJ!µx\ ЩƒÊ€ò˜!ˆAwõžžÔp| pô¨àPÂ!i'º4B°_ºÇ>ñ–+„–&  Ð(†Üø `Ç~YŽÁ„§æ®B}•  i:–£ D 5^ÌÕ¡f\Áཱུ©]äoë¨î…ð— ¬$¨ŽCH¦áÖgƒïrº2HØkÁD,‡ôQ‰M„Á"4¶é\‚¼Iò€?à@$ 4(› иd6ˆCAȔꆈÆcPgÛqh9:®#q¡ Ϋ5 dp·¢PÒxP:%p@š=DƒfpWÃLªYL·ærY<¦wg'P¦e£žfM)Σ Eûp ÈÆ%ZD”J¨ï¡ˆø wÃÉõQ¸Z¯O§Ó¢©q¼^`ÌÅzRÃÆ…Uë —Ni’˜‡^$O'…ûÏ #Õ”j;Ñ&h<(fS0š:n>U§¥BÂeÁ3Ìf³”vrq LÑÈôº}MyØÍWkç¤80!Å`¦ Ñ™¯†ìsv)Þ{A¢††eõ¡Ôkzž—µ­l–6ÌX_¡ØxÌžkócÁUª¤ÀøÂßm³1Q f¼¡ŽÙʱèI ã»°ÒåÔ5F¨+¨*ÍÀª³jB ¥šœ•¦°t ½g®kœG€„!: ʨ~#8ÞM7(4@ÐD¡ƒ1DŒáp¼@%‘¦[ó' ÆibJ¯è Ï„ ½ ¤A0…Q“ât¤È”HšO4vVpÊvy’C2a #@‘RaûzŸ¦+B©\×6«Æi6Aó¢20d@ܧRÚ8NIŠAÍÉ)9£!qVY áô~$ê@™gÕ$óÅ”¨õÊÈl°5UkÀ2í–£¸nüždÀÜ;“N„# hÙL¥g™"3GéÜìR“Ò¬{Ϲ0¡PV%d%t1D§``Z(—¤(ЏV •fAhXCmXêµ×f£7}‹x¯'¹¬3 ä¡™t°Õi-*°2¸š4à Š U òœ¥øz4G«òÌ pÚÞD€Ê;TR"Ò”¤ =¦g¹¢) ÄÅ„ãÖ8«„Ñ3y42‘xÒÌRÙçdVcã¸þB•Ž‘&/ "òu˜ÅŽC˜øJâgd¾‡†"`Ñ­+ÂPÞ?ÜÀËš)e/!Ž4ãhayà êMîp&J”Ä(u”%g¹ - ¤Á®Øn{®ïš[nÞ¼ñ9Š!5#'ž{Î÷£q»¶ñ½o‰˜"–Å¿µ/E¡:¦+-²%fyhLkèp`& ý¢¬ † 8*ëÉönóQ{-³)`7бÞG ƒÆ—$0‚ ªÇA$ „þú†Ê\~Ь_’CÐâ]¬¸f"ƒ0ˆ`‹Êuâàø*QQ y¯=õ·¦õ^¹3a`7 и ËÐèo€R>7|A€´.䆂ð–ï`¼!„PŽBRÀJÀ°0(À0Cè~Hf=GØóƒÈrŽ‘Ö8‡0ã£}ÙÂh †ˆµƒjÁ‚ÁД¢CÈ€?à@$ +"˜ иd6ˆDbQ8¤V-ŒFcQ¸äv=HdR9$–Õ]¨!ð'ü'5­}Œ’²ÒÚ(1â=s‡òEu§Ø 00’ ”1áHHSeashore 0.1.9applmntrRGB XYZ Ú! acspAPPLöÖÓ-applÃw¡ïÃg¢Ý7årXYZ,gXYZ@bXYZTwtpthchad|,rTRC¨gTRC¸bTRCÈvcgtØndinì>desc,ddscm>mmodÐ(cprtø$XYZ [Š4KXYZ w•µ¡(MXYZ #·a¢XYZ óRÏsf32 BÞÿÿó&’ý‘ÿÿû¢ÿÿý£ÜÀlcurvÍcurvÍcurvÍvcgt$¦z||~€‚ƒ D Å ‡ ˆ ‰ Œ¶h‘‘’”••—Åo››È u!¢"£#Ï%{&¦'Ñ)~*«+Ö-‚.­/Ú1‡2²3ß5Œ6¶7á9Ž:º;æ=“>¾?êA–BÂCîEšFÆGòIŸJÊKöM¢NÎOÐPÐQÑRüTªUÕVÖW×XØZ[±\Ü]Ý^Þ_ß`àb c¹däeåfægçhèiéklÁmínîoïpðqñròsôtôuõvöw÷xøyùzú{ü|ü}ý)€Õ‚ƒ„…†‡ˆ‰Š ‹ Œ Ž ‘’“”•–—˜™š›œžŸ ¡ ¢!£"¤#¥$¦%§'¨'©(ª)«*«ë¬l­,®-¯/°0±1²1³2´4µ5¶6¶ö·v¸7¹8º:»;¼<½<¾=¾þ¿À?Á@ÂAÃBÄCÅÅ„ÆEÇFÈGÉIÊIË Ë‹ÌKÍLÎNÏÏÐPÑQÒRÓÓ’ÔSÕTÖU××—ØWÙXÚZÛÛ›Ü\Ý\Þ]ßߟà_á`â!â¢ãbäcådæ%æ¦çfègéhê)êªëjìkílî-î®ïnðoñpò1ò²órôsõtö5ö¶÷vøxùyúyû:û»ü{ý|þ=þ¾ÿÿ#ðË«“|gT C 4 ' ' &(8L^sޝËé6g ˜!Ç#$=%q&±'ï)(*l+»-.A/‘0á2)3†4×6*7p8Å:;x<Ì>?o@ÂB$C{DÑFGxH½IùK1LeM•NÑPQGRxS¥TÔV W@XqYZÆ[ï]^O_z`¢aÅbéde?fXg~h iÀjÝkùmn+oDphq|rs¢tµuÈvÛwêxöz{| },~5@€KO‚[ƒ`„e…l†t‡rˆ€‰€Šƒ‹‰Œ’‹Žš™—‘‘’œ“’”–•˜–¨—§˜®™¨š«›¯œ¼¼žÅŸÌ Ñ¡Ó¢Ó£Ó¤Û¥ä¦ç§â¨å©ïªñ«ï¬î­ò®ï¯ë°ì±ç²á³â´ÚµÑ¶É·À¸·¹¯ºœ»’¼€½m¾[¿KÀ<Á*ÂÂùÃàÄÊÅ´Æ“ÇrÈSÉ6ÊÊÿËÚÌ´ÍŠÎZÏ#ÏæÐ³Ñ}ÒEÓÓÝÔ ÕjÖ3Öý×ÍØ“Ù]Ú)Úóۺ܂ÝKÞÞÞß©àsá;ââÊã”ä^å'åìæºçèJééÝê¤ëlì5ìþíÉî’ï[ð$ðìñ³ò|óGôôØõ¥öo÷9øøÇù‘ú[û#ûíü¶ý€þIÿÿÿƒxz;º}?¿…FÅ † ‡ Š J Ë ŽOÏ’““TÔ––˜š››œ\ÝŸ  ¡!¡"¡#£$¤%¥&¦'§(¨)©*i*ê+ª,¬-­.®/¯0°1±2²3³4´5¶6¶7¶8x8ø9º:º;»<¼=½>~>þ?¿@ÀAÁBÂCÃD„EEÅFÆGÇHÈIÉJÊK‹L LÌMÍNÎOÏPQQÑRÒSÓTÔUÖV–WW×XØYÙZÚ[›\\Ü]Ý^ß_à`àa¡b!bâcãdäeåf¦g&gçhèiéjêk«l,lìmínîoïpðqñròsótôuõvöw÷x¸y8yùzú{û|ü}ý~þÿ‚ƒ„…†‡ˆ‰‰ÉŠJ‹ Œ Ž ‘’“”•–—˜™š›œžŸ ¡ ¢!¢â£c¤#¥$¦&§&¨'©(ª)«*¬,­-®.¯/°0±1²1³2´3µ4¶5·7¸7¹8º9»;¼;½<¾>¿>À?Á@ÂAÃBÄCÅEÆFÇFÈGÉHÊIËKÌvÎ"ÏNÐPÑPÒQÓ}Õ*ÖV×WØ‚Ú/ÛZ܆Þ3߉á5âŒädæ;ç‘éiëjílïoñŠôZöù‹ýRÿÿndin6–+VšS¢†+'_¨P T9=pJ=.BYs°ø Kx¨ÎçG½ü=Æü!Y¦õF…¯ïG¡æ\½9„ë : o À - € ¸  Ù  n è E ƒ áaÂfìQ–ý‰ò:¥7¥ï_÷i¶+Çfª%wôGó $|µj ! Ú!”"""€##Ï$‘%U&&â'«(C(©)B**á+³,‡-\.3/ /ç0Ä1¢2‚3d4G5,66ü7æ8—99À:°;¡<”=ˆ>?w@qAlBiChDhEkFnGtH{I„JK›L©M¸NÉOÜPñRST8USVpWŽX®YÐZó\]>^f_`»aècdGeyf¬ijPkŠlÅnoApqÃstKu’x$yoz¼| }Z~¬ÿT„…\†·ˆ‰qŠÑ•Žù_‘Æ“/”š—s˜ãšS›Åž® %¡£¦§Ž©ª­—¯°¤²-µD¶Ñ¸a¹ñ½¾¬ÀBÃtÅƬÈJËŠÍ-ÎÑÐvÓÆÕpרÈÜ&ÝØßŠá?䬿dèéÚíVïð×òšô_÷ìùµûÿÿÿ )?Xu•¸Þ0_Ž¿ó*_šÔMŒÍ O•Û i°øCÙ%uÃd¸ \ ®  ^ ´ c ¿  p Í * ìL¯ oÖ@¤vÛF± ’þsíjêlòtözŒª9ÆV逶Qê †!&!È"n##¾$c% %Á&n''Ò(‰)B)ý*»+|,=,÷-¿.ˆ/T0!0ï1¿2‘3j4D55û6Õ7¹89:g;W<==/>!?@AAòBñCïDëEæFóGëHõJKLM1N>OOPRQkRyS›T²UÌVÛWüYZ/[N\q]™^Å_ça b0chdše¿fðh)iej—kÕmnUo›pèr(svtÉvwsxÊz#{Ž|ê~YÈ6‚¥„…އˆ–Š‹›5ŽÎe‘ú“•7–嘞šjœUž) ¡ì£Â¥µ§™©†«c­\¯F±8³4µ.·-¹(»%½(¿0Á?ÃHÅQÇlÉqˑ͠ϼÑÞÓÿÖØ=Úd܋޺àìãåBç€é¨ëäîðfòžôæ÷(ùnû¶þÿÿBY°Ò Kx¨G½=ÆYõFšïG¡þ\„ë T À - œ  ÷ n è daãfìsý‰¥7Ê_÷ÇfªNôGó Pµ ! Ú!”"Q##Ï$‘&&â'«(v)B*á+³,‡-\.3/ 0Ä1¢2‚3d4G66ü7æ8Ò9À:°<”=ˆ>?w@qBiChDhEkFnH{I„JK›L©M¸NÉOÜPñRST8USWŽX®YÐZó\]>^f_`»aècdGeyf¬gáijPlÅnoApqÃstKu’vÚx$yoz¼| }Z~¬ÿT‚ª„…\†·ˆ‰qŠÑŒ2Žù_‘Æ“/”š–—s˜ãšS›Å9ž® %¡£¤“¦§Ž©ª¬­—¯°¤²-³¸µD¶Ñ¸a¹ñ»ƒ½¾¬ÀBÁÚÃtÅƬÈJÉéËŠÌÄÍ–ÎÑÐvÒÓÆÕpְ׆ØÈÚvÜ&ÝkÞDߊá?â‡ãbä¬åöæÓèékêIë(ìíVî¦ï†ðgñHò*ó óîôÐõ³ö–÷T÷ìø„ùBú'úæûüüžýý„ý÷þ¤ÿ‹ÿÿdesc Color LCDmluc nbNOèptPTúsvSEfiFI daDK0zhCN LfrFRXjaJPjenUSxplPLŠptBRœesES´zhTWÆruRU$ÔkoKR ødeDEnlNLitIT*Farge-LCDLCD a CoresFärg-LCDVäri-LCDLCD-farveskærm_i‚r LCDÉcran LCD0«0é0ü LCDColor LCDKolor LCDLCD ColoridoLCD color_i‚rm²fv˜oy:Vh&25B=>9 -48A?;59Îì·ì LCDFarb-LCDKleuren-LCDLCD colorimmodœW¿ø{€textCopyright Apple, Inc., 2010vmtk-1.0.1/distribution/nsis/vmtk-startup.bat0000664000175000017500000000036011757446472020012 0ustar lucalucarem @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 vmtk-1.0.1/distribution/nsis/mingw-postinst.bat0000664000175000017500000000053111757446472020333 0ustar lucaluca@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=! ) vmtk-1.0.1/PypeS/0000775000175000017500000000000011757446472012207 5ustar lucalucavmtk-1.0.1/PypeS/pyperun.py0000664000175000017500000000540211757446472014264 0ustar lucaluca#!/usr/bin/env python ## Program: PypeS ## Module: $RCSfile: pype.py,v $ ## Language: Python ## Date: $Date: 2006/07/07 10:45:42 $ ## Version: $Revision: 1.18 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys from multiprocessing import Process, Manager try: from vmtk import pypeserver from vmtk import pypes except: import os if sys.platform == 'darwin': ldEnvironmentVariable = "DYLD_LIBRARY_PATH" elif sys.platform == 'win32': ldEnvironmentVariable = "PATH" else: ldEnvironmentVariable = "LD_LIBRARY_PATH" currentEnviron = dict() currentEnviron[ldEnvironmentVariable] = "" currentEnviron["PYTHONPATH"] = "" if os.environ.has_key(ldEnvironmentVariable): currentEnviron[ldEnvironmentVariable] = os.environ[ldEnvironmentVariable] if os.environ.has_key("PYTHONPATH"): currentEnviron["PYTHONPATH"] = os.environ["PYTHONPATH"] newEnviron = {} vmtkhome = os.path.dirname(os.path.abspath(__file__)) if vmtkhome.endswith('bin'): vmtkhome = os.path.join(os.path.dirname(os.path.abspath(__file__)),"..") else: vmtkhome = os.path.join(os.path.dirname(os.path.abspath(__file__)),"..","..","..") vtkdir = [el for el in os.listdir(os.path.join(vmtkhome,"lib")) if el.startswith('vtk')][0] newEnviron[ldEnvironmentVariable] = os.path.join(vmtkhome,"bin") + os.path.pathsep + \ os.path.join(vmtkhome,"lib",vtkdir) + os.path.pathsep + \ os.path.join(vmtkhome,"lib","vmtk") + os.path.pathsep + \ os.path.join(vmtkhome,"lib","InsightToolkit") os.environ[ldEnvironmentVariable] = newEnviron[ldEnvironmentVariable] + os.path.pathsep + currentEnviron[ldEnvironmentVariable] sys.path.append(os.path.join(vmtkhome,"bin","Python")) sys.path.append(os.path.join(vmtkhome,"lib",vtkdir)) sys.path.append(os.path.join(vmtkhome,"lib","vmtk")) from vmtk import pypeserver from vmtk import pypes if __name__=='__main__': manager = Manager() queue = manager.list() pypeProcess = Process(target=pypeserver.PypeServer, args=(queue,None), kwargs={"returnIfEmptyQueue":True}) pypeProcess.start() args = sys.argv[:] if sys.argv[0].startswith('pyperun'): args = sys.argv[1:] queue.append(args) try: pypeProcess.join() except KeyboardInterrupt: pypeProcess.terminate() except BaseException, e: print e vmtk-1.0.1/PypeS/pypetestrunner.py0000664000175000017500000001606311757446472015676 0ustar lucaluca#!/usr/bin/env python import vtk import sys from vmtk import pypes import unittest import datetime import traceback pypetestrunner = 'PypeTestRunner' class PypeTestCase(unittest.TestCase): def __init__(self,line,lineno): unittest.TestCase.__init__(self) self.Line = line self.LineNo = lineno self.Name = 'unavailable' def setUp(self): self.Pipe = pypes.Pype() self.Pipe.SetArgumentsString(self.Line) self.Pipe.LogOn = 0 def runTest(self): self.Pipe.ParseArguments() if self.Pipe.Arguments: self.Name = self.Pipe.Arguments[self.Pipe.Arguments.index('-name') + 1] self.Pipe.Execute() self.Log = self.Pipe.GetScriptObject('pypetest','0').PypeTestLog splitLog = self.Log.split('.') self.Result = splitLog[1] self.assertEqual(self.Result,'passed') class PypeTestResult(unittest.TestResult): def appendLogLine(self,logline): try: self.ResultList.append(logline) except: self.ResultList = [] self.ResultList.append(logline) def startTest(self,test): self.testLog = {'id':str(test.LineNo),'error':'None'} def stopTest(self,test): self.testLog['name'] = test.Name self.testLog['pype'] = test.Line self.testLog['date'] = datetime.datetime.now().strftime('%d-%m-%Y') self.testLog['time'] = datetime.datetime.now().strftime('%H:%M:%S') self.appendLogLine(self.testLog) self.testsRun += 1 def addError(self,test,err): self.testLog['result'] = 'error' self.testLog['error'] = err self.errors.append([test,err]) def addFailure(self,test,err): self.testLog['result'] = 'failed' self.testLog['error'] = err self.failures.append([test,err]) def addSuccess(self,test): self.testLog['result'] = 'passed' class PypeTestRunner(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.SuiteName = None self.TestSuiteFileName = None self.LogFileName = '' self.TestSuiteLog = '' self.Format = '' self.GuessFormat = 1 self.SetScriptName('pypetestrunner') self.SetScriptDoc('Run a set of tests from a given list') self.SetInputMembers([ ['SuiteName','name','str',1,'','name of the test suite'], ['TestSuiteFileName','testsuitefile','str',1,'','test suitefilename'], ['LogFileName','logfile','str',1,'','Log filename'], ['Format','f','str',1,'["text","xml"]','file format'], ['GuessFormat','guessformat','bool',1,'','guess file format from extension'], ]) self.SetOutputMembers([ ['TestSuiteLog','log','str',1,'','log'] ]) def WriteXMLLogFile(self): self.PrintLog('Writing XML Test Suite Log') from xml.dom import minidom xmlDocument = minidom.Document() xmlTestSuite = xmlDocument.appendChild(xmlDocument.createElement('TestSuite')) xmlTestSuite.setAttribute('name',self.SuiteName) xmlTestSuite.setAttribute('tests_run',str(self.Result.testsRun)) xmlTestSuite.setAttribute('tests_errors',str(len(self.Result.errors))) xmlTestSuite.setAttribute('tests_failed',str(len(self.Result.failures))) xmlTestSuite.setAttribute('date',self.Date) xmlTestSuite.setAttribute('time',self.Time) xmlTestSuite.setAttribute('outcome',self.Success) for case in self.Result.ResultList: xmlCase = xmlTestSuite.appendChild(xmlDocument.createElement('TestCase')) if case['error'] != 'None': caseError = case['error'] editedError = '' caseException = traceback.format_exception(caseError[0],caseError[1],caseError[2]) for line in caseException: editedError += line xmlCaseError = xmlCase.appendChild(xmlDocument.createElement('CaseError')) errorText = xmlDocument.createTextNode(editedError) xmlCaseError.appendChild(errorText) del case['error'] xmlCasePype = xmlCase.appendChild(xmlDocument.createElement('CasePype')) xmlCasePype.appendChild(xmlDocument.createTextNode(case['pype'])) del case['pype'] for k,v in case.iteritems(): xmlCase.setAttribute(k,v) xmlFile = open(self.LogFileName,'w') xmlFile.write(xmlDocument.toprettyxml()) xmlFile.close() def WriteTEXTLogFile(self): self.PrintLog('Writing TEXT Test Suite Log') txtDocument = open(self.LogFileName, 'w') txtDocument.write(self.TestSuiteLog) def Execute(self): self.PrintLog('Testing') if not self.TestSuiteFileName: self.PrintError('Error: No Test list.') if not self.SuiteName: self.PrintError('Error: No test name.') extensionFormats = {'txt':'text', 'xml':'xml'} self.Suite = unittest.TestSuite() self.Success = 'FAILED' lineno = 1 self.TestSuiteLog = '' with open(self.TestSuiteFileName) as suitefile: for line in suitefile.readlines(): if line.strip(): self.Suite.addTest(PypeTestCase(line,lineno)) lineno += 1 self.Result = PypeTestResult() self.Suite.run(self.Result) if self.Result.wasSuccessful(): self.Success = 'SUCCESS' self.TestSuiteLog += '\nID NAME RESULT' for case in self.Result.ResultList: resultline = '\n'+ case['id'] +' '+ case['name'] +' '+ case['result'] self.TestSuiteLog += resultline self.Date = datetime.datetime.now().strftime('%d-%m-%Y') self.Time = datetime.datetime.now().strftime('%H:%M:%S') self.TestSuiteLog += '\n\nTEST SUITE NAME: ' + self.SuiteName self.TestSuiteLog += '\nDATE: ' + self.Date self.TestSuiteLog += '\nTIME: ' + self.Time self.TestSuiteLog += '\nTOTAL TESTS RUN: ' + str(self.Result.testsRun) self.TestSuiteLog += '\nTOTAL TEST ERRORS: ' + str(len(self.Result.errors)) self.TestSuiteLog += '\nTOTAL TEST FAILURES: ' + str(len(self.Result.failures)) self.TestSuiteLog += '\nTEST SUITE OUTCOME: ' + self.Success if self.GuessFormat and self.LogFileName and not self.Format: import os.path extension = os.path.splitext(self.LogFileName)[1] if extension: extension = extension[1:] if extension in extensionFormats.keys(): self.Format = extensionFormats[extension] if self.LogFileName: if (self.Format == 'text'): self.WriteTEXTLogFile() elif (self.Format == 'xml'): self.WriteXMLLogFile() else: self.PrintError('Error: unsupported format '+ self.Format + '.') if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/PypeS/pypebatch.py0000664000175000017500000000713211757446472014543 0ustar lucaluca#!/usr/bin/env python ## Program: PypeS ## Module: $RCSfile: pypebatch.py,v $ ## Language: Python ## Date: $Date: 2005/09/14 09:47:30 $ ## Version: $Revision: 1.4 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import os import os.path class pypeBatch(object): def __init__(self): self.Arguments = [] self.Directory = '.' self.ScriptName = '' self.ScriptArguments = [] def GetUsageString(self): usageString = 'Usage: pypebatch -d directory scriptName scriptArguments ["pythonStringMethods"]' return usageString def PrintLog(self,logMessage,indent=0): indentUnit = ' ' indentation = '' for i in range(indent): indentation = indentation + indentUnit print indentation + logMessage def PrintError(self,logMessage): print logMessage def ParseArguments(self): state = 0 for arg in self.Arguments: if (arg == '--help'): self.PrintLog(self.GetUsageString()) sys.exit() elif (arg == '-d'): state = 1 elif (state == 1): self.Directory = arg state = 2 elif (state == 0): state == 2 elif (state == 2): if (self.ScriptName == ''): self.ScriptName = arg self.ScriptArguments.append(arg) def ReplaceFileNamesInScriptArguments(self,fileName): actualScriptArguments = [] for arg in self.ScriptArguments: if not ((arg[0]=='[') & (arg[-1]==']')): actualScriptArguments.append(arg) continue pattern = arg[1:-1] actualArgument = self.Directory + '/' if (pattern != ''): ## exec('actualArgument += fileName.' + pattern) actualArgument += fileName.__getattribute__(pattern) else: actualArgument += fileName actualScriptArguments.append(actualArgument) return actualScriptArguments def Execute(self): self.PrintLog('') moduleName = self.ScriptName exec('import '+ moduleName) scriptObjectClassName = '' exec ('scriptObjectClassName = '+moduleName+'.'+moduleName) moduleScriptObjectClassName = moduleName+'.'+scriptObjectClassName scriptObject = 0 fileNames = os.listdir(self.Directory) for fileName in fileNames: self.PrintLog('Creating ' + scriptObjectClassName + ' instance.') exec ('scriptObject = '+moduleScriptObjectClassName+'()') completeFileName = os.path.normpath(self.Directory + '/' + fileName) self.PrintLog('Replacing FileNames in ' + scriptObject.ScriptName + ' arguments') actualScriptArguments = self.ReplaceFileNamesInScriptArguments(fileName) scriptObject.Arguments = actualScriptArguments scriptObject.ParseArguments() scriptString = '' for arg in actualScriptArguments: scriptString += arg + ' ' self.PrintLog('Executing ' + scriptString) scriptObject.Execute() if __name__=='__main__': batch = pypeBatch() batch.Arguments = sys.argv batch.ParseArguments() batch.Execute() vmtk-1.0.1/PypeS/LICENCE0000664000175000017500000000300511757446472013172 0ustar lucalucaCopyright (c) 2004-2011, Luca Antiga, David Steinman All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. 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. 3. Neither the name of the Robarts Research Institute, of the Mario Negri Institute, 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. vmtk-1.0.1/PypeS/pypepad.py0000664000175000017500000005347711757446472014243 0ustar lucaluca#!/usr/bin/env python ## Program: Pype Pad ## Module: $RCSfile: pypepad.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:36:30 $ ## Version: $Revision: 1.6 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys from vmtk import pypes from vmtk import pypeserver from multiprocessing import Process, Manager class TkPadOutputStream(object): def __init__(self,tk_text_widget): self.text_widget = tk_text_widget self.output_to_file = False self.output_file = None def write(self,text): from Tkinter import NORMAL, END, DISABLED self.text_widget["state"] = NORMAL if text[0] == '\r': endline = str(int(self.text_widget.index(END).split('.')[0])-1) self.text_widget.delete(endline+".0",endline+".end") self.text_widget.update() text = text[1:] self.text_widget.insert(END,text) self.text_widget["state"] = DISABLED self.text_widget.see(END) self.text_widget.update() if self.output_to_file and self.output_file: self.output_file.write(text) self.output_file.flush() def flush(self): if self.output_to_file and self.output_file: self.output_file.flush() class TkPadInputStream(object): def __init__(self,tk_entry_widget,input_stream): self.entry_widget = tk_entry_widget self.entry_widget.bind("",self.EntryReturnHandler) self.text = '' self.input_stream = input_stream def EntryReturnHandler(self,event): from Tkinter import END, DISABLED self.text = self.entry_widget.get() self.entry_widget.delete(0,END) self.entry_widget.quit() self.entry_widget["state"] = DISABLED self.input_stream.write(self.text+'\n') def readline(self): from Tkinter import NORMAL self.entry_widget["state"] = NORMAL self.entry_widget.focus_set() self.entry_widget.grab_set() self.entry_widget.mainloop() self.entry_widget.grab_release() return self.text class CallbackShim: """Create a callback shim. Based on code by Scott David Daniels (which also handles keyword arguments). """ def __init__(self, callback, *firstArgs): self.__callback = callback self.__firstArgs = firstArgs def __call__(self, *args): return self.__callback (*(self.__firstArgs + args)) class PypeTkPad(object): def __init__(self, master, queue, pypeOutput): self.queue = queue self.pypeOutput = pypeOutput self.master = master self.master.title('PypePad') self.master.geometry("%dx%d%+d%+d" % (700, 700, 0, 0)) self.master.minsize(300, 100) self.output_file_name = None self.BuildMainFrame() self.UpdateOutput() def NewCommand(self): self.ClearAllCommand() def OpenCommand(self): import tkFileDialog from Tkinter import END openfile = tkFileDialog.askopenfile() if not openfile: return for line in openfile.readlines(): self.text_input.insert(END,line) def SaveCommand(self): import tkFileDialog from Tkinter import END saveasfile = tkFileDialog.asksaveasfile() if not saveasfile: return alltext = self.text_input.get("1.0",END) saveasfile.write(alltext) def QuitCommand(self): self.master.quit() def ClearInputCommand(self): from Tkinter import END self.text_input.delete("1.0",END) def ClearOutputCommand(self): from Tkinter import NORMAL, END, DISABLED self.text_output["state"] = NORMAL self.text_output.delete("1.0",END) self.text_output["state"] = DISABLED self.text_output.see(END) self.text_output.update() def ClearAllCommand(self): self.ClearInputCommand() self.ClearOutputCommand() def OutputFileCommand(self): import tkFileDialog outputfilename = tkFileDialog.asksaveasfilename() if sys.platform == 'win32' and len(outputfilename.split()) > 1: outputfilename = '"%s"' % outputfilename self.output_file_name = outputfilename def AboutCommand(self): self.OutputText('\n') self.OutputText('* PypePad, Copyright (c) Luca Antiga, David Steinman. *\n') self.OutputText('\n') def UpdateOutput(self): if self.pypeOutput: text = self.pypeOutput.pop(0) self.output_stream.write(text) self.master.after(10,self.UpdateOutput) def RunPype(self,arguments): if not arguments: return if self.output_to_file.get() is not 'n' and self.output_file_name: self.output_stream.output_to_file = True self.output_stream.output_file = open(self.output_file_name,self.output_to_file.get()) else: self.output_stream.output_to_file = False self.queue.append(arguments) def GetWordUnderCursor(self): from Tkinter import CURRENT splitindex = self.text_input.index(CURRENT).split('.') line = self.text_input.get(splitindex[0]+".0",splitindex[0]+".end") wordstart = line.rfind(' ',0,int(splitindex[1])-1)+1 wordend = line.find(' ',int(splitindex[1])) if wordend == -1: wordend = len(line) word = line[wordstart:wordend] return word def GetWordIndex(self): startindex = self.text_input.index("insert-1c wordstart") endindex = self.text_input.index("insert-1c wordend") if self.text_input.get(startindex+'-1c') == '-' and self.text_input.get(startindex+'-2c') == '-': startindex = self.text_input.index("insert-1c wordstart -2c") elif self.text_input.get(startindex+'-1c') == '-' and self.text_input.get(startindex+'-2c') == ' ': startindex = self.text_input.index("insert-1c wordstart -1c") self.wordIndex[0] = startindex self.wordIndex[1] = endindex word = self.text_input.get(self.wordIndex[0],self.wordIndex[1]) return word def GetLogicalLine(self,physicallineid): indexes, lines = self.GetLogicalLines() return lines[indexes[physicallineid]] def GetLogicalLineRange(self,physicallinefirstid,physicallinelastid): indexes, lines = self.GetLogicalLines() return lines[indexes[physicallinefirstid]:indexes[physicallinelastid]+1] def GetAllLogicalLines(self): return self.GetLogicalLines()[1] def GetLogicalLines(self): from Tkinter import END physicallines = self.text_input.get("1.0",END).split('\n') lines = [] indexes = [0] * len(physicallines) lineid = 0 previousline = "" join = 0 for line in physicallines: if line.startswith('#'): if join: indexes[lineid] = indexes[lineid-1] elif join: if line.endswith('\\'): lines[-1] = lines[-1] + " " + line[:-1] join = 1 else: lines[-1] = lines[-1] + " " + line join = 0 indexes[lineid] = indexes[lineid-1] else: if line.endswith('\\'): join = 1 lines.append(line[:-1]) else: lines.append(line) join = 0 if lineid > 0: indexes[lineid] = indexes[lineid-1]+1 lineid += 1 return indexes, lines def GetLineUnderCursor(self): from Tkinter import INSERT currentlineid = int(self.text_input.index(INSERT).split('.')[0]) - 1 return self.GetLogicalLine(currentlineid) def RunAllCommand(self): lines = self.GetAllLogicalLines() for line in lines: if line and line.strip(): self.RunPype(line) def RunLineCommand(self): line = self.GetLineUnderCursor() if line and line.strip(): self.RunPype(line) def RunSelectionCommand(self): from Tkinter import TclError, SEL_FIRST, SEL_LAST try: firstlineid = int(self.text_input.index(SEL_FIRST).split('.')[0]) - 1 lastlineid = int(self.text_input.index(SEL_LAST).split('.')[0]) - 1 lines = self.GetLogicalLineRange(firstlineid,lastlineid) for line in lines: self.RunPype(line) except TclError: pass def GetSuggestionsList(self,word): list = [] try: exec('import vmtkscripts') except ImportError: return None if word.startswith('--'): list = ['--pipe','--help'] elif word.startswith('-'): optionlist = [] scriptindex = self.text_input.search('vmtk',self.wordIndex[0],backwards=1) moduleName = self.text_input.get( scriptindex,scriptindex+' wordend' ) try: exec('import '+moduleName) exec('scriptObjectClassName = '+moduleName+'.'+moduleName) exec ('scriptObject = '+moduleName+'.'+scriptObjectClassName +'()') members = scriptObject.InputMembers + scriptObject.OutputMembers for member in members: optionlist.append('-'+member.OptionName) exec('list = [option for option in optionlist if option.count(word)]') except: return list else: exec('list = [scriptname for scriptname in vmtkscripts.__all__ if scriptname.count(word) ]') return list def FillSuggestionsList(self,word): from Tkinter import END self.suggestionslist.delete(0,END) suggestions = self.GetSuggestionsList(word) for suggestion in suggestions: self.suggestionslist.insert(END,suggestion) def ReplaceTextCommand(self,word): self.text_input.delete(self.wordIndex[0],self.wordIndex[1]) self.text_input.insert(self.wordIndex[0],word) self.text_input.focus_set() def ShowHelpCommand(self): word = self.GetWordUnderCursor() self.OutputText(word) if word: self.RunPype(word+' --help') else: self.OutputText('Enter your vmtk Pype above and Run.\n') def AutoCompleteCommand(self): word = self.GetWordIndex() self.suggestionswindow.withdraw() if word: self.FillSuggestionsList(word) self.suggestionswindow.geometry("%dx%d%+d%+d" % (400, 150, self.text_output.winfo_rootx(),self.text_output.winfo_rooty())) self.suggestionswindow.deiconify() self.suggestionswindow.lift() def InsertScriptName(self,scriptname): from Tkinter import INSERT self.text_input.insert(INSERT,scriptname+' ') def InsertFileName(self): from Tkinter import INSERT import tkFileDialog openfilename = tkFileDialog.askopenfilename() if not openfilename: return if len(openfilename.split()) > 1: openfilename = '"%s"' % openfilename self.text_input.insert(INSERT,openfilename+' ') def KeyPressHandler(self,event): if event.keysym == "Tab" : self.AutoCompleteCommand() self.suggestionslist.focus_set() self.suggestionslist.selection_set(0) return "break" else: self.text_input.focus_set() def TopKeyPressHandler(self,event): from Tkinter import ACTIVE, INSERT if event.keysym in ['Down','Up'] : self.suggestionslist.focus_set() elif event.keysym == "Return": word = self.suggestionslist.get(ACTIVE) self.ReplaceTextCommand(word) self.suggestionswindow.withdraw() self.text_input.focus_set() elif len(event.keysym) == 1 : self.suggestionswindow.withdraw() self.text_input.insert(INSERT,event.keysym) self.text_input.focus_set() else : self.suggestionswindow.withdraw() self.text_input.focus_set() def NewHandler(self,event): self.NewCommand() def OpenHandler(self,event): self.OpenCommand() def SaveHandler(self,event): self.SaveCommand() def InsertFileNameHandler(self,event): self.InsertFileName() return "break" def QuitHandler(self,event): self.QuitCommand() def ShowHelpHandler(self,event): self.ShowHelpCommand() def RunKeyboardHandler(self,event): from Tkinter import SEL_FIRST, TclError try: self.text_input.index(SEL_FIRST) self.RunSelectionCommand() except TclError: self.RunLineCommand() return "break" def RunAllHandler(self,event): self.RunAllCommand() def PopupHandler(self,event): try: self.popupmenu.tk_popup(event.x_root, event.y_root, 0) finally: self.popupmenu.grab_release() def OutputText(self,text): from Tkinter import NORMAL, END, DISABLED self.text_output["state"] = NORMAL self.text_output.insert(END,text) self.text_output["state"] = DISABLED def BuildScriptMenu(self,parentmenu,modulename): from Tkinter import Menu menu = Menu(parentmenu,bd=1,activeborderwidth=0) try: exec('import '+ modulename) except ImportError: return None scriptnames = [] exec ('scriptnames = [scriptname for scriptname in '+modulename+'.__all__]') menulength = 20 for i in range(len(scriptnames)/menulength+1): subscriptnames = scriptnames[i*menulength:(i+1)*menulength] if not subscriptnames: break submenu = Menu(menu,bd=1,activeborderwidth=0) menu.add_cascade(label=subscriptnames[0]+"...",menu=submenu) for scriptname in subscriptnames: callback = CallbackShim(self.InsertScriptName,scriptname) submenu.add_command(label=scriptname,command=callback) return menu def BuildMainFrame(self): from Tkinter import Menu, IntVar, StringVar, Toplevel, Listbox, Frame, PanedWindow, Text, Scrollbar, Entry from Tkinter import X, N, S, W, E, VERTICAL, TOP, END, DISABLED, RAISED menu = Menu(self.master,activeborderwidth=0,bd=0) self.master.config(menu=menu) filemenu = Menu(menu,tearoff=0,bd=1,activeborderwidth=0) menu.add_cascade(label="File", underline=0, menu=filemenu) filemenu.add_command(label="New", accelerator='Ctrl+N',command=self.NewCommand) filemenu.add_command(label="Open...",accelerator='Ctrl+O', command=self.OpenCommand) filemenu.add_command(label="Save as...",accelerator='Ctrl+S', command=self.SaveCommand) filemenu.add_separator() filemenu.add_command(label="Quit",accelerator='Ctrl+Q', command=self.QuitCommand) self.log_on = IntVar() self.log_on.set(1) self.output_to_file = StringVar() self.output_to_file.set('n') scriptmenu = Menu(menu,tearoff=0,bd=1,activeborderwidth=0) modulenames = ['vmtkscripts'] for modulename in modulenames: scriptsubmenu = self.BuildScriptMenu(menu,modulename) if scriptsubmenu: scriptmenu.add_cascade(label=modulename,menu=scriptsubmenu) editmenu = Menu(menu,tearoff=0,bd=1,activeborderwidth=0) menu.add_cascade(label="Edit",underline=0, menu=editmenu) editmenu.add_cascade(label="Insert script",menu=scriptmenu) editmenu.add_command(label="Insert file name", accelerator='Ctrl+F',command=self.InsertFileName) editmenu.add_separator() editmenu.add_command(label="Clear input", command=self.ClearInputCommand) editmenu.add_command(label="Clear output", command=self.ClearOutputCommand) editmenu.add_command(label="Clear all", command=self.ClearAllCommand) editmenu.add_separator() editmenu.add_checkbutton(label="Log", variable=self.log_on) editmenu.add_separator() editmenu.add_radiobutton(label="No output to file", variable=self.output_to_file,value='n') editmenu.add_radiobutton(label="Write output to file", variable=self.output_to_file,value='w') editmenu.add_radiobutton(label="Append output to file", variable=self.output_to_file,value='a') editmenu.add_command(label="Output file...", command=self.OutputFileCommand) runmenu = Menu(menu,tearoff=0,bd=1,activeborderwidth=0) menu.add_cascade(label="Run", underline=0, menu=runmenu) runmenu.add_command(label="Run all", command=self.RunAllCommand) runmenu.add_command(label="Run current line", command=self.RunLineCommand) runmenu.add_command(label="Run selection", command=self.RunSelectionCommand) helpmenu = Menu(menu,tearoff=0,bd=1,activeborderwidth=0) menu.add_cascade(label="Help", underline=0, menu=helpmenu) helpmenu.add_command(label="Help", underline=0, accelerator='F1',command=self.ShowHelpCommand) helpmenu.add_command(label="About", underline=0, command=self.AboutCommand) self.master.bind("", self.QuitHandler) self.master.bind("", self.NewHandler) self.master.bind("", self.OpenHandler) self.master.bind("", self.SaveHandler) self.master.bind("", self.InsertFileNameHandler) self.master.bind("", self.ShowHelpHandler) self.master.bind("", self.KeyPressHandler) self.wordIndex = ['1.0','1.0'] self.suggestionswindow = Toplevel(bg='#ffffff',bd=0,height=50,width=600,highlightthickness=0,takefocus=True) self.suggestionswindow.overrideredirect(1) self.suggestionslist = Listbox(self.suggestionswindow,bg='#ffffff',bd=1,fg='#336699',activestyle='none',highlightthickness=0,height=9) self.suggestionslist.insert(END,"foo") self.suggestionslist.pack(side=TOP,fill=X) self.suggestionswindow.bind("", self.TopKeyPressHandler) self.suggestionswindow.withdraw() self.master.rowconfigure(0,weight=1) self.master.columnconfigure(0,weight=1) content = Frame(self.master,bd=0,padx=2,pady=2) content.grid(row=0,column=0,sticky=N+S+W+E) content.rowconfigure(0,weight=1,minsize=50) content.rowconfigure(1,weight=0) content.columnconfigure(0,weight=1) panes = PanedWindow(content,orient=VERTICAL,bd=1,sashwidth=8,sashpad=0,sashrelief=RAISED,showhandle=True) panes.grid(row=0,column=0,sticky=N+S+W+E) frame1 = Frame(panes,bd=0) frame1.grid(row=0,column=0,sticky=N+S+W+E) frame1.columnconfigure(0,weight=1) frame1.columnconfigure(1,weight=0) frame1.rowconfigure(0,weight=1) panes.add(frame1,height=300,minsize=20) frame2 = Frame(panes,bd=0) frame2.grid(row=1,column=0,sticky=N+S+W+E) frame2.columnconfigure(0,weight=1) frame2.columnconfigure(1,weight=0) frame2.rowconfigure(0,weight=1) panes.add(frame2,minsize=20) self.text_input = Text(frame1, bg='#ffffff',bd=1,highlightthickness=0) self.text_input.bind("", self.KeyPressHandler) self.text_input.bind("", self.PopupHandler) self.text_input.bind("", self.RunKeyboardHandler) self.input_scrollbar = Scrollbar(frame1,orient=VERTICAL,command=self.text_input.yview) self.text_input["yscrollcommand"] = self.input_scrollbar.set self.text_output = Text(frame2,state=DISABLED,bd=1,bg='#ffffff',highlightthickness=0) self.output_scrollbar = Scrollbar(frame2,orient=VERTICAL,command=self.text_output.yview) self.text_output["yscrollcommand"] = self.output_scrollbar.set self.text_entry = Entry(content,bd=1,bg='#ffffff',state=DISABLED,highlightthickness=0) self.text_input.focus_set() self.text_input.grid(row=0,column=0,sticky=N+S+W+E) self.input_scrollbar.grid(row=0,column=1,sticky=N+S+W+E) self.text_output.grid(row=0,column=0,sticky=N+S+W+E) self.output_scrollbar.grid(row=0,column=1,sticky=N+S+W+E) self.text_entry.grid(row=1,column=0,sticky=N+S+W+E) self.popupmenu = Menu(self.text_input, tearoff=1, bd=0) self.popupmenu.add_command(label="Context help", command=self.ShowHelpCommand) self.popupmenu.add_cascade(label="Insert script",menu=scriptmenu) self.popupmenu.add_command(label="Insert file name...", command=self.InsertFileName) self.popupmenu.add_separator() self.popupmenu.add_command(label="Run all", command=self.RunAllCommand) self.popupmenu.add_command(label="Run current line", command=self.RunLineCommand) self.popupmenu.add_command(label="Run selection", command=self.RunSelectionCommand) self.output_stream = TkPadOutputStream(self.text_output) self.input_stream = TkPadInputStream(self.text_entry,self.output_stream) def RunPypeTkPad(): manager = Manager() queue = manager.list() output = manager.list() pypeProcess = Process(target=pypeserver.PypeServer, args=(queue,output)) pypeProcess.start() from Tkinter import Tk root = Tk() app = PypeTkPad(root,queue,output) root.mainloop() pypeProcess.terminate() if __name__=='__main__': RunPypeTkPad() vmtk-1.0.1/PypeS/pypeserver.py0000664000175000017500000000340311757446472014765 0ustar lucaluca#!/usr/bin/env python ## Program: PypeServer ## Language: Python ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. from vmtk import pypes import time class OutputStream(object): def __init__(self,textList): self.textList = textList def write(self, text): self.textList.append(text) def flush(self): pass def RunPypeProcess(arguments, inputStream=None, outputStream=None, logOn=True): pipe = pypes.Pype() pipe.ExitOnError = 0 if inputStream: pipe.InputStream = inputStream if outputStream: pipe.OutputStream = outputStream pipe.LogOn = logOn pipe.LogOn = True if type(arguments) in [str,unicode]: pipe.SetArgumentsString(arguments) else: pipe.Arguments = arguments pipe.ParseArguments() try: pipe.Execute() except BaseException, e: print "Error from pype:", e del pipe def PypeServer(queue, output, returnIfEmptyQueue=False): outputStream = None if output != None: outputStream = OutputStream(output) while True: try: if queue: arguments = queue.pop(0) RunPypeProcess(arguments,outputStream=outputStream) elif returnIfEmptyQueue: return else: time.sleep(0.5) except IOError, e: print "Connection closed" break except KeyboardInterrupt, e: print "Connection closed" break vmtk-1.0.1/PypeS/CMakeLists.txt0000664000175000017500000000367611757446472014763 0ustar lucalucaPROJECT (PYPES) SET(PYPES_SRCS pypebatch.py pypepad.py pypeserver.py pypetest.py pypetestrunner.py pypewrapper.py pyperun.py ) SET(PYPES_BASE_SRCS pype.py pypescript.py pypes.py ) FOREACH (SCRIPT_FILE ${PYPES_BASE_SRCS}) CONFIGURE_FILE(${PYPES_SOURCE_DIR}/${SCRIPT_FILE} ${PYPES_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) ENDFOREACH (SCRIPT_FILE) IF(NOT PYPES_INSTALL_BIN_DIR) #SET(PYPES_INSTALL_BIN_DIR ${PYPES_INSTALL_ROOT}/bin) SET(PYPES_INSTALL_BIN_DIR bin) ENDIF(NOT PYPES_INSTALL_BIN_DIR) IF(NOT PYPES_MODULE_INSTALL_LIB_DIR) #SET(PYPES_MODULE_INSTALL_LIB_DIR ${PYPES_INSTALL_ROOT}/lib/vmtk/vmtk) SET(PYPES_MODULE_INSTALL_LIB_DIR lib/vmtk/vmtk) ENDIF(NOT PYPES_MODULE_INSTALL_LIB_DIR) FOREACH (SCRIPT_FILE ${PYPES_SRCS}) CONFIGURE_FILE(${PYPES_SOURCE_DIR}/${SCRIPT_FILE} ${PYPES_BINARY_DIR}/${SCRIPT_FILE} COPYONLY) ENDFOREACH (SCRIPT_FILE) #INSTALL_FILES(${PYPES_MODULE_INSTALL_LIB_DIR} .py ${PYPES_BASE_SRCS} ${PYPES_SRCS}) INSTALL(FILES ${PYPES_BASE_SRCS} ${PYPES_SRCS} DESTINATION ${PYPES_MODULE_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries) IF (NOT WIN32 AND NOT VMTK_MINIMAL_INSTALL) SET (STRIPPED_PYPES_SRCS) FOREACH (SCRIPT_FILE ${PYPES_SRCS}) STRING(REGEX REPLACE ".py" "" STRIPPED_SCRIPT_FILE ${SCRIPT_FILE}) # Rename script 'pype' to 'vmtk-pype' to avoid conflict # with /usr/bin/pype in package 'pype' in Debian. IF("${STRIPPED_SCRIPT_FILE}" STREQUAL "pype") SET(STRIPPED_SCRIPT_FILE "vmtk-pype") ENDIF("${STRIPPED_SCRIPT_FILE}" STREQUAL "pype") CONFIGURE_FILE(${PYPES_SOURCE_DIR}/${SCRIPT_FILE} ${PYPES_BINARY_DIR}/${STRIPPED_SCRIPT_FILE} COPYONLY) SET (STRIPPED_PYPES_SRCS ${STRIPPED_PYPES_SRCS} ${PYPES_BINARY_DIR}/${STRIPPED_SCRIPT_FILE}) ENDFOREACH (SCRIPT_FILE) #INSTALL_PROGRAMS(${PYPES_INSTALL_BIN_DIR} FILES ${STRIPPED_PYPES_SRCS}) INSTALL(PROGRAMS ${STRIPPED_PYPES_SRCS} DESTINATION ${PYPES_INSTALL_BIN_DIR} COMPONENT RuntimeExecutables) ENDIF (NOT WIN32 AND NOT VMTK_MINIMAL_INSTALL) vmtk-1.0.1/PypeS/pypescript.py0000664000175000017500000006550211757446472014773 0ustar lucaluca#!/usr/bin/env python ## Program: PypeS ## Module: $RCSfile: pypescript.py,v $ ## Language: Python ## Date: $Date: 2006/05/26 12:36:30 $ ## Version: $Revision: 1.18 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import string import os.path class pypeMember(object): def __init__(self,memberName,optionName,memberType,memberLength,memberRange='',memberDoc='',memberIO=''): self.MemberName = memberName self.OptionName = optionName self.MemberType = memberType self.MemberLength = memberLength self.MemberRange = memberRange self.MemberDoc = memberDoc self.MemberIO = memberIO self.MemberPipe = '' self.MemberValue = None self.ExplicitPipe = '' self.AutoPipe = 1 self.Pushed = 0 def IsInRange(self,value): if not self.MemberRange: return if self.MemberRange[0] == '[' and self.MemberRange[-1] == ']': parsedMemberRange = [eval(entry) for entry in self.MemberRange[1:-1].split(',')] if value in parsedMemberRange: return True if self.MemberRange[0] == '(' and self.MemberRange[-1] == ')': parsedMemberRange = [entry for entry in self.MemberRange[1:-1].split(',')] if len(parsedMemberRange) < 2: return False inRange = True if parsedMemberRange[0] and value < eval(parsedMemberRange[0]): inRange = False if parsedMemberRange[1] and value > eval(parsedMemberRange[1]): inRange = False return inRange return False def GetRangeEnumeration(self): if not self.MemberRange: return [] if self.MemberRange[0] == '[' and self.MemberRange[-1] == ']': parsedMemberRange = [eval(entry) for entry in self.MemberRange[1:-1].split(',')] return parsedMemberRange return [] def GetRangeValues(self): if not self.MemberRange: return [] if self.MemberRange[0] == '(' and self.MemberRange[-1] == ')': parsedMemberRange = [] for entry in self.MemberRange[1:-1].split(','): if entry != '': entry = eval(entry) else: entry = None parsedMemberRange.append(entry) if len(parsedMemberRange) == 2: parsedMemberRange.append(None) if len(parsedMemberRange) != 3: return [] return parsedMemberRange return [] def GetRangeRepresentation(self): if not self.MemberRange: return [] enumeration = self.GetRangeEnumeration() values = self.GetRangeValues() if enumeration: return 'in ' + str(enumeration) if values: representation = '' if values[0] != None: representation += '>= ' + str(values[0]) if values[1] != None: if representation: representation += ' and ' representation += '<= ' + str(values[1]) return representation class pypeScript(object): lastVisitedPath = '.' def __init__(self): self.BuiltinOptionTypes = ['int','str','float'] self.InputStream = sys.stdin self.OutputStream = sys.stdout self.ScriptName = '' self.ScriptDoc = '' self.Arguments = [] self.InputMembers = [] self.OutputMembers = [] self.Id = '0' self.Self = self self.Disabled = 0 idMember = pypeMember('Id','id','str',1,'','script id') idMember.AutoPipe = 0 self.InputMembers.append(idMember) self.OutputMembers.append(idMember) selfMember = pypeMember('Self','handle','self',1,'','handle to self') selfMember.AutoPipe = 0 self.InputMembers.append(selfMember) self.OutputMembers.append(selfMember) selfMember = pypeMember('Disabled','disabled','bool',1,'','disable execution and piping') selfMember.AutoPipe = 0 self.InputMembers.append(selfMember) self.ExitOnError = 1 self.LogOn = 1 self.Progress = 0 def PrintLog(self,logMessage,indent=0): if not self.LogOn: return indentUnit = ' ' indentation = '' for i in range(indent): indentation = indentation + indentUnit self.OutputStream.write(indentation + logMessage + '\n') def PrintError(self,errorMessage): self.OutputStream.write(errorMessage + '\n') if self.ExitOnError: self.Exit() else: raise RuntimeError def Exit(self): sys.exit() def OutputText(self,text): self.OutputStream.write(text) def OutputProgress(self,progress,percentStep): if int(100 * progress)/percentStep == int(100 * self.Progress)/percentStep: return self.Progress = progress self.OutputStream.write('\r') self.OutputStream.write('Progress: '+str(int(100 * self.Progress))+'%') self.OutputStream.flush() self.InputInfo('Progress: '+str(int(100 * self.Progress))+'%') def EndProgress(self): self.OutputStream.write('\n') def InputInfo(self,prompt=''): self.OutputText(prompt) try: self.InputStream.prompt(prompt) except: pass def InputText(self,prompt='',validator=None): self.OutputText(prompt) try: self.InputStream.prompt(prompt) except: pass text = self.InputStream.readline() if text: text = text.rstrip('\n') if validator: while not validator(text): self.OutputText(prompt) text = self.InputStream.readline() if text: text = text.rstrip('\n') return text def PrintMembers(self,members): for memberEntry in members: memberName = memberEntry.MemberName memberType = memberEntry.MemberType memberPipe = memberEntry.MemberPipe memberValue = self.__getattribute__(memberName) ## if memberPipe: ## self.__getattribute__("PrintLog")(memberName+' = '+memberPipe,1) if memberName == 'Self': pass elif (memberType in self.BuiltinOptionTypes + ["bool"]) or (memberType == 'list'): self.__getattribute__("PrintLog")(memberName+' = '+str(memberValue),1) elif memberValue: self.__getattribute__("PrintLog")(memberName+' = '+memberType,1) else: self.__getattribute__("PrintLog")(memberName+' = '+str(memberValue),1) def PrintInputMembers(self): self.PrintLog("Input " + self.ScriptName + " members:") self.PrintMembers(self.InputMembers) def PrintOutputMembers(self): self.PrintLog("Output " + self.ScriptName + " members:") self.PrintMembers(self.OutputMembers) def ConvertToPypeMembers(self,members): pypeMembers = [] for member in members: if type(member) == pypeMember: pypeMembers.append(member) elif type(member) == list: pypeMembers.append(pypeMember(*member)) return pypeMembers def SetInputMembers(self,membersToAppend): pypeMembersToAppend = self.ConvertToPypeMembers(membersToAppend) for member in pypeMembersToAppend: self.InputMembers.append(member) if member.MemberIO: filenameMember = pypeMember(self.GetIOInputFileNameMember(member.MemberName),self.GetIOFileNameOption(member.OptionName),'str',1,'','filename for the default ' + member.MemberName + ' reader') ## filenameMember.AutoPipe = 0 exec('self.'+filenameMember.MemberName+' = \'\'') self.InputMembers.append(filenameMember) def SetOutputMembers(self,membersToAppend): pypeMembersToAppend = self.ConvertToPypeMembers(membersToAppend) for member in pypeMembersToAppend: self.OutputMembers.append(member) if member.MemberIO: filenameMember = pypeMember(self.GetIOOutputFileNameMember(member.MemberName),self.GetIOFileNameOption(member.OptionName),'str',1,'','filename for the default ' + member.MemberName + ' writer') ## filenameMember.AutoPipe = 0 exec('self.'+filenameMember.MemberName+' = \'\'') self.InputMembers.append(filenameMember) def SetScriptName(self,scriptName): self.ScriptName = scriptName def SetScriptDoc(self,scriptDoc): self.ScriptDoc = scriptDoc def GetUsageString(self): usageString = '' scriptUsageString = os.path.splitext(self.ScriptName)[0] if self.ScriptDoc: scriptUsageString += ' : ' + self.ScriptDoc useTextWrap = 1 try: import textwrap except ImportError: useTextWrap = 0 else: textwrapper = textwrap.TextWrapper() textwrapper.initial_indent = '' textwrapper.subsequent_indent = ' ' if useTextWrap: usageString += textwrapper.fill(scriptUsageString) else: usageString += scriptUsageString for memberList in [self.InputMembers, self.OutputMembers]: if memberList == self.InputMembers : usageString += '\n' + ' ' + 'Input arguments:' elif memberList == self.OutputMembers : usageString += '\n' + ' ' + 'Output arguments:' for memberEntry in memberList: memberUsageString = '' indentation = ' ' if useTextWrap: textwrapper.initial_indent = indentation textwrapper.subsequent_indent = indentation + ' ' memberName = memberEntry.MemberName option = memberEntry.OptionName memberType = memberEntry.MemberType memberLength = memberEntry.MemberLength memberRange = memberEntry.MemberRange memberDoc = memberEntry.MemberDoc if option!='': default = 0 if memberLength == 0: memberUsageString += '-' + option + ' ' + memberName elif memberType in self.BuiltinOptionTypes + ["bool"]: default = self.__getattribute__(memberName) memberUsageString += '-' + option + ' ' + memberName + ' (' + memberType + ',' + str(memberLength) + ')' if memberRange: memberUsageString += " " + memberEntry.GetRangeRepresentation() if default != '': memberUsageString += '; default=' + str(default) else: memberUsageString += '-' + option + ' ' + memberName + ' (' + memberType + ',' + str(memberLength) + ')' if memberDoc != '': memberUsageString += ': ' + memberDoc if useTextWrap: usageString += '\n' + textwrapper.fill(memberUsageString) else: usageString += '\n' + memberUsageString usageString += '\n' return usageString def GetMarkdownUsageString(self): usageString = '' usageString += '---' + '\n' usageString += 'layout: default' + '\n' usageString += '---' + '\n' usageString += '

' usageString += self.ScriptName usageString += '

' usageString += '\n' if self.ScriptDoc != '': usageString += '

Description

' + '\n' usageString += self.ScriptDoc + '\n' for memberList in [self.InputMembers, self.OutputMembers]: if memberList == self.InputMembers : usageString += '

Input arguments

' + '\n' elif memberList == self.OutputMembers : usageString += '

Output arguments

' + '\n' usageString += '
' + '\n' usageString += '' + '\n' usageString += '\n' usageString += '' + '\n' for memberEntry in memberList: memberUsageString = '' memberName = memberEntry.MemberName option = memberEntry.OptionName memberType = memberEntry.MemberType memberLength = memberEntry.MemberLength memberRange = memberEntry.MemberRange memberDoc = memberEntry.MemberDoc if option!='': default = 0 if memberLength == 0: memberUsageString += '' elif memberType in self.BuiltinOptionTypes + ["bool"]: default = self.__getattribute__(memberName) memberUsageString += '' else: memberUsageString += '' if not memberDoc: memberDoc = '' memberUsageString += '' #memberUsageString += ' | ' memberUsageString += '\n' usageString += '' + memberUsageString + '' + '\n' usageString += '
ArgumentVariableTypeLengthRangeDefaultDescription
' + option + '' + memberName + '' + option + '' + memberName + '' + memberType + '' + str(memberLength) + '' + str(memberRange) + '' + str(default) + '' + option + '' + memberName + '' + memberType + '' + str(memberLength) + '' + memberDoc + '
' usageString += '\n' return usageString def GetDokuWikiUsageString(self): usageString = '' usageString = '======' usageString += self.ScriptName usageString += '======' usageString += '\n' if self.ScriptDoc != '': usageString += '=====Description=====' + '\n' usageString += self.ScriptDoc + '\n' for memberList in [self.InputMembers, self.OutputMembers]: if memberList == self.InputMembers : usageString += '=====Input arguments=====' + '\n' elif memberList == self.OutputMembers : usageString += '=====Output arguments=====' + '\n' usageString += '^ Argument ^ Variable ^ Type ^ Length ^ Range ^ Default ^ Description ^\n' for memberEntry in memberList: memberUsageString = '' memberName = memberEntry.MemberName option = memberEntry.OptionName memberType = memberEntry.MemberType memberLength = memberEntry.MemberLength memberRange = memberEntry.MemberRange memberDoc = memberEntry.MemberDoc if option!='': default = 0 if memberLength == 0: memberUsageString += '| ' + option + ' | ' + memberName + ' | | | | | ' elif memberType in self.BuiltinOptionTypes + ["bool"]: default = self.__getattribute__(memberName) memberUsageString += '| ' + option + ' | ' + memberName + ' | ' + memberType + ' | ' + str(memberLength) + ' | ' + str(memberRange) + ' | ' + str(default) + ' | ' else: memberUsageString += '| ' + option + ' | ' + memberName + ' | ' + memberType + ' | ' + str(memberLength) + ' | | | ' if memberDoc != '': memberUsageString += memberDoc memberUsageString += ' | ' memberUsageString += '\n' usageString += memberUsageString usageString += '\n' return usageString def GetPmWikiUsageString(self): usageString = 'version=pmwiki-2.2.0-beta65 ordered=1 urlencoded=1\n' usageString += 'name=VmtkScripts.' + self.ScriptName.capitalize() + '\n' usageString += 'text=' usageString += '!' + self.ScriptName usageString += '%0a' if self.ScriptDoc != '': usageString += '!!Description' + '%0a' usageString += self.ScriptDoc + '%0a' usageString += '%0a' for memberList in [self.InputMembers, self.OutputMembers]: if memberList == self.InputMembers : usageString += '!!Input arguments' + '%0a' elif memberList == self.OutputMembers : usageString += '!!Output arguments' + '%0a' usageString += '||border=1 cellpadding=3 cellspacing=0' + '%0a' usageString += '||!Argument ||!Variable ||!Type ||!Length ||!Range ||!Default ||!Description ||%0a' for memberEntry in memberList: memberUsageString = '' memberName = memberEntry.MemberName option = memberEntry.OptionName memberType = memberEntry.MemberType memberLength = memberEntry.MemberLength memberRange = memberEntry.MemberRange memberDoc = memberEntry.MemberDoc if option!='': default = 0 if memberLength == 0: memberUsageString += '||' + option + ' ||' + memberName + ' || || || || ||' elif memberType in self.BuiltinOptionTypes + ["bool"]: default = self.__getattribute__(memberName) memberUsageString += '||' + option + ' ||' + memberName + ' ||' + memberType + ' ||' + str(memberLength) + ' ||' + str(memberRange) + ' ||' + str(default) + ' ||' else: memberUsageString += '||' + option + ' ||' + memberName + ' ||' + memberType + ' ||' + str(memberLength) + ' || || ||' if memberDoc != '': memberUsageString += memberDoc memberUsageString += ' ||' memberUsageString += '%0a' usageString += memberUsageString usageString += '%0a' usageString += '%0a' return usageString def ParseArguments(self): for arg in self.Arguments: if arg == '--help': self.PrintLog('') self.OutputText(self.GetUsageString()) self.PrintLog('') return 0 if arg == '--markdown': self.PrintLog('') self.OutputText(self.GetMarkdownUsageString()) self.PrintLog('') return 0 if arg == '--dokuwiki': self.PrintLog('') self.OutputText(self.GetDokuWikiUsageString()) self.PrintLog('') return 0 if arg == '--pmwiki': self.PrintLog('') self.OutputText(self.GetPmWikiUsageString()) self.PrintLog('') return 0 if (arg[0] == '-') & (len(arg)==1): self.PrintError(self.ScriptName + ' error: unknown option ' + arg + '\n' + self.GetUsageString()) return 0 if (arg[0] == '-'): if (arg[1] in string.ascii_letters): matchingMembers = [member for member in self.InputMembers if member.OptionName in [arg.lstrip('-'), arg.lstrip('-').rstrip('@')]] if not matchingMembers: self.PrintError(self.ScriptName + ' error: unknown option ' + arg + '\n' + self.GetUsageString()) return 0 for memberEntry in self.InputMembers: if not memberEntry.OptionName: continue memberName = memberEntry.MemberName option = '-' + memberEntry.OptionName memberType = memberEntry.MemberType memberLength = memberEntry.MemberLength memberRange = memberEntry.MemberRange memberValues = [] activated = 0 explicitPipe = 0 specifiedOptions = [arg for arg in self.Arguments if (arg[0] == '-') and (arg[1] in string.ascii_letters + '-')] pushedOption = option + '@' if pushedOption in specifiedOptions: memberEntry.Pushed = 1 specifiedOptions[specifiedOptions.index(pushedOption)] = option self.Arguments[self.Arguments.index(pushedOption)] = option if option in specifiedOptions: if memberLength == 0: activated = 1 optionValues = [] optionIndex = self.Arguments.index(option) if option != specifiedOptions[-1]: nextOptionIndex = self.Arguments.index(specifiedOptions[specifiedOptions.index(option)+1]) optionValues = self.Arguments[optionIndex+1:nextOptionIndex] else: optionValues = self.Arguments[optionIndex+1:] for value in optionValues: if value[0] == '@': memberEntry.ExplicitPipe = value[1:] if value[1:] == '': memberEntry.ExplicitPipe = 'None' else: if memberType in self.BuiltinOptionTypes: exec('castValue = '+memberType+'(\''+value+'\')') memberValues.append(castValue) elif memberType is 'bool': exec('castValue = int(\''+value+'\')') memberValues.append(castValue) else: memberValues.append(value) else: continue if memberLength != -1: if (len(memberValues) != memberLength) and not memberEntry.ExplicitPipe: self.PrintError('Error for option '+option+': '+str(len(memberValues))+' entries given, '+str(memberLength)+' expected.\n\n'+self.GetUsageString()) return 0 if len(memberValues) > 0: if (memberLength==0): if (activated == 1): setattr(self,memberName,1) memberEntry.MemberValue = 1 elif (memberLength==1): setattr(self,memberName,memberValues[0]) memberEntry.MemberValue = memberValues[0] else: setattr(self,memberName,memberValues) memberEntry.MemberValue = memberValues if memberType is 'bool': if [value for value in memberValues if value not in [0,1]]: self.PrintError('Error for option '+option+': should be either 0 or 1\n\n'+self.GetUsageString()) return 0 if memberRange != '': if [value for value in memberValues if not memberEntry.IsInRange(value)]: self.PrintError('Error for option '+option+': should be ' + memberEntry.GetRangeRepresentation() + '\n\n'+self.GetUsageString()) return 0 if (memberType != ''): if (memberLength==0): if activated: self.PrintLog(memberName + ' = ' + 'on',1) else: self.PrintLog(memberName + ' = ' + 'off',1) else: if (memberLength==-1): memberLength = len(memberValues) if memberEntry.ExplicitPipe: self.PrintLog(memberName+ ' = @' + memberEntry.ExplicitPipe,1) else: self.PrintLog(memberName+ ' = ' + str(self.__getattribute__(memberName)),1) return 1 def IORead(self): for member in self.InputMembers: if member.MemberIO: exec('filename = self.' + self.GetIOInputFileNameMember(member.MemberName)) if filename: try: exec('import ' + member.MemberIO) except ImportError: self.PrintError('Cannot import module ' + member.MemberIO + ' required for reading ' + member.MemberName) exec('readerName = ' + member.MemberIO + '.' + member.MemberIO) readerClassName = member.MemberIO + '.' + readerName exec('reader = ' + readerClassName + '()') reader.InputFileName = filename reader.LogOn = self.LogOn reader.InputStream = self.InputStream reader.OutputStream = self.OutputStream reader.Execute() exec('self.' + member.MemberName + ' = reader.Output') def IOWrite(self): for member in self.OutputMembers: if member.MemberIO: exec('filename = self.' + self.GetIOOutputFileNameMember(member.MemberName)) exec('input = self.' + member.MemberName) if filename: try: exec('import ' + member.MemberIO) except ImportError: self.PrintError('Cannot import module ' + member.MemberIO + ' required for writing ' + member.MemberIO) exec('writerName = ' + member.MemberIO + '.' + member.MemberIO) writerClassName = member.MemberIO + '.' + writerName exec('writer = ' + writerClassName + '()') writer.Input = input writer.OutputFileName = filename writer.LogOn = self.LogOn writer.InputStream = self.InputStream writer.OutputStream = self.OutputStream writer.Execute() def GetIOInputFileNameMember(self,memberName): return memberName + 'InputFileName' def GetIOOutputFileNameMember(self,memberName): return memberName + 'OutputFileName' def GetIOFileNameOption(self,optionName): return optionName + 'file' def Execute(self): pass def Deallocate(self): pass class pypeMain(object): def __init__(self): self.Arguments = None def Execute(self): import pype pipe = pype.Pype() pipe.Arguments = self.Arguments pipe.ParseArguments() pipe.Execute() vmtk-1.0.1/PypeS/pypes.py0000664000175000017500000000045111757446472013721 0ustar lucaluca#!/usr/bin/env python __all__ = [ 'pypescript', 'pype', 'pypebatch' ] for item in __all__: exec('from '+item+' import *') vmtk-1.0.1/PypeS/pype.py0000664000175000017500000003251611757446472013545 0ustar lucaluca#!/usr/bin/env python ## Program: PypeS ## Module: $RCSfile: pype.py,v $ ## Language: Python ## Date: $Date: 2006/07/07 10:45:42 $ ## Version: $Revision: 1.18 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import os.path pype = 'Pype' class NullOutputStream(object): def __init__(self): pass def write(self,text): pass def flush(self): pass class Pype(object): def __init__(self): self.ScriptObjectList = [] self.ScriptList = [] self.AutoPipe = 1 self.LogOn = 1 self.ScriptName = 'pype' self.ExitOnError = 1 self.InputStream = sys.stdin self.OutputStream = sys.stdout self.Arguments = None def GetUsageString(self): usageString = 'Usage: pype --nolog --noauto --query firstScriptName -scriptOptionName scriptOptionValue --pipe secondScriptName -scriptOptionName scriptOptionValue -scriptOptionName @firstScriptName.scriptOptionName -id 2 --pipe thirdScriptName -scriptOptionName @secondScriptName-2.scriptOptionName' return usageString def SetOutputStreamToNull(self): self.OutputStream = NullOutputStream() def PrintLog(self,logMessage,indent=0): if not self.LogOn: return indentUnit = ' ' indentation = '' for i in range(indent): indentation = indentation + indentUnit self.OutputStream.write(indentation + logMessage + '\n') def PrintError(self,logMessage): self.OutputStream.write(logMessage + '\n') def SetArgumentsString(self,argumentsString): if '"' not in argumentsString: self.Arguments = argumentsString.split() import re quoteRe = re.compile('(\".*?\")') splitArguments = quoteRe.split(argumentsString) arguments = [] for splitArgument in splitArguments: arg = splitArgument if splitArgument.startswith('"') and splitArgument.endswith('"'): arg = splitArgument[1:-1] arguments.append(arg) else: arguments.extend(arg.strip().split()) if '"' in arg: self.PrintError('Error: non-matching quote found') self.Arguments = arguments def ParseArguments(self): self.ScriptList = [] arguments = self.Arguments[:] if os.path.basename(arguments[0]).strip() in ['pyperun']: arguments.remove(arguments[0]) pypeArguments = [] for arg in arguments: if arg[:2] == '--': pypeArguments.append(arg) else: break if '--help' in pypeArguments: self.PrintLog(self.GetUsageString()) return if '--noauto' in pypeArguments: self.AutoPipe = 0 if '--nolog' in pypeArguments: self.LogOn = 0 if '--query' in pypeArguments: queryScripts = arguments[arguments.index('--query')+1:] for queryScript in queryScripts: exec('import '+queryScript) exec('allScripts = '+queryScript+'.__all__') self.PrintLog('\n'.join(allScripts)) return for arg in pypeArguments: arguments.remove(arg) if 'FILE' in arguments: text = '' self.OutputStream.write('\nThe current pype contains filename placeholders identified by the string FILE.') self.OutputStream.write('\nEvery occcurence of FILE is meant to be replaced with an actual file path.\n') self.OutputStream.write('\nPress \'c\' to continue and be authomatically prompted for the required filenames.') self.OutputStream.write('\nPress \'e\' to exit. You can still edit your pype manually and run it back.\n\n') while text not in ['c','e']: self.OutputStream.write('> ') text = self.InputStream.readline().rstrip('\n') if text == 'e': return elif text =='c': while 'FILE' in arguments: arguments[arguments.index('FILE')] = 'BROWSER' while '--pipe' in arguments: scriptSlice = arguments[:arguments.index('--pipe')] self.ScriptList.append([os.path.splitext(os.path.split(scriptSlice[0])[1])[0],scriptSlice[1:]]) arguments = arguments[arguments.index('--pipe')+1:] scriptSlice = arguments[:] if not arguments: return self.ScriptList.append([os.path.splitext(os.path.split(scriptSlice[0])[1])[0],scriptSlice[1:]]) def GetCompatibleMember(self,member,script): pushedInputMembers = [scriptMember for scriptMember in script.InputMembers if scriptMember.Pushed] compatibleOutputMembers = [scriptMember for scriptMember in pushedInputMembers + script.OutputMembers if scriptMember.AutoPipe and (scriptMember.MemberName == member.MemberName) and (scriptMember.MemberType == member.MemberType)] if not compatibleOutputMembers: return None return compatibleOutputMembers[0] def AutoPipeScriptObject(self,scriptObject): self.PrintLog('Automatic piping ' + scriptObject.ScriptName) for memberEntry in scriptObject.InputMembers: if not memberEntry.AutoPipe: continue if memberEntry.MemberType == 'id': continue if memberEntry.MemberType == 'handle': continue candidateScriptObjectList = [candidateScriptObject for candidateScriptObject in self.ScriptObjectList if self.GetCompatibleMember(memberEntry,candidateScriptObject)] if not candidateScriptObjectList: continue pipedScriptObject = candidateScriptObjectList[-1] pipedMember = self.GetCompatibleMember(memberEntry,pipedScriptObject) memberEntry.MemberPipe = pipedScriptObject.ScriptName + '-' + str(pipedScriptObject.Id) + '.' + pipedMember.MemberName self.PrintLog(memberEntry.MemberName + ' = ' + memberEntry.MemberPipe,1) def GetScriptObject(self,scriptName,scriptId): for scriptObject in self.ScriptObjectList: if (scriptObject.ScriptName == scriptName) & (scriptObject.Id == scriptId): return scriptObject def ExplicitPipeScriptObject(self,scriptObject): self.PrintLog('Explicit piping ' + scriptObject.ScriptName) for memberEntry in scriptObject.InputMembers: memberName = memberEntry.MemberName option = memberEntry.OptionName memberType = memberEntry.MemberType if memberEntry.ExplicitPipe == 'None': memberEntry.MemberPipe = None exec ('scriptObject.'+memberEntry.MemberName+'= None') continue if memberEntry.ExplicitPipe: pipedArgument = memberEntry.ExplicitPipe splitPipedArgument = pipedArgument.split('.') if (len(splitPipedArgument)<2): self.PrintError('Error: invalid option piping: '+pipedArgument) upstreamPipedModuleName = splitPipedArgument[0] if not upstreamPipedModuleName: upstreamPipedModuleName = self.ScriptObjectList[-1].ScriptName upstreamPipedOption = '' if (len(splitPipedArgument) == 2): upstreamPipedOption = splitPipedArgument[1] else: self.PrintError('Error: invalid option piping: '+pipedArgument) upstreamPipedId = '' splitUpstreamPipedModuleName = upstreamPipedModuleName.split('-') if (len(splitUpstreamPipedModuleName) > 1): upstreamPipedModuleName = splitUpstreamPipedModuleName[-2] upstreamPipedId = splitUpstreamPipedModuleName[-1] if not upstreamPipedOption: self.PrintError('Error: invalid option piping: '+pipedArgument) candidateScriptObjectList = [] if upstreamPipedModuleName: candidateScriptObjectList = [candidateScriptObject for candidateScriptObject in self.ScriptObjectList if candidateScriptObject.ScriptName == upstreamPipedModuleName] if upstreamPipedId: candidateScriptObjectList = [candidateScriptObject for candidateScriptObject in candidateScriptObjectList if upstreamPipedId == candidateScriptObject.Id] if not candidateScriptObjectList: self.PrintError('Error: invalid option piping: '+pipedArgument) continue pipedScriptObject = candidateScriptObjectList[-1] candidatePipedMembers = [member for member in pipedScriptObject.OutputMembers + pipedScriptObject.InputMembers if upstreamPipedOption == member.OptionName] if not candidatePipedMembers: self.PrintError('Error: invalid option piping: '+pipedArgument) continue pipedMember = candidatePipedMembers[0] memberEntry.MemberPipe = pipedScriptObject.ScriptName + '-' + str(pipedScriptObject.Id) + '.' + pipedMember.MemberName self.PrintLog(memberName+' = '+memberEntry.MemberPipe,1) def PipeScriptObject(self,scriptObject): for memberEntry in [member for member in scriptObject.InputMembers if member.MemberPipe and not member.MemberValue]: pipedScriptName = memberEntry.MemberPipe.split('.')[0].split('-')[0] pipedScriptId = memberEntry.MemberPipe.split('.')[0].split('-')[1] pipedMemberName = memberEntry.MemberPipe.split('.')[1] previousScriptObjects = self.ScriptObjectList[:] if scriptObject in previousScriptObjects: previousScriptObjects = previousScriptObjects[:previousScriptObjects.index(scriptObject)] candidatePipedScriptObjects = [candidateScriptObject for candidateScriptObject in previousScriptObjects if (candidateScriptObject.ScriptName == pipedScriptName) and (candidateScriptObject.Id == pipedScriptId)] pipedScriptObject = candidatePipedScriptObjects[-1] exec ('scriptObject.'+memberEntry.MemberName+'='+'pipedScriptObject.'+pipedMemberName) def Execute(self): self.ScriptObjectList = [] for scriptNameAndArguments in self.ScriptList: self.PrintLog('') scriptName = scriptNameAndArguments[0] moduleName = scriptName scriptArguments = scriptNameAndArguments[1] imported = True try: exec('import '+ moduleName) except ImportError, e: self.PrintError('No module named ' + moduleName + '\n' + e) break scriptObjectClassName = '' exec ('scriptObjectClassName = '+moduleName+'.'+moduleName) moduleScriptObjectClassName = moduleName+'.'+scriptObjectClassName self.PrintLog('Creating ' + scriptObjectClassName + ' instance.') scriptObject = 0 exec ('scriptObject = '+moduleScriptObjectClassName+'()') scriptArguments = scriptNameAndArguments[1] scriptObject.Arguments = scriptArguments scriptObject.LogOn = self.LogOn if self.InputStream: scriptObject.InputStream = self.InputStream if self.OutputStream: scriptObject.OutputStream = self.OutputStream scriptObject.ExitOnError = self.ExitOnError if self.AutoPipe: self.AutoPipeScriptObject(scriptObject) self.PrintLog('Parsing options ' + scriptObject.ScriptName) execute = scriptObject.ParseArguments() if not execute: return if scriptObject.Disabled: self.PrintLog('\n' + scriptObject.ScriptName + ' is disabled. Bypassing it.') continue self.ExplicitPipeScriptObject(scriptObject) self.PipeScriptObject(scriptObject) scriptObject.PrintInputMembers() scriptObject.IORead() self.PrintLog('Executing ' + scriptObject.ScriptName + ' ...') scriptObject.Execute() self.PrintLog('Done executing ' + scriptObject.ScriptName + '.') scriptObject.IOWrite() scriptObject.PrintOutputMembers() self.ScriptObjectList.append(scriptObject) for scriptObject in self.ScriptObjectList: scriptObject.Deallocate() def PypeRun(arguments): pipe = Pype() pipe.ExitOnError = 0 pipe.SetArgumentsString(arguments) pipe.ParseArguments() pipe.Execute() return pipe if __name__=='__main__': from vmtk import pypes main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() # pipe = Pype() # pipe.Arguments = sys.argv # pipe.ParseArguments() # pipe.Execute() vmtk-1.0.1/PypeS/pypewrapper.py0000775000175000017500000003035511757446472015150 0ustar lucaluca#!/usr/bin/env python ## Program: PypeS ## Module: $RCSfile: pype.py,v $ ## Language: Python ## Date: $Date: 2006/07/07 10:45:42 $ ## Version: $Revision: 1.18 $ ## Copyright (c) Luca Antiga, David Steinman. All rights reserved. ## See LICENCE file 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. import sys import os.path from vmtk import pypes class PypeWrapper(object): def __init__(self): self.Mode = 'slicer3' self.XMLDescription = '' self.PypeTitle = '' self.PypeDescription = '' self.Contributor = '' self.ModuleFileName = '' self.Arguments = None self.ScriptList = [] self.ModulePipeArguments = [] self.AllExposedMembers = [] self.Indentation = ' ' def ParseArguments(self): if '--help' in self.Arguments: print 'hey!' return if '--pype' not in self.Arguments: print 'complain!' return if '--mode' in self.Arguments: self.Mode = self.Arguments[self.Arguments.index('--mode')+1] if '--title' in self.Arguments: self.PypeTitle = self.Arguments[self.Arguments.index('--title')+1] if '--description' in self.Arguments: self.PypeDescription = self.Arguments[self.Arguments.index('--description')+1] if '--contributor' in self.Arguments: self.Contributor = self.Arguments[self.Arguments.index('--contributor')+1] if '--modulefile' in self.Arguments: self.ModuleFileName = self.Arguments[self.Arguments.index('--modulefile')+1] arguments = self.Arguments[self.Arguments.index('--pype')+1:] self.ModulePipeArguments = arguments[:] while '--pipe' in arguments: scriptSlice = arguments[:arguments.index('--pipe')] self.ScriptList.append([os.path.splitext(os.path.split(scriptSlice[0])[1])[0],scriptSlice[1:]]) arguments = arguments[arguments.index('--pipe')+1:] scriptSlice = arguments[:] if not arguments: return self.ScriptList.append([os.path.splitext(os.path.split(scriptSlice[0])[1])[0],scriptSlice[1:]]) def Execute(self): ind = self.Indentation self.XMLDescription = '\n' self.XMLDescription += '\n' self.XMLDescription += ind + 'vmtk\n' self.XMLDescription += ind + '%s\n' % (self.PypeTitle) self.XMLDescription += ind + '%s\n' % (self.PypeDescription) self.XMLDescription += ind + '%s\n' % (self.Contributor) self.AllExposedMembers = [] for scriptNameAndArguments in self.ScriptList: self.XMLDescription += ind + '\n' scriptName = scriptNameAndArguments[0] moduleName = scriptName scriptArguments = scriptNameAndArguments[1] try: exec('from vmtk import '+ moduleName) except ImportError: print 'No module named ' + moduleName break scriptObjectClassName = '' exec ('scriptObjectClassName = '+moduleName+'.'+moduleName) self.XMLDescription += 2*ind + '\n' % (scriptObjectClassName) moduleScriptObjectClassName = moduleName+'.'+scriptObjectClassName scriptObject = 0 exec ('scriptObject = '+moduleScriptObjectClassName+'()') scriptArguments = scriptNameAndArguments[1] exposedArgumentNames = [argument.split('@')[0] for argument in scriptArguments if '@' in argument[1:]] exposedArgumentChannels = [argument.split('@')[1] for argument in scriptArguments if '@' in argument[1:]] exposedArgumentOptions = [scriptArguments[scriptArguments.index(argument)-1][1:] for argument in scriptArguments if '@' in argument[1:]] exposedOptionsToNamesAndChannels = {} for i in range(len(exposedArgumentOptions)): exposedOptionsToNamesAndChannels[exposedArgumentOptions[i]] = [exposedArgumentNames[i], exposedArgumentChannels[i]] exposedMembers = [] for member in scriptObject.InputMembers + scriptObject.OutputMembers: exec('member.MemberValue = scriptObject.'+member.MemberName) if exposedOptionsToNamesAndChannels.has_key(member.OptionName): member.ExposedName = exposedOptionsToNamesAndChannels[member.OptionName][0] member.ExposedChannel = exposedOptionsToNamesAndChannels[member.OptionName][1] exposedMembers.append(member) self.AllExposedMembers.append(member) for exposedMember in exposedMembers: memberXMLTag = '' memberXMLOptions = '' enumeration = exposedMember.GetRangeEnumeration() if exposedMember.MemberType == 'int': memberXMLTag = 'integer' elif exposedMember.MemberType == 'float': memberXMLTag = 'float' elif exposedMember.MemberType == 'str': memberXMLTag = 'string' if enumeration: memberXMLTag += '-enumeration' elif exposedMember.MemberType == 'bool': memberXMLTag = 'boolean' if exposedMember.MemberLength != 1: memberXMLTag += '-vector' if exposedMember.MemberType == 'vtkImageData': memberXMLTag = 'image' elif exposedMember.MemberType == 'vtkPolyData': memberXMLTag = 'geometry' if exposedMember.ExposedChannel == 'point': memberXMLTag = 'point' if exposedMember.MemberLength == -1: memberXMLOptions += 'multiple="true"' self.XMLDescription += 2*ind + '<%s>\n' % (memberXMLTag+' '+memberXMLOptions) self.XMLDescription += 3*ind + '%s\n' % (exposedMember.ExposedName) self.XMLDescription += 3*ind + '%s\n' % (exposedMember.ExposedName) self.XMLDescription += 3*ind + '\n' % (exposedMember.ExposedName) if exposedMember.MemberDoc: self.XMLDescription += 3*ind + '%s\n' % (exposedMember.MemberDoc) if exposedMember.MemberValue not in [None, [], '']: self.XMLDescription += 3*ind + '%s\n' % (str(exposedMember.MemberValue)) if enumeration: for element in enumeration: self.XMLDescription += 3*ind + '%s\n' % (str(element)) values = exposedMember.GetRangeValues() if values: self.XMLDescription += 3*ind + '\n' if values[0] != None: self.XMLDescription += 4*ind + '%s\n' % (str(values[0])) if values[1] != None: self.XMLDescription += 4*ind + '%s\n' % (str(values[1])) if values[2] != None: self.XMLDescription += 4*ind + '%s\n' % (str(values[2])) self.XMLDescription += 3*ind + '\n' if exposedMember.ExposedChannel in ['input','output']: self.XMLDescription += 3*ind + '%s\n' % (exposedMember.ExposedChannel) self.XMLDescription += 2*ind + '\n' % (memberXMLTag) self.XMLDescription += ind + '\n' self.XMLDescription += '\n' moduleFile = open(self.ModuleFileName,'w') moduleFile.write('#!/usr/bin/env python\n\n') moduleFile.write('xmlDescription = """') moduleFile.write(self.XMLDescription) moduleFile.write('"""\n') moduleFile.write('\n') moduleFile.write('pypeWrapperCommand = "%s"\n' % ' '.join(sys.argv)) moduleFile.write('\n') moduleFile.write('import sys\n') moduleFile.write('if "--xml" in sys.argv:\n') moduleFile.write(self.Indentation+'print xmlDescription\n') moduleFile.write(self.Indentation+'sys.exit(0)\n') moduleFile.write('\n') moduleFile.write('if "--logo" in sys.argv:\n') moduleFile.write(self.Indentation+'sys.exit(0)\n') moduleFile.write('\n') moduleFile.write('import sys\n') moduleFile.write('if "--pypewrapper" in sys.argv:\n') moduleFile.write(self.Indentation+'print pypeWrapperCommand\n') moduleFile.write(self.Indentation+'sys.exit(0)\n') moduleFile.write('\n') substModulePipeArguments = [] exposedMembersOrder = [] for argument in self.ModulePipeArguments: if '@' in argument[1:]: substModulePipeArguments.append(argument.split('@')[0]) else: substModulePipeArguments.append(argument) for exposedMember in self.AllExposedMembers: exposedMembersOrder.append(substModulePipeArguments.index(exposedMember.ExposedName)) if exposedMember.ExposedChannel in ['input','output']: substModulePipeArguments[substModulePipeArguments.index(exposedMember.ExposedName)-1] += 'file' substModulePipeArguments[substModulePipeArguments.index(exposedMember.ExposedName)] = '%s' sortedExposedMembersOrder = exposedMembersOrder[:] sortedExposedMembersOrder.sort() allOrderedExposedMemberNames = [] for position in sortedExposedMembersOrder: allOrderedExposedMemberNames.append(self.AllExposedMembers[exposedMembersOrder.index(position)].ExposedName) moduleFile.write('arguments = sys.argv[:]\n') moduleFile.write('\n') for exposedMember in self.AllExposedMembers: if exposedMember.MemberType is 'bool': moduleFile.write('%s = "0"\n' % exposedMember.ExposedName) moduleFile.write('if "--%s" in arguments:\n' % (exposedMember.ExposedName)) moduleFile.write(self.Indentation+'%s = "1"\n' % (exposedMember.ExposedName)) moduleFile.write(self.Indentation+'arguments.remove("--%s")\n' % exposedMember.ExposedName) moduleFile.write('%s = " ".join(%s.split(","))\n' % (exposedMember.ExposedName, exposedMember.ExposedName)) moduleFile.write('\n') else: moduleFile.write('%s = ""\n' % exposedMember.ExposedName) moduleFile.write('while "--%s" in arguments:\n' % (exposedMember.ExposedName)) moduleFile.write(self.Indentation+'index = arguments.index("--%s")\n' % (exposedMember.ExposedName)) moduleFile.write(self.Indentation+'if index != len(arguments)-1 and "--" not in arguments[index+1]:\n') moduleFile.write(2*self.Indentation+'if %s:\n' % exposedMember.ExposedName) moduleFile.write(3*self.Indentation+'%s += ","\n' % exposedMember.ExposedName) moduleFile.write(2*self.Indentation+'%s += arguments[index+1]\n' % exposedMember.ExposedName) moduleFile.write(2*self.Indentation+'arguments.remove(arguments[index+1])\n') moduleFile.write(self.Indentation+'arguments.remove("--%s")\n' % exposedMember.ExposedName) moduleFile.write('%s = " ".join(%s.split(","))\n' % (exposedMember.ExposedName, exposedMember.ExposedName)) moduleFile.write('\n') moduleFile.write('pipe = "%s" %% (%s)\n' % (' '.join(substModulePipeArguments),','.join(allOrderedExposedMemberNames))) moduleFile.write('\n') moduleFile.write('from vmtk import pypes\n') moduleFile.write('pypes.PypeRun(pipe)\n') moduleFile.write('\n') moduleFile.close() if __name__=='__main__': pipeLumper = PypeWrapper() pipeLumper.Arguments = sys.argv pipeLumper.ParseArguments() pipeLumper.Execute() vmtk-1.0.1/PypeS/pypetest.py0000664000175000017500000000570511757446472014445 0ustar lucaluca#!/usr/bin/env python import vtk import sys from vmtk import pypes pypetest = 'pypeTest' class pypeTest(pypes.pypeScript): def __init__(self): pypes.pypeScript.__init__(self) self.TestName = None self.PypeTestLog = '' self.TestInput = None self.Condition = None self.ConditionValue = None self.ConditionType = None self.SetScriptName('pypetest') self.SetScriptDoc('tests a script property against a condition') self.SetInputMembers([ ['TestName','name','str',1,'','name of the test'], ['TestInput','i','test',1,'','log'], ['Condition','condition','str',1,'["equalto","differentfrom","greaterthan","lessthan","nonnone"]','condition type'], ['ConditionValue','value','str',1,'','condition value'], ['ConditionType','type','str',1,'["str","int","float","bool"]','condition type'] ]) self.SetOutputMembers([ ['PypeTestLog','log','str',1,'','log'] ]) def castValue(self,val): if not self.ConditionType: self.PrintError('Error: No condition type.') if self.ConditionType == 'str': return str(val) elif self.ConditionType == 'int': return int(val) elif self.ConditionType == 'float': return float(val) elif self.ConditionType == 'bool': if val == True or val in ['1','True','true']: return True else: return False def Execute(self): self.PrintLog('Testing') if not self.TestName: self.PrintError('Error: No test name.') if self.TestInput == None: self.PrintError('Error: No test input.') if not self.Condition: self.PrintError('Error: No condition.') passed = False self.CompareLog = 'failed' if self.Condition == 'equalto': if self.ConditionValue and self.castValue(self.TestInput) == self.castValue(self.ConditionValue): passed = True elif self.Condition == 'differentfrom': if self.ConditionValue and self.castValue(self.TestInput) != self.castValue(self.ConditionValue): passed = True elif self.Condition == 'greaterthan': if self.ConditionValue and self.castValue(self.TestInput) > self.castValue(self.ConditionValue): passed = True elif self.Condition == 'lessthan': if self.ConditionValue and self.castValue(self.TestInput) < self.castValue(self.ConditionValue): passed = True elif self.Condition == 'nonnone': if self.TestInput != None : passed = True if passed: self.CompareLog = 'passed' self.PypeTestLog = "%s.%s" % (self.TestName, self.CompareLog) if __name__=='__main__': main = pypes.pypeMain() main.Arguments = sys.argv main.Execute() vmtk-1.0.1/CMakeInput/0000775000175000017500000000000011757446472013147 5ustar lucalucavmtk-1.0.1/CMakeInput/VMTKConfig.cmake.in0000775000175000017500000000131311757446472016466 0ustar lucaluca# Tell the user project where to find headers and libraries SET (VMTK_CPP_SOURCE_DIRS "@VMTK_SOURCE_DIR@/vtkVmtk") SET(VMTK_INCLUDE_DIRS ${VMTK_CPP_SOURCE_DIRS} ${VMTK_CPP_SOURCE_DIRS}/Common ${VMTK_CPP_SOURCE_DIRS}/ComputationalGeometry ${VMTK_CPP_SOURCE_DIRS}/DifferentialGeometry ${VMTK_CPP_SOURCE_DIRS}/IO ${VMTK_CPP_SOURCE_DIRS}/Misc ${VMTK_CPP_SOURCE_DIRS}/Segmentation "@VMTK_BINARY_DIR@" "@VMTK_BINARY_DIR@/vtkVmtk" ) SET(VMTK_BUILD_SETTINGS_FILE "@VMTK_BINARY_DIR@/VMTKBuildSettings.cmake" ) INCLUDE( "@VMTK_BINARY_DIR@/VMTKLibraryDepends.cmake" ) SET(VMTK_LIBRARY_DIRS "@VMTK_BINARY_DIR@/bin") SET(VMTK_USE_FILE "@VMTK_BINARY_DIR@/VMTKUse.cmake" ) vmtk-1.0.1/CMakeInput/VMTKUse.cmake.in0000775000175000017500000000051311757446472016016 0ustar lucalucaINCLUDE(CMakeImportBuildSettings) CMAKE_IMPORT_BUILD_SETTINGS("${VMTK_BUILD_SETTINGS_FILE}") INCLUDE_DIRECTORIES(${VMTK_INCLUDE_DIRS}) LINK_DIRECTORIES(${VMTK_LIBRARY_DIRS}) LINK_LIBRARIES(vtkvmtkCommon vtkvmtkComputationalGeometry vtkvmtkDifferentialGeometry vtkvmtkIO vtkvmtkITK vtkvmtkMisc vtkvmtkSegmentation tet) vmtk-1.0.1/README0000664000175000017500000000046211757446472012031 0ustar lucalucavmtk - the Vascular Modeling Toolkit ------------------------------------ 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. See www.vmtk.org for details. vmtk-1.0.1/__init__.py.in0000664000175000017500000000006211757446472013663 0ustar lucaluca#import pypes #import vtkvmtk #import vmtkscripts vmtk-1.0.1/vmtkApps/0000775000175000017500000000000011757446472012754 5ustar lucalucavmtk-1.0.1/vmtkApps/CerebralAneurysms/0000775000175000017500000000000011757446472016402 5ustar lucalucavmtk-1.0.1/vmtkApps/CerebralAneurysms/ParentVesselReconstruction/0000775000175000017500000000000011757446472023757 5ustar lucalucavmtk-1.0.1/vmtkApps/CerebralAneurysms/ParentVesselReconstruction/paralleltransportvoronoidiagram.py0000775000175000017500000004753411757446472033063 0ustar lucaluca#!/usr/bin/env python import vtk import sys import math from vmtk import vtkvmtk def ReadPolyData(filename): reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(filename) reader.Update() return reader.GetOutput() def WritePolyData(input,filename): writer = vtk.vtkXMLPolyDataWriter() writer.SetFileName(filename) writer.SetInput(input) writer.Write() def ExtractCylindricInterpolationVoronoiDiagram(cellId,pointId,cylinderRadius,voronoi,centerlines): isInside = 0 if (cellId == 0): cylinderTop = centerlines.GetPoint(pointId) cylinderCenter = centerlines.GetPoint(pointId-interpolationHalfSize) cylinderBottom = centerlines.GetPoint(pointId-interpolationHalfSize*2) else: cylinderTop = centerlines.GetPoint(pointId) cylinderCenter = centerlines.GetPoint(pointId+interpolationHalfSize) cylinderBottom = centerlines.GetPoint(pointId+interpolationHalfSize*2) interpolationDataset = vtk.vtkPolyData() interpolationDatasetPoints = vtk.vtkPoints() interpolationDatasetCellArray = vtk.vtkCellArray() maskArray = vtk.vtkIntArray() maskArray.SetNumberOfComponents(1) maskArray.SetNumberOfTuples(voronoi.GetNumberOfPoints()) maskArray.FillComponent(0,0) for i in range(voronoi.GetNumberOfPoints()): point = voronoi.GetPoint(i) isInside = IsPointInsideInterpolationCylinder(point,cylinderTop,cylinderCenter,cylinderBottom,cylinderRadius) if (isInside == 1): maskArray.SetTuple1(i,1) numberOfInterpolationPoints = ComputeNumberOfMaskedPoints(maskArray) radiusArray = vtk.vtkDoubleArray() radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(numberOfInterpolationPoints) radiusArray.SetName(radiusArrayName) radiusArray.FillComponent(0,0.0) count = 0 for i in range(voronoi.GetNumberOfPoints()): value = maskArray.GetTuple1(i) if (value == 1): interpolationDatasetPoints.InsertNextPoint(voronoi.GetPoint(i)) interpolationDatasetCellArray.InsertNextCell(1) interpolationDatasetCellArray.InsertCellPoint(count) radius = voronoi.GetPointData().GetArray(radiusArrayName).GetTuple1(i) radiusArray.SetTuple1(count,radius) count +=1 interpolationDataset.SetPoints(interpolationDatasetPoints) interpolationDataset.SetVerts(interpolationDatasetCellArray) interpolationDataset.GetPointData().AddArray(radiusArray) return interpolationDataset def IsPointInsideInterpolationCylinder(x,t,c,b,r): halfheigth = math.sqrt(vtk.vtkMath.Distance2BetweenPoints(b,t))/2.0 xc = [0.0,0.0,0.0] tb = [0.0,0.0,0.0] xc[0] = x[0]-c[0] xc[1] = x[1]-c[1] xc[2] = x[2]-c[2] tb[0] = t[0]-b[0] tb[1] = t[1]-b[1] tb[2] = t[2]-b[2] xcnorm = vtk.vtkMath.Norm(xc) vtk.vtkMath.Normalize(xc) vtk.vtkMath.Normalize(tb) alpha = math.acos(vtk.vtkMath.Dot(xc,tb)) parallelxc = xcnorm*math.cos(alpha) perpendicularxc = xcnorm*math.sin(alpha) thetamin = math.atan(r/halfheigth) thetamax = thetamin + (math.pi - 2*thetamin) inside = 0 if (thetamin<=alpha<=thetamax): if (abs(perpendicularxc)<=r): inside = 1 else: if (abs(parallelxc)<=halfheigth): inside = 1 return inside def ComputeNumberOfMaskedPoints(dataArray): numberOfPoints = 0 for i in range(dataArray.GetNumberOfTuples()): value = dataArray.GetTuple1(i) if (value ==1): numberOfPoints +=1 return numberOfPoints def VoronoiDiagramInterpolation(interpolationcellid,id0,id1,voronoiDataset0,voronoiDataset1,centerlines,direction): print 'Interpolating cells ',id0,id1 cellLine = ExtractLine(interpolationcellid,centerlines) startPoint = clippingPoints.GetPoint(id0) endPoint = clippingPoints.GetPoint(id1) startId = cellLine.FindPoint(startPoint) endId = cellLine.FindPoint(endPoint) if (direction == 1): gapStartId = startId + 1 gapEndId = endId - 1 arrivalId = gapEndId + 1 endSavingInterval = gapEndId + 1 step = 1 else: gapStartId = startId - 1 gapEndId = endId + 1 arrivalId = gapEndId - 1 endSavingInterval = gapEndId - 1 step = -1 numberOfGapPoints = int(math.fabs(gapEndId - gapStartId)) + 1 numberOfInterpolationPoints = voronoiDataset0.GetNumberOfPoints() numberOfCenterlinesPoints = cellLine.GetNumberOfPoints() numberOfAddedPoints = numberOfGapPoints*numberOfInterpolationPoints print 'from id ',gapStartId,'to id ',gapEndId,'; number of points added ',numberOfAddedPoints finalNewVoronoiPoints = vtk.vtkPoints() cellArray = vtk.vtkCellArray() finalRadiusArray = vtk.vtkDoubleArray() finalRadiusArray.SetNumberOfComponents(1) finalRadiusArray.SetNumberOfTuples(numberOfAddedPoints) finalRadiusArray.SetName(radiusArrayName) finalRadiusArray.FillComponent(0,0.0) count = 0 for i in range(numberOfInterpolationPoints): voronoiPoint = voronoiDataset0.GetPoint(i) voronoiPointRadius = voronoiDataset0.GetPointData().GetArray(radiusArrayName).GetTuple1(i) centerlinePointLocator = vtk.vtkPointLocator() centerlinePointLocator.SetDataSet(cellLine) centerlinePointLocator.BuildLocator() closestPointId = centerlinePointLocator.FindClosestPoint(voronoiPoint) closestPoint = cellLine.GetPoint(closestPointId) voronoiVector = [0.0,0.0,0.0] voronoiVector[0] = voronoiPoint[0] - closestPoint[0] voronoiVector[1] = voronoiPoint[1] - closestPoint[1] voronoiVector[2] = voronoiPoint[2] - closestPoint[2] voronoiVectorNorm = vtk.vtkMath.Norm(voronoiVector) rotationAngle = ComputeVoronoiVectorToCenterlineAngle(closestPointId,voronoiVector,cellLine) PTPoints = vtk.vtkPoints() for j in range(closestPointId,arrivalId,step): localtangent = [0.0,0.0,0.0] localnormal = [0.0,0.0,0.0] newVoronoiVector = [0.0,0.0,0.0] newVoronoiPoint = [0.0,0.0,0.0] transform = vtk.vtkTransform() point0 = [0.0,0.0,0.0] point0 = cellLine.GetPoint(j) if (j0): point2 = [0.0,0.0,0.0] cellLine.GetPoint(j-1,point2) localtangent[0] += point0[0] - point2[0] localtangent[1] += point0[1] - point2[1] localtangent[2] += point0[2] - point2[2] localnormal = cellLine.GetPointData().GetArray(parallelTransportNormalsArrayName).GetTuple3(j) localnormaldot = vtk.vtkMath.Dot(localtangent,localnormal) localtangent[0] -= localnormaldot*localnormal[0] localtangent[1] -= localnormaldot*localnormal[1] localtangent[2] -= localnormaldot*localnormal[2] vtk.vtkMath.Normalize(localtangent) transform.RotateWXYZ(rotationAngle,localtangent) transform.TransformNormal(localnormal,newVoronoiVector) vtk.vtkMath.Normalize(newVoronoiVector) newVoronoiPoint[0] = point0[0] + voronoiVectorNorm*newVoronoiVector[0] newVoronoiPoint[1] = point0[1] + voronoiVectorNorm*newVoronoiVector[1] newVoronoiPoint[2] = point0[2] + voronoiVectorNorm*newVoronoiVector[2] PTPoints.InsertNextPoint(newVoronoiPoint) numberOfPTPoints = PTPoints.GetNumberOfPoints() lastPTPoint = PTPoints.GetPoint(PTPoints.GetNumberOfPoints()-1) voronoiPointLocator = vtk.vtkPointLocator() voronoiPointLocator.SetDataSet(voronoiDataset1) voronoiPointLocator.BuildLocator() arrivalVoronoiPointId = voronoiPointLocator.FindClosestPoint(lastPTPoint) arrivalVoronoiPoint = voronoiDataset1.GetPoint(arrivalVoronoiPointId) arrivalVoronoiPointRadius = voronoiDataset1.GetPointData().GetArray(radiusArrayName).GetTuple1(arrivalVoronoiPointId) arrivalCenterlinePointLocator = vtk.vtkPointLocator() arrivalCenterlinePointLocator.SetDataSet(cellLine) arrivalCenterlinePointLocator.BuildLocator() arrivalCenterlineClosestPointId = arrivalCenterlinePointLocator.FindClosestPoint(arrivalVoronoiPoint) arrivalCenterlineClosestPoint = cellLine.GetPoint(arrivalCenterlineClosestPointId) arrivalVoronoiVector = [0.0,0.0,0.0] arrivalVoronoiVector[0] = arrivalVoronoiPoint[0] - arrivalCenterlineClosestPoint[0] arrivalVoronoiVector[1] = arrivalVoronoiPoint[1] - arrivalCenterlineClosestPoint[1] arrivalVoronoiVector[2] = arrivalVoronoiPoint[2] - arrivalCenterlineClosestPoint[2] arrivalVoronoiVectorNorm = vtk.vtkMath.Norm(arrivalVoronoiVector) radiusArray = ComputeSpline(voronoiPointRadius,arrivalVoronoiPointRadius,numberOfPTPoints) vectorNormArray = ComputeSpline(voronoiVectorNorm,arrivalVoronoiVectorNorm, numberOfPTPoints) if (direction==1): pointsToGap = gapStartId - closestPointId else: pointsToGap = closestPointId - gapStartId pointId = pointsToGap for k in range(gapStartId,endSavingInterval,step): ptpoint = PTPoints.GetPoint(pointsToGap) clpoint = cellLine.GetPoint(k) vector = [0.0,0.0,0.0] vector[0] = ptpoint[0] - clpoint[0] vector[1] = ptpoint[1] - clpoint[1] vector[2] = ptpoint[2] - clpoint[2] vtk.vtkMath.Normalize(vector) norm = vectorNormArray.GetTuple1(pointsToGap) newvector = [0.0,0.0,0.0] newvector[0] = norm*vector[0] newvector[1] = norm*vector[1] newvector[2] = norm*vector[2] newpoint = [0.0,0.0,0.0] newpoint[0] = clpoint[0] + newvector[0] newpoint[1] = clpoint[1] + newvector[1] newpoint[2] = clpoint[2] + newvector[2] finalNewVoronoiPoints.InsertNextPoint(newpoint) cellArray.InsertNextCell(1) cellArray.InsertCellPoint(count) finalRadiusArray.SetTuple1(count,radiusArray.GetTuple1(pointsToGap)) pointsToGap +=1 count +=1 return finalNewVoronoiPoints,finalRadiusArray def ExtractLine(cellid,centerlines): cell = vtk.vtkGenericCell() centerlines.GetCell(cellid,cell) numberOfPoints = cell.GetNumberOfPoints() line = vtk.vtkPolyData() cellArray = vtk.vtkCellArray() cellArray.InsertNextCell(numberOfPoints) linePoints = cell.GetPoints() ptnArray = vtk.vtkDoubleArray() ptnArray.SetNumberOfComponents(3) ptnArray.SetNumberOfTuples(numberOfPoints) ptnArray.SetName(parallelTransportNormalsArrayName) ptnArray.FillComponent(0,0.0) ptnArray.FillComponent(1,0.0) ptnArray.FillComponent(2,0.0) for i in range(numberOfPoints): cellArray.InsertCellPoint(i) normal = centerlines.GetPointData().GetArray(parallelTransportNormalsArrayName).GetTuple3(cell.GetPointId(i)) ptnArray.SetTuple3(i,normal[0],normal[1],normal[2]) line.SetPoints(linePoints) line.SetLines(cellArray) line.GetPointData().AddArray(ptnArray) return line def ComputeVoronoiVectorToCenterlineAngle(pointId,vector,centerline): point0 = [0.0,0.0,0.0] point1 = [0.0,0.0,0.0] point2 = [0.0,0.0,0.0] centerline.GetPoint(pointId,point0) centerline.GetPoint(pointId+1,point1) centerline.GetPoint(pointId-1,point2) tangent = [0.0,0.0,0.0] tangent[0] += point1[0]-point0[0] tangent[1] += point1[1]-point0[1] tangent[2] += point1[2]-point0[2] tangent[0] += point0[0]-point2[0] tangent[1] += point0[1]-point2[1] tangent[2] += point0[2]-point2[2] ptnnormal = centerline.GetPointData().GetArray(parallelTransportNormalsArrayName).GetTuple3(pointId) alpha = ComputeAngleBetweenVectors(ptnnormal,tangent,vector) return alpha def ComputeAngleBetweenVectors(normal,tangent,vector): #compute the tangent component orthogonal to normal otangent = [0.0,0.0,0.0] normalDot = vtk.vtkMath.Dot(tangent,normal) otangent[0] = tangent[0] - normalDot*normal[0] otangent[1] = tangent[1] - normalDot*normal[1] otangent[2] = tangent[2] - normalDot*normal[2] vtk.vtkMath.Normalize(otangent) #compute the vector component orthogonal to otangent, i.e. parallel to normal vtk.vtkMath.Normalize(vector) ovector = [0.0,0.0,0.0] vectorDot = vtk.vtkMath.Dot(vector,otangent) ovector[0] = vector[0] - vectorDot*otangent[0] ovector[1] = vector[1] - vectorDot*otangent[1] ovector[2] = vector[2] - vectorDot*otangent[2] vtk.vtkMath.Normalize(ovector) theta = vtkvmtk.vtkvmtkMath.AngleBetweenNormals(normal,ovector) theta = vtk.vtkMath.DegreesFromRadians(theta) cross = [0.0,0.0,0.0] vtk.vtkMath.Cross(ovector,normal,cross) tangentDot = vtk.vtkMath.Dot(otangent,cross) if (tangentDot<0.0): theta = -1.0*theta angle = -theta return angle def ComputeSpline(startValue,endValue,numberOfPoints): averageValue = (startValue + endValue)/2.0 averageId = int(numberOfPoints/2) splineArray = vtk.vtkDoubleArray() splineArray.SetNumberOfComponents(1) splineArray.SetNumberOfTuples(numberOfPoints) splineArray.FillComponent(0,0.0) spline = vtk.vtkCardinalSpline() spline.AddPoint(float(0),startValue) spline.AddPoint(float(averageId),averageValue) spline.AddPoint(float(numberOfPoints),endValue) spline.Compute() for i in range(numberOfPoints): splineArray.SetTuple1(i,spline.Evaluate(float(i))) return splineArray def InsertNewVoronoiPoints(oldDataset,newPoints,newArray): numberOfDatasetPoints = oldDataset.GetNumberOfPoints() numberOfNewPoints = newPoints.GetNumberOfPoints() numberOfNewVoronoiPoints = numberOfDatasetPoints + numberOfNewPoints newDataset = vtk.vtkPolyData() radiusArray = vtk.vtkDoubleArray() radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(numberOfNewVoronoiPoints) radiusArray.SetName(radiusArrayName) radiusArray.FillComponent(0,0.0) cellArray = vtk.vtkCellArray() points = vtk.vtkPoints() for i in range(numberOfDatasetPoints): point = [0.0,0.0,0.0] oldDataset.GetPoint(i,point) points.InsertNextPoint(point) cellArray.InsertNextCell(1) cellArray.InsertCellPoint(i) value = oldDataset.GetPointData().GetArray(radiusArrayName).GetTuple1(i) radiusArray.SetTuple1(i,value) for i in range(numberOfNewPoints): point = [0.0,0.0,0.0] newPoints.GetPoint(i,point) points.InsertNextPoint(point) cellArray.InsertNextCell(1) cellArray.InsertCellPoint(numberOfDatasetPoints+i) value = newArray.GetTuple1(i) radiusArray.SetTuple1(numberOfDatasetPoints+i,value) newDataset.SetPoints(points) newDataset.SetVerts(cellArray) newDataset.GetPointData().AddArray(radiusArray) return newDataset # ----------------------------------------------------------------------------------------- ## Program: clipvoronoidiagram.py ## Language: Python ## Date: 2012/02/27 ## Version: 1.0 ## Application: Cerebral Aneurysms - Parent Vessel Reconstruction ## Author: Marina Piccinelli ## Description: Given the parallel transport normal system defined on the interpolated ## centerlines computes the trajectory of Voronoi Diagram points from one end ## to the other of the empty area in the clipped Voronoi Diagram. Saves a new ## complete Voronoi Diagram and recalculates the model surface by merging of ## maximal inscribed spheres. Recommended use of smoothed clipped Voronoi ## Diagram. # ----------------------------------------------------------------------------------------- #SOME COMMON VMTK DATA ARRAY NAMES radiusArrayName = 'MaximumInscribedSphereRadius' parallelTransportNormalsArrayName = 'ParallelTransportNormals' #OPTIONS TO SET interpolationHalfSize = 3 polyBallImageSize = [90,90,90] #size of the image for the evaluation of the polyball function #inputfilenames: print 'USAGE:' print ' ./paralleltransportvoronoidiagram.py inputfilesDirectory caseID smoothVoronoi' print '' inputfiledirectory = sys.argv[1] ID = sys.argv[2] smoothedVoronoi = int(sys.argv[3]) print 'Inputfiles Directory ', inputfiledirectory print 'case ID ', ID print '' interpolatedCenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_interpolatedcl.vtp' patchCenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_patchcl.vtp' if smoothedVoronoi == 1: clippedVoronoiFilename = inputfiledirectory + '/' + ID + '/' + ID + '_smoothclippedvoronoi.vtp' else: clippedVoronoiFilename = inputfiledirectory + '/' + ID + '/' + ID + '_clippedvoronoi.vtp' clippingPointsFilename = inputfiledirectory + '/' + ID + '/' + ID + '_clippingpoints.vtp' #outputfilenames: completeVoronoiFilename = inputfiledirectory + '/' + ID + '/' + ID + '_completevoronoi.vtp' surfaceFilename = inputfiledirectory + '/' + ID + '/' + ID + '_reconstructedmodel.vtp' interpolatedCenterlines = ReadPolyData(interpolatedCenterlinesFilename) patchCenterlines = ReadPolyData(patchCenterlinesFilename) clippedVoronoi = ReadPolyData(clippedVoronoiFilename) clippingPoints = ReadPolyData(clippingPointsFilename) completeVoronoiDiagram = vtk.vtkPolyData() completeVoronoiDiagram.DeepCopy(clippedVoronoi) numberOfInterpolatedCenterlinesCells = interpolatedCenterlines.GetNumberOfCells() for j in range(1,numberOfInterpolatedCenterlinesCells+1): interpolationCellId = j-1 startId = 0 endId = j startCell = vtk.vtkGenericCell() patchCenterlines.GetCell(startId,startCell) startCellPointId = startCell.GetPointId(startCell.GetNumberOfPoints()-1) startCellPoint = patchCenterlines.GetPoint(startCellPointId) startCellPointRadius = patchCenterlines.GetPointData().GetArray(radiusArrayName).GetTuple1(startCellPointId) startCellPointHalfRadius = startCellPointRadius/7.0 startInterpolationDataset = ExtractCylindricInterpolationVoronoiDiagram(startId,startCellPointId,startCellPointRadius,clippedVoronoi,patchCenterlines) startHalfInterpolationDataset = ExtractCylindricInterpolationVoronoiDiagram(startId,startCellPointId,startCellPointHalfRadius,clippedVoronoi,patchCenterlines) endCell = vtk.vtkGenericCell() patchCenterlines.GetCell(endId,endCell) endCellPointId = endCell.GetPointId(0) endCellPoint = patchCenterlines.GetPoint(endCellPointId) endCellPointRadius = patchCenterlines.GetPointData().GetArray(radiusArrayName).GetTuple1(endCellPointId) endCellPointHalfRadius = endCellPointRadius/7.0 endInterpolationDataset = ExtractCylindricInterpolationVoronoiDiagram(endId,endCellPointId,endCellPointRadius,clippedVoronoi,patchCenterlines) endHalfInterpolationDataset = ExtractCylindricInterpolationVoronoiDiagram(endId,endCellPointId,endCellPointHalfRadius,clippedVoronoi,patchCenterlines) newVoronoiPoints, newVoronoiPointsMISR = VoronoiDiagramInterpolation(interpolationCellId,startId,endId,startInterpolationDataset,endHalfInterpolationDataset,interpolatedCenterlines,1) completeVoronoiDiagram = InsertNewVoronoiPoints(completeVoronoiDiagram,newVoronoiPoints,newVoronoiPointsMISR) newVoronoiPoints, newVoronoiPointsMISR = VoronoiDiagramInterpolation(interpolationCellId,endId,startId,endInterpolationDataset,startHalfInterpolationDataset,interpolatedCenterlines,0) completeVoronoiDiagram = InsertNewVoronoiPoints(completeVoronoiDiagram,newVoronoiPoints,newVoronoiPointsMISR) WritePolyData(completeVoronoiDiagram,completeVoronoiFilename) print 'Reconstructing Surface from Voronoi Diagram' modeller = vtkvmtk.vtkvmtkPolyBallModeller() modeller.SetInput(completeVoronoiDiagram) modeller.SetRadiusArrayName(radiusArrayName) modeller.UsePolyBallLineOff() modeller.SetSampleDimensions(polyBallImageSize) modeller.Update() marchingCube = vtk.vtkMarchingCubes() marchingCube.SetInput(modeller.GetOutput()) marchingCube.SetValue(0,0.0) marchingCube.Update() envelope = marchingCube.GetOutput() WritePolyData(envelope,surfaceFilename) vmtk-1.0.1/vmtkApps/CerebralAneurysms/ParentVesselReconstruction/clipvoronoidiagram.py0000775000175000017500000002250311757446472030226 0ustar lucaluca#!/usr/bin/env python import vtk import sys import math from vmtk import vtkvmtk def ReadPolyData(filename): reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(filename) reader.Update() return reader.GetOutput() def WritePolyData(input,filename): writer = vtk.vtkXMLPolyDataWriter() writer.SetInput(input) writer.SetFileName(filename) writer.Write() def MaskVoronoiDiagram(voronoi,centerlines): numberOfCenterlinesPatches = centerlines.GetNumberOfCells() numberOfVoronoiPoints = voronoi.GetNumberOfPoints() maskArray = vtk.vtkIntArray() maskArray.SetNumberOfComponents(1) maskArray.SetNumberOfTuples(numberOfVoronoiPoints) maskArray.FillComponent(0,0) for i in range(numberOfCenterlinesPatches): tangent,center,centerMISR = ComputePatchEndPointParameters(i,centerlines) MaskWithPatch(i,tangent,center,centerMISR,maskArray,centerlines,voronoi) maskedPoints = ComputeNumberOfMaskedPoints(maskArray) return maskArray def ComputePatchEndPointParameters(id,centerlines): point0 = [0.0,0.0,0.0] point1 = [0.0,0.0,0.0] tan = [0.0,0.0,0.0] radius0 = -1 cell = vtk.vtkGenericCell() centerlines.GetCell(id,cell) if (id == 0): point0 = cell.GetPoints().GetPoint(cell.GetNumberOfPoints()-1) point1 = cell.GetPoints().GetPoint(cell.GetNumberOfPoints()-2) radius0 = centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell.GetPointId(cell.GetNumberOfPoints()-1)) tan[0] = point1[0]-point0[0] tan[1] = point1[1]-point0[1] tan[2] = point1[2]-point0[2] vtk.vtkMath.Normalize(tan) else: point0 = cell.GetPoints().GetPoint(0) point1 = cell.GetPoints().GetPoint(1) radius0 = centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell.GetPointId(0)) tan[0] = point1[0]-point0[0] tan[1] = point1[1]-point0[1] tan[2] = point1[2]-point0[2] vtk.vtkMath.Normalize(tan) return tan, point0, radius0 def MaskWithPatch(id,t,c,r,maskArray,centerlines,voronoi): patch = ExtractPatch(id,centerlines) tubeFunction = vtkvmtk.vtkvmtkPolyBallLine() tubeFunction.SetInput(patch) tubeFunction.SetPolyBallRadiusArrayName(radiusArrayName) lastSphere = vtk.vtkSphere() lastSphere.SetRadius(r*1.5) lastSphere.SetCenter(c) for i in range(voronoi.GetNumberOfPoints()): point = [0.0,0.0,0.0] voronoiVector = [0.0,0.0,0.0] voronoi.GetPoint(i,point) voronoiVector[0] = point[0]-c[0] voronoiVector[1] = point[1]-c[1] voronoiVector[2] = point[2]-c[2] voronoiVectorDot = vtk.vtkMath.Dot(voronoiVector,t) tubevalue = tubeFunction.EvaluateFunction(point) spherevalue = lastSphere.EvaluateFunction(point) if (spherevalue<0.0) & (voronoiVectorDot<0.0): continue elif (tubevalue<=0.0): maskArray.SetTuple1(i,1) def ExtractPatch(id,centerlines): cell = vtk.vtkGenericCell() centerlines.GetCell(id,cell) numberOfPoints = cell.GetNumberOfPoints() line = vtk.vtkPolyData() cellArray = vtk.vtkCellArray() cellArray.InsertNextCell(numberOfPoints) linePoints = cell.GetPoints() radiusArray = vtk.vtkDoubleArray() radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(numberOfPoints) radiusArray.SetName(radiusArrayName) radiusArray.FillComponent(0,0.0) for i in range(numberOfPoints): cellArray.InsertCellPoint(i) radius = centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell.GetPointId(i)) radiusArray.SetTuple1(i,radius) line.SetPoints(linePoints) line.SetLines(cellArray) line.GetPointData().AddArray(radiusArray) return line def ComputeNumberOfMaskedPoints(dataArray): numberOfPoints = 0 for i in range(dataArray.GetNumberOfTuples()): value = dataArray.GetTuple1(i) if (value ==1): numberOfPoints +=1 return numberOfPoints def ExtractMaskedVoronoiPoints(voronoi,maskArray): numberOfPoints = ComputeNumberOfMaskedPoints(maskArray) maskedVoronoi = vtk.vtkPolyData() maskedPoints = vtk.vtkPoints() cellArray = vtk.vtkCellArray() radiusArray = vtk.vtkDoubleArray() radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(numberOfPoints) radiusArray.SetName(radiusArrayName) radiusArray.FillComponent(0,0.0) count = 0 for i in range(voronoi.GetNumberOfPoints()): point = [0.0,0.0,0.0] voronoi.GetPoint(i,point) pointRadius = voronoi.GetPointData().GetArray(radiusArrayName).GetTuple1(i) value = maskArray.GetTuple1(i) if (value ==1): maskedPoints.InsertNextPoint(point) radiusArray.SetTuple1(count,pointRadius) cellArray.InsertNextCell(1) cellArray.InsertCellPoint(count) count +=1 maskedVoronoi.SetPoints(maskedPoints) maskedVoronoi.SetVerts(cellArray) maskedVoronoi.GetPointData().AddArray(radiusArray) return maskedVoronoi def SmoothClippedVoronoiDiagram(voronoi,centerlines): numberOfPoints = voronoi.GetNumberOfPoints() numberOfCenterlinesPoints = centerlines.GetNumberOfPoints() maskArray = vtk.vtkIntArray() maskArray.SetNumberOfComponents(1) maskArray.SetNumberOfTuples(numberOfPoints) maskArray.FillComponent(0,0) for i in range(numberOfCenterlinesPoints): localRadius = centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(i) threshold = localRadius*(1.0 - smoothingFactor) sphere = vtk.vtkSphere() sphere.SetRadius(localRadius) sphere.SetCenter(centerlines.GetPoint(i)) localMaskArray = vtk.vtkIntArray() localMaskArray.SetNumberOfComponents(1) localMaskArray.SetNumberOfTuples(numberOfPoints) localMaskArray.FillComponent(0,0) for j in range(numberOfPoints): value = sphere.EvaluateFunction(voronoi.GetPoint(j)) if (value <= 0.0): localMaskArray.SetTuple1(j,1) for j in range(numberOfPoints): value = localMaskArray.GetTuple1(j) if (value==1): r = voronoi.GetPointData().GetArray(radiusArrayName).GetTuple1(j) if (r>threshold): maskArray.SetTuple1(j,1) finalNumberOfMaskedPoints = ComputeNumberOfMaskedPoints(maskArray) print 'from original number of points ', numberOfPoints,'to ',finalNumberOfMaskedPoints smoothedDiagram = vtk.vtkPolyData() points = vtk.vtkPoints() cellArray = vtk.vtkCellArray() radiusArray = vtk.vtkDoubleArray() radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(finalNumberOfMaskedPoints) radiusArray.FillComponent(0,0.0) radiusArray.SetName(radiusArrayName) count = 0 for i in range(numberOfPoints): value = maskArray.GetTuple1(i) if (value==1): radius = voronoi.GetPointData().GetArray(radiusArrayName).GetTuple1(i) points.InsertNextPoint(voronoi.GetPoint(i)) cellArray.InsertNextCell(1) cellArray.InsertCellPoint(count) radiusArray.SetTuple1(count,radius) count +=1 smoothedDiagram.SetPoints(points) smoothedDiagram.SetVerts(cellArray) smoothedDiagram.GetPointData().AddArray(radiusArray) return smoothedDiagram # ----------------------------------------------------------------------------------------- ## Program: clipvoronoidiagram.py ## Language: Python ## Date: 2012/02/27 ## Version: 1.0 ## Application: Cerebral Aneurysms - Parent Vessel Reconstruction ## Author: Marina Piccinelli ## Description: Keeps the Voronoi Diagram points around to the "patched" centerlines and ## removes all the rest. If smoothing option is selected (default and ## recommended) provides a smoothed version of Voronoi Diagram; points from ## the Voronoi Diagram are removed depending on the value of the maximum ## inscribed sphere radius. # ----------------------------------------------------------------------------------------- #SOME COMMON VMTK DATA ARRAY NAMES radiusArrayName = 'MaximumInscribedSphereRadius' #OPTIONS TO SET smoothVoronoiDiagram = 1 # recommended; perform smoothing of the Voronoi Diagram to ## remove smaller maximal spheres smoothingFactor = 0.25 # usually set to 0.25; the bigger the smoothing factor the ## smaller the number of removed spheres. #inputfilename: print 'USAGE:' print ' ./clipvoronoidiagram.py inputfilesDirectory caseID' print '' inputfiledirectory = sys.argv[1] ID = sys.argv[2] print 'Inputfiles Directory ', inputfiledirectory print 'case ID ', ID print '' voronoiDiagramFilename = inputfiledirectory + '/' + ID + '/' + ID + '_voronoi.vtp' patchCenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_patchcl.vtp' #outputfilenames: clippedVoronoiDiagramFilename = inputfiledirectory + '/' + ID + '/' + ID + '_clippedvoronoi.vtp' smoothVoronoiDiagramFilename = inputfiledirectory + '/' + ID + '/' + ID + '_smoothclippedvoronoi.vtp' originalVoronoiDiagram = ReadPolyData(voronoiDiagramFilename) patchCenterlines = ReadPolyData(patchCenterlinesFilename) print 'Clipping Voronoi Diagram' maskedVoronoiArray = MaskVoronoiDiagram(originalVoronoiDiagram,patchCenterlines) clippedVoronoiDiagram = ExtractMaskedVoronoiPoints(originalVoronoiDiagram,maskedVoronoiArray) WritePolyData(clippedVoronoiDiagram, clippedVoronoiDiagramFilename) if (smoothVoronoiDiagram==1): print 'Smoothing Voronoi Diagram', smoothVoronoiDiagram = SmoothClippedVoronoiDiagram(clippedVoronoiDiagram,patchCenterlines) WritePolyData(smoothVoronoiDiagram,smoothVoronoiDiagramFilename) vmtk-1.0.1/vmtkApps/CerebralAneurysms/ParentVesselReconstruction/patchandinterpolatecenterlines.py0000775000175000017500000004641211757446472032630 0ustar lucaluca#!/usr/bin/env python import vtk import sys import math from vmtk import vtkvmtk def ReadPolyData(filename): reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(filename) reader.Update() return reader.GetOutput() def WritePolyData(input,filename): writer = vtk.vtkXMLPolyDataWriter() writer.SetFileName(filename) writer.SetInput(input) writer.Write() def SaveParentArtery(centerlines): numberOfCells = centerlines.GetNumberOfCells() cell0 = centerlines.GetCell(0) numberOfArteryPoints = centerlines.GetNumberOfPoints()-cell0.GetNumberOfPoints() artery = vtk.vtkPolyData() arteryPoints = vtk.vtkPoints() arteryCellArray = vtk.vtkCellArray() radiusArray = vtk.vtkDoubleArray() radiusArray.SetName(radiusArrayName) radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(numberOfArteryPoints) radiusArray.FillComponent(0,0.0) count = 0 for i in range(1,numberOfCells): # cell0 is the one that goes to the aneurysm dome cell = vtk.vtkGenericCell() centerlines.GetCell(i,cell) arteryCellArray.InsertNextCell(cell.GetNumberOfPoints()) for j in range(cell.GetNumberOfPoints()): arteryPoints.InsertNextPoint(cell.GetPoints().GetPoint(j)) radiusArray.SetTuple1(count,centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell.GetPointId(j))) arteryCellArray.InsertCellPoint(count) count+=1 artery.SetPoints(arteryPoints) artery.SetLines(arteryCellArray) artery.GetPointData().AddArray(radiusArray) return artery def FindClippingPointOnParentArtery(centerlines,parentCenterlines,toll): divergingPointID = -1 divergingPoint = [0.0,0.0,0.0] divergingPointMISR = -1 clippingPointID = -1 clippingPoint = [0.0,0.0,0.0] cell0PointIds = vtk.vtkIdList() cell1PointIds = vtk.vtkIdList() centerlines.GetCellPoints(0,cell0PointIds) #this is the cl that goes through the aneurysm centerlines.GetCellPoints(1,cell1PointIds) for i in range(0,min(cell0PointIds.GetNumberOfIds(),cell1PointIds.GetNumberOfIds())): cell0Point = centerlines.GetPoint(cell0PointIds.GetId(i)) cell1Point = centerlines.GetPoint(cell1PointIds.GetId(i)) distanceBetweenPoints = math.sqrt(vtk.vtkMath.Distance2BetweenPoints(cell0Point,cell1Point)) if (distanceBetweenPoints>toll): divergingPointID = cell1PointIds.GetId(i) divergingPoint = centerlines.GetPoint(cell1PointIds.GetId(i)) divergingPointMISR = centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell1PointIds.GetId(i)) break MISphere = vtk.vtkSphere() MISphere.SetCenter(divergingPoint) MISphere.SetRadius(divergingPointMISR) tempPoint = [0.0,0.0,0.0] for i in range(divergingPointID,0,-1): value = MISphere.EvaluateFunction(centerlines.GetPoint(i)) if (value>=0.0): tempPoint = centerlines.GetPoint(i) break locator = vtk.vtkPointLocator() locator.SetDataSet(parentCenterlines) locator.BuildLocator() clippingPointID = locator.FindClosestPoint(tempPoint) clippingPoint = parentCenterlines.GetPoint(clippingPointID) return clippingPoint,divergingPoint def SaveClippingPoints(points,filename): pointSet = vtk.vtkPolyData() cellArray = vtk.vtkCellArray() for i in range(points.GetNumberOfPoints()): cellArray.InsertNextCell(1) cellArray.InsertCellPoint(i) pointSet.SetPoints(points) pointSet.SetVerts(cellArray) WritePolyData(pointSet,filename) def CreateParentArteryPatches(parentCenterlines,clipPoints): numberOfDaughterPatches = parentCenterlines.GetNumberOfCells() patchedCenterlines = vtk.vtkPolyData() patchedCenterlinesPoints = vtk.vtkPoints() patchedCenterlinesCellArray = vtk.vtkCellArray() patchedRadiusArray = vtk.vtkDoubleArray() clipIds,numberOfPatchedCenterlinesPoints = ExtractPatchesIds(parentCenterlines,clipPoints) print 'Clipping Point Ids ', clipIds radiusArray = vtk.vtkDoubleArray() radiusArray.SetNumberOfComponents(1) radiusArray.SetName(radiusArrayName) radiusArray.SetNumberOfTuples(numberOfPatchedCenterlinesPoints) radiusArray.FillComponent(0,0.0) numberOfCommonPatch = clipIds[0]+1 patchedCenterlinesCellArray.InsertNextCell(numberOfCommonPatch) count = 0 for i in range(0,numberOfCommonPatch): patchedCenterlinesPoints.InsertNextPoint(parentCenterlines.GetPoint(i)) patchedCenterlinesCellArray.InsertCellPoint(i) radiusArray.SetTuple1(i,parentCenterlines.GetPointData().GetArray(radiusArrayName).GetTuple1(i)) count+=1 for j in range(numberOfDaughterPatches): cell = vtk.vtkGenericCell() parentCenterlines.GetCell(j,cell) numberOfCellPoints = cell.GetNumberOfPoints() startId = clipIds[j+1] patchNumberOfPoints = numberOfCellPoints-startId patchedCenterlinesCellArray.InsertNextCell(patchNumberOfPoints) for i in range(startId, cell.GetNumberOfPoints()): point = cell.GetPoints().GetPoint(i) patchedCenterlinesPoints.InsertNextPoint(point) patchedCenterlinesCellArray.InsertCellPoint(count) radiusArray.SetTuple1(count,parentCenterlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell.GetPointId(i))) count+=1 patchedCenterlines.SetPoints(patchedCenterlinesPoints) patchedCenterlines.SetLines(patchedCenterlinesCellArray) patchedCenterlines.GetPointData().AddArray(radiusArray) return patchedCenterlines def ExtractPatchesIds(parentCl,clipPts): clipIds = [] numberOfPoints = 0 if (clipPts.GetNumberOfPoints() == 2): upstreamPoint = clipPts.GetPoint(0) downstreamPoint = clipPts.GetPoint(1) for j in range(parentCl.GetNumberOfCells()): cellLine = ExtractSingleLine(parentCl,j) locator = vtk.vtkPointLocator() locator.SetDataSet(cellLine) locator.BuildLocator() upstreamId = locator.FindClosestPoint(upstreamPoint) downstreamId = locator.FindClosestPoint(downstreamPoint) if j==0: clipIds.append(upstreamId) clipIds.append(downstreamId) numberOfPoints += upstreamId+1 numberOfPoints += cellLine.GetNumberOfPoints()-downstreamId else: clipIds.append(downstreamId) numberOfPoints += cellLine.GetNumberOfPoints()-downstreamId if (clipPts.GetNumberOfPoints() == 3): commonPoint = clipPts.GetPoint(0) dau1Point = clipPts.GetPoint(1) dau2Point = clipPts.GetPoint(2) for j in range(parentCl.GetNumberOfCells()): cellLine = ExtractSingleLine(parentCl,j) locator = vtk.vtkPointLocator() locator.SetDataSet(cellLine) locator.BuildLocator() if j==0: upstreamId = locator.FindClosestPoint(commonPoint) downstreamId = locator.FindClosestPoint(dau1Point) clipIds.append(upstreamId) clipIds.append(downstreamId) numberOfPoints += upstreamId+1 numberOfPoints += cellLine.GetNumberOfPoints()-downstreamId else: downstreamId = locator.FindClosestPoint(dau2Point) clipIds.append(downstreamId) numberOfPoints += cellLine.GetNumberOfPoints()-downstreamId return clipIds,numberOfPoints def ExtractSingleLine(centerlines,id): cell = vtk.vtkGenericCell() centerlines.GetCell(id,cell) line = vtk.vtkPolyData() points = vtk.vtkPoints() cellArray = vtk.vtkCellArray() cellArray.InsertNextCell(cell.GetNumberOfPoints()) radiusArray = vtk.vtkDoubleArray() radiusArray.SetName(radiusArrayName) radiusArray.SetNumberOfComponents(1) radiusArray.SetNumberOfTuples(cell.GetNumberOfPoints()) radiusArray.FillComponent(0,0.0) for i in range(cell.GetNumberOfPoints()): point = [0.0,0.0,0.0] point = cell.GetPoints().GetPoint(i) points.InsertNextPoint(point) cellArray.InsertCellPoint(i) radius = centerlines.GetPointData().GetArray(radiusArrayName).GetTuple1(cell.GetPointId(i)) radiusArray.SetTuple1(i,radius) line.SetPoints(points) line.SetLines(cellArray) line.GetPointData().AddArray(radiusArray) return line def InterpolatePatchCenterlines(patchCenterlines,parentCenterlines): additionalPoint = [-1.0,-1.0,-1.0] additionalPointIds = [] if (useAdditionalInterpolationPoint == 1): additionalPoint = divergingPoints.GetPoint(0) line1 = ExtractSingleLine(parentCenterlines,0) line2 = ExtractSingleLine(parentCenterlines,1) additionalPointIds.append(line1.FindPoint(additionalPoint)) additionalPointIds.append(line2.FindPoint(additionalPoint)) else: for i in range(parentCenterlines.GetNumberOfCells()): additionalPoint = clippingPoints.GetPoint(0) line1 = ExtractSingleLine(parentCenterlines,0) additionalPointIds.append(line1.FindPoint(additionalPoint)) interpolatedLines = vtk.vtkPolyData() interpolatedPoints = vtk.vtkPoints() interpolatedCellArray = vtk.vtkCellArray() pointsInserted = 0 interpolatedCellArray.Initialize() for i in range(parentCenterlines.GetNumberOfCells()): startingCell = vtk.vtkGenericCell() endingCell = vtk.vtkGenericCell() numberOfInterpolationPoints = parentCenterlines.GetCell(i).GetNumberOfPoints() patchCenterlines.GetCell(0,startingCell) patchCenterlines.GetCell(i+1,endingCell) splinePoints = InterpolateTwoCells(startingCell,endingCell,numberOfInterpolationPoints,additionalPointIds[i],additionalPoint) interpolatedCellArray.InsertNextCell(splinePoints.GetNumberOfPoints()) for j in range(splinePoints.GetNumberOfPoints()): interpolatedPoints.InsertNextPoint(splinePoints.GetPoint(j)) interpolatedCellArray.InsertCellPoint(pointsInserted + j) pointsInserted += splinePoints.GetNumberOfPoints() interpolatedLines.SetPoints(interpolatedPoints) interpolatedLines.SetLines(interpolatedCellArray) attributeFilter = vtkvmtk.vtkvmtkCenterlineAttributesFilter() attributeFilter.SetInput(interpolatedLines) attributeFilter.SetAbscissasArrayName(abscissasArrayName) attributeFilter.SetParallelTransportNormalsArrayName(parallelTransportNormalsArrayName) attributeFilter.Update() attributeInterpolatedLines = attributeFilter.GetOutput() return attributeInterpolatedLines def InterpolateTwoCells(startCell,endCell,numberOfSplinePoints,additionalPointId,additionalPoint): points = vtk.vtkPoints() xspline = vtk.vtkCardinalSpline() yspline = vtk.vtkCardinalSpline() zspline = vtk.vtkCardinalSpline() numberOfStartCellPoints = startCell.GetNumberOfPoints() numberOfEndCellPoints = endCell.GetNumberOfPoints() endCellFirstId = numberOfSplinePoints - numberOfEndCellPoints numberOfClippedCenterlinePoints = numberOfStartCellPoints + numberOfEndCellPoints for i in range(numberOfStartCellPoints): point = startCell.GetPoints().GetPoint(i) xspline.AddPoint(float(i),point[0]) yspline.AddPoint(float(i),point[1]) zspline.AddPoint(float(i),point[2]) if (useAdditionalInterpolationPoint == 1): xspline.AddPoint(float(additionalPointId),additionalPoint[0]) yspline.AddPoint(float(additionalPointId),additionalPoint[1]) zspline.AddPoint(float(additionalPointId),additionalPoint[2]) for i in range(numberOfEndCellPoints): point = endCell.GetPoints().GetPoint(i) index = endCellFirstId+i xspline.AddPoint(float(endCellFirstId + i),point[0]) yspline.AddPoint(float(endCellFirstId + i),point[1]) zspline.AddPoint(float(endCellFirstId + i),point[2]) xspline.Compute() yspline.Compute() zspline.Compute() points.SetNumberOfPoints(numberOfSplinePoints) for i in range(numberOfSplinePoints): points.SetPoint(i,xspline.Evaluate(float(i)),yspline.Evaluate(float(i)),zspline.Evaluate(float(i))) return points # ----------------------------------------------------------------------------------------- ## Program: patchandinterpolatecenterlines.py ## Language: Python ## Date: 2012/02/27 ## Version: 1.0 ## Application: Cerebral Aneurysms - Parent Vessel Reconstruction ## Author: Marina Piccinelli ## Description: Given centerlines traveling along parent vessels and to the aneurysm ## dome, identifies clipping points on centerlines delimiting aneurysm, ## eliminates the portion of centerlines within clipping points and ## interpolates with cubic splines the empty regions. It is possible to ## directly provide clipping points and parent vasculature centerlines. # ----------------------------------------------------------------------------------------- #SOME COMMON VMTK DATA ARRAY NAMES radiusArrayName = 'MaximumInscribedSphereRadius' abscissasArrayName = 'Abscissas' parallelTransportNormalsArrayName = 'ParallelTransportNormals' #OPTIONS TO SET useAdditionalInterpolationPoint = 0 # automatically set to 1 for terminal aneurysms setClippingPoints = 0 # set to 1 if clipping points will be provided not computed from the centerlines divergingRatioToSpacingTolerance = 2.0 # commonly 2.0; the DivergingTolerange for the identification of diverging points on each couple of centerlines is computed as (centerlineSpacing / DivergingRatioToSpacingTolerance) #inputfilename: print 'USAGE:' print ' ./patchandinterpolatecenterlines.py inputfilesDirectory caseID aneurysmType' print '' inputfiledirectory = sys.argv[1] ID = sys.argv[2] aneurysmType = sys.argv[3] print 'Inputfiles Directory ', inputfiledirectory print 'case ID ', ID print 'Aneurysm Type ', aneurysmType print '' # outputfilenames: divergingPointsFilename = inputfiledirectory + '/' + ID + '/' + ID + '_divergingpoints.vtp' patchParentArteryFilename = inputfiledirectory + '/' + ID + '/' + ID + '_patchcl.vtp' interpolatedCenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_interpolatedcl.vtp' if (aneurysmType == 'lateral'): if (setClippingPoints == 0): forwardCenterlinesFilename = inputfiledirectory + '/' + ID + '/'+ ID + '_forwardcl.vtp' backwardCenterlinesFilename = inputfiledirectory + '/' + ID + '/'+ ID + '_backwardcl.vtp' clippingPointsFilename = inputfiledirectory + '/' + ID + '/' + ID + '_clippingpoints.vtp' forwardCenterlines = ReadPolyData(forwardCenterlinesFilename) backwardCenterlines = ReadPolyData(backwardCenterlinesFilename) parentArteryCenterlines = SaveParentArtery(forwardCenterlines) centerlineSpacing = math.sqrt(vtk.vtkMath.Distance2BetweenPoints(parentArteryCenterlines.GetPoint(10),parentArteryCenterlines.GetPoint(11))) divergingTolerance = centerlineSpacing/divergingRatioToSpacingTolerance upstreamClippingPoint = [0.0,0.0,0.0] downstreamClippingPoint = [0.0,0.0,0.0] clippingPoints = vtk.vtkPoints() divergingPoints = vtk.vtkPoints() print 'Computing Clipping Points' upstreamClippingPoint,upstreamDivergingPoint = FindClippingPointOnParentArtery(forwardCenterlines,parentArteryCenterlines,divergingTolerance) clippingPoints.InsertNextPoint(upstreamClippingPoint) divergingPoints.InsertNextPoint(upstreamDivergingPoint) downstreamClippingPoint,downstreamDivergingPoint = FindClippingPointOnParentArtery(backwardCenterlines,parentArteryCenterlines,divergingTolerance) for i in range(parentArteryCenterlines.GetNumberOfCells()): clippingPoints.InsertNextPoint(downstreamClippingPoint) divergingPoints.InsertNextPoint(downstreamDivergingPoint) SaveClippingPoints(clippingPoints,clippingPointsFilename) SaveClippingPoints(divergingPoints,divergingPointsFilename) elif (setClippingPoints == 1): print 'Clipping Points and Parent Vessel Centerlines provided' parentArteryFileName = inputfiledirectory + '/' + ID + '/' + ID + '_parentvessel.vtp' clippingPointsFileName = inputfiledirectory + '/' + ID + '/' + ID + '_clippingpoints.vtp' clippingPoints = ReadPolyData(clippingPointsFileName) parentArteryCenterlines = ReadPolyData(parentArteryFileName) print 'Creating Patched Centerlines' patchParentArteryCenterlines = CreateParentArteryPatches(parentArteryCenterlines,clippingPoints) WritePolyData(patchParentArteryCenterlines,patchParentArteryFilename) print 'Interpolating Patched Centerlines' interpolatedCenterlines = InterpolatePatchCenterlines(patchParentArteryCenterlines,parentArteryCenterlines) WritePolyData(interpolatedCenterlines,interpolatedCenterlinesFilename) if (aneurysmType == 'terminal'): useAdditionalInterpolationPoint = 1 if (setClippingPoints == 0): parentArteryCenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_parentvessel.vtp' daughter1CenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_dau1cl.vtp' daughter2CenterlinesFilename = inputfiledirectory + '/' + ID + '/' + ID + '_dau2cl.vtp' clippingPointsFilename = inputfiledirectory + '/' + ID + '/' + ID + '_clippingpoints.vtp' parentArteryCenterlines = ReadPolyData(parentArteryCenterlinesFilename) daughter1Centerlines = ReadPolyData(daughter1CenterlinesFilename) daughter2Centerlines = ReadPolyData(daughter2CenterlinesFilename) centerlineSpacing = math.sqrt(vtk.vtkMath.Distance2BetweenPoints(parentArteryCenterlines.GetPoint(10),parentArteryCenterlines.GetPoint(11))) divergingTolerance = centerlineSpacing/divergingRatioToSpacingTolerance commonClippingPoint = [0.0,0.0,0.0] dau1ClippingPoint = [0.0,0.0,0.0] dau2ClippingPoint = [0.0,0.0,0.0] clippingPoints = vtk.vtkPoints() divergingPoints = vtk.vtkPoints() commonClippingPoint,commonDivergingPoint = FindClippingPointOnParentArtery(parentArteryCenterlines,parentArteryCenterlines,divergingTolerance) clippingPoints.InsertNextPoint(commonClippingPoint) divergingPoints.InsertNextPoint(commonDivergingPoint) dau1ClippingPoint,dau1DivergingPoint = FindClippingPointOnParentArtery(daughter1Centerlines,parentArteryCenterlines,divergingTolerance) clippingPoints.InsertNextPoint(dau1ClippingPoint) divergingPoints.InsertNextPoint(dau1DivergingPoint) dau2ClippingPoint,dau2DivergingPoint = FindClippingPointOnParentArtery(daughter2Centerlines,parentArteryCenterlines,divergingTolerance) clippingPoints.InsertNextPoint(dau2ClippingPoint) divergingPoints.InsertNextPoint(dau2DivergingPoint) SaveClippingPoints(clippingPoints,clippingPointsFilename) SaveClippingPoints(divergingPoints,divergingPointsFilename) elif (setClippingPoints == 1): print 'Clipping Points and Parent Vessel Centerlines provided' parentArteryFileName = inputfiledirectory + '/' + ID + '/' + ID + '_parentvessel.vtp' clippingPointsFileName = inputfiledirectory + '/' + ID + '/' + ID + '_clippingpoints.vtp' clippingPoints = ReadPolyData(clippingPointsFileName) parentArteryCenterlines = ReadPolyData(parentArteryFileName) print 'Creating Patched Centerlines' patchParentArteryCenterlines = CreateParentArteryPatches(parentArteryCenterlines,clippingPoints) WritePolyData(patchParentArteryCenterlines,patchParentArteryFilename) print 'Interpolating Patched Centerlines' interpolatedCenterlines = InterpolatePatchCenterlines(patchParentArteryCenterlines,parentArteryCenterlines) WritePolyData(interpolatedCenterlines,interpolatedCenterlinesFilename)