Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

463 lines
14 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkCurvatures.cxx,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.
=========================================================================*/
#include "vtkCurvatures.h"
#include "vtkCellArray.h"
#include "vtkDoubleArray.h"
#include "vtkFieldData.h"
#include "vtkFloatArray.h"
#include "vtkMath.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolyDataNormals.h"
#include "vtkPolygon.h"
#include "vtkTensor.h"
#include "vtkTriangle.h"
vtkCxxRevisionMacro(vtkCurvatures, "$Revision: 1.14 $");
vtkStandardNewMacro(vtkCurvatures);
//------------------------------------------------------------------------------
#if VTK3
vtkCurvatures* vtkCurvatures::New()
{
// First try to create the object from the vtkObjectFactory
vtkObject* ret = vtkObjectFactory::CreateInstance("vtkCurvatures");
if(ret)
{
return (vtkCurvatures*)ret;
}
// If the factory was unable to create the object, then create it here.
return new vtkCurvatures;
}
#endif
//-------------------------------------------------------//
vtkCurvatures::vtkCurvatures()
{
this->CurvatureType = VTK_CURVATURE_GAUSS;
this->InvertMeanCurvature = 0;
}
//-------------------------------------------------------//
void vtkCurvatures::GetMeanCurvature(vtkPolyData *mesh)
{
vtkDebugMacro("Start vtkCurvatures::GetMeanCurvature");
// Empty array check
if (mesh->GetNumberOfPolys()==0 || mesh->GetNumberOfPoints()==0)
{
vtkErrorMacro("No points/cells to operate on");
return;
}
int numPts = mesh->GetNumberOfPoints();
// vtkData
vtkIdList* vertices, *vertices_n, *neighbours;
vtkTriangle* facet;
vtkTriangle* neighbour;
// create-allocate
vertices = vtkIdList::New();
vertices_n = vtkIdList::New();
neighbours = vtkIdList::New();
facet = vtkTriangle::New();
neighbour = vtkTriangle::New();
vtkDoubleArray* meanCurvature = vtkDoubleArray::New();
meanCurvature->SetName("Mean_Curvature");
meanCurvature->SetNumberOfComponents(1);
meanCurvature->SetNumberOfTuples(numPts);
// Get the array so we can write to it directly
double *meanCurvatureData = meanCurvature->GetPointer(0);
// data
int v, v_l, v_r, v_o, f, F, n, nv;// n short for neighbor
// create-allocate
double n_f[3]; // normal of facet (could be stored for later?)
double n_n[3]; // normal of edge
double t[3]; // to store the cross product of n_f n_n
double ore[3]; // origin of e
double end[3]; // end of e
double oth[3]; // third vertex necessary for comp of n
double vn0[3];
double vn1[3]; // vertices for computation of neighbour's n
double vn2[3];
double e[3]; // edge (oriented)
double cs, sn; // cs: cos; sn sin
double angle, length, Af, Hf; // temporary store
mesh->BuildLinks();
//data init
f = 0;
F = mesh->GetNumberOfCells();
// init, preallocate the mean curvature
int* num_neighb = new int[numPts];
for (v = 0; v < numPts; v++)
{
meanCurvatureData[v] = 0.0;
num_neighb[v] = 0;
}
// main loop
vtkDebugMacro(<<"Main loop: loop over facets such that id > id of neighb");
vtkDebugMacro(<<"so that every edge comes only once");
//
for (f = 0; f < F; f++)
{
mesh->GetCellPoints(f,vertices);
nv = vertices->GetNumberOfIds();
for (v = 0; v < nv; v++)
{
// get neighbour
v_l = vertices->GetId(v);
v_r = vertices->GetId((v+1) % nv);
v_o = vertices->GetId((v+2) % nv);
mesh->GetCellEdgeNeighbors(f,v_l,v_r,neighbours);
// compute only if there is really ONE neighbour
// AND meanCurvature has not been computed yet!
// (ensured by n > f)
if (neighbours->GetNumberOfIds() == 1 && (n = neighbours->GetId(0)) > f)
{
// find 3 corners of f: in order!
mesh->GetPoint(v_l,ore);
mesh->GetPoint(v_r,end);
mesh->GetPoint(v_o,oth);
// compute normal of f
facet->ComputeNormal(ore,end,oth,n_f);
// compute common edge
e[0] = end[0]; e[1] = end[1]; e[2] = end[2];
e[0] -= ore[0]; e[1] -= ore[1]; e[2] -= ore[2];
length = double(vtkMath::Normalize(e));
Af = double(facet->TriangleArea(ore,end,oth));
// find 3 corners of n: in order!
mesh->GetCellPoints(n,vertices_n);
mesh->GetPoint(vertices_n->GetId(0),vn0);
mesh->GetPoint(vertices_n->GetId(1),vn1);
mesh->GetPoint(vertices_n->GetId(2),vn2);
Af += double(facet->TriangleArea(vn0,vn1,vn2));
// compute normal of n
neighbour->ComputeNormal(vn0,vn1,vn2,n_n);
// the cosine is n_f * n_n
cs = double(vtkMath::Dot(n_f,n_n));
// the sin is (n_f x n_n) * e
vtkMath::Cross(n_f,n_n,t);
sn = double(vtkMath::Dot(t,e));
// signed angle in [-pi,pi]
if (sn!=0.0 || cs!=0.0)
{
angle = atan2(sn,cs);
Hf = length*angle;
}
else
{
Hf = 0.0;
}
// add weighted Hf to scalar at v_l and v_r
if (Af!=0.0)
{
(Hf /= Af) *=3.0;
}
meanCurvatureData[v_l] += Hf;
meanCurvatureData[v_r] += Hf;
num_neighb[v_l] += 1;
num_neighb[v_r] += 1;
}
}
}
// put curvature in vtkArray
for (v = 0; v < numPts; v++)
{
if (num_neighb[v]>0)
{
Hf = 0.5*meanCurvatureData[v]/(double)num_neighb[v];
if (this->InvertMeanCurvature)
{
meanCurvatureData[v] = -Hf;
}
else
{
meanCurvatureData[v] = Hf;
}
}
else
{
meanCurvatureData[v] = 0.0;
}
}
mesh->GetPointData()->AddArray(meanCurvature);
mesh->GetPointData()->SetActiveScalars("Mean_Curvature");
vtkDebugMacro("Set Values of Mean Curvature: Done");
// clean
vertices ->Delete();
vertices_n->Delete();
neighbours->Delete();
facet ->Delete();
neighbour ->Delete();
if (meanCurvature) meanCurvature->Delete();
if (num_neighb) delete [] num_neighb;
};
//--------------------------------------------
#define CLAMP_MACRO(v) ((v)<(-1) ? (-1) : (v) > (1) ? (1) : v)
void vtkCurvatures::GetGaussCurvature(vtkPolyData *output)
{
vtkDebugMacro("Start vtkCurvatures::GetGaussCurvature()");
// vtk data
vtkCellArray* facets = output->GetPolys();
// Empty array check
if (output->GetNumberOfPolys()==0 || output->GetNumberOfPoints()==0)
{
vtkErrorMacro("No points/cells to operate on");
return;
}
vtkTriangle* facet = vtkTriangle::New();
// other data
vtkIdType Nv = output->GetNumberOfPoints();
double* K = new double[Nv];
double* dA = new double[Nv];
double pi2 = 2.0*vtkMath::Pi();
for (int k = 0; k < Nv; k++)
{
K[k] = pi2;
dA[k] = 0.0;
}
double v0[3], v1[3], v2[3], e0[3], e1[3], e2[3];
double A, alpha0, alpha1, alpha2;
vtkIdType f, *vert=0;
facets->InitTraversal();
while (facets->GetNextCell(f,vert))
{
output->GetPoint(vert[0],v0);
output->GetPoint(vert[1],v1);
output->GetPoint(vert[2],v2);
// edges
e0[0] = v1[0] ; e0[1] = v1[1] ; e0[2] = v1[2] ;
e0[0] -= v0[0]; e0[1] -= v0[1]; e0[2] -= v0[2];
e1[0] = v2[0] ; e1[1] = v2[1] ; e1[2] = v2[2] ;
e1[0] -= v1[0]; e1[1] -= v1[1]; e1[2] -= v1[2];
e2[0] = v0[0] ; e2[1] = v0[1] ; e2[2] = v0[2] ;
e2[0] -= v2[0]; e2[1] -= v2[1]; e2[2] -= v2[2];
// normalise
vtkMath::Normalize(e0); vtkMath::Normalize(e1); vtkMath::Normalize(e2);
// angles
// I get lots of acos domain errors so clamp the value to +/-1 as the
// normalize function can return 1.000000001 etc (I think)
double ac1 = vtkMath::Dot(e1,e2);
double ac2 = vtkMath::Dot(e2,e0);
double ac3 = vtkMath::Dot(e0,e1);
alpha0 = acos(-CLAMP_MACRO(ac1));
alpha1 = acos(-CLAMP_MACRO(ac2));
alpha2 = acos(-CLAMP_MACRO(ac3));
// surf. area
A = double(facet->TriangleArea(v0,v1,v2));
// UPDATE
dA[vert[0]] += A;
dA[vert[1]] += A;
dA[vert[2]] += A;
K[vert[0]] -= alpha1;
K[vert[1]] -= alpha2;
K[vert[2]] -= alpha0;
}
int numPts = output->GetNumberOfPoints();
// put curvature in vtkArray
vtkDoubleArray* gaussCurvature = vtkDoubleArray::New();
gaussCurvature->SetName("Gauss_Curvature");
gaussCurvature->SetNumberOfComponents(1);
gaussCurvature->SetNumberOfTuples(numPts);
double *gaussCurvatureData = gaussCurvature->GetPointer(0);
for (int v = 0; v < Nv; v++)
{
if (dA[v]>0.0)
{
gaussCurvatureData[v] = 3.0*K[v]/dA[v];
}
else
{
gaussCurvatureData[v] = 0.0;
}
}
output->GetPointData()->AddArray(gaussCurvature);
output->GetPointData()->SetActiveScalars("Gauss_Curvature");
vtkDebugMacro("Set Values of Gauss Curvature: Done");
/*******************************************************/
if (facet) facet->Delete();
if (K) delete [] K;
if (dA) delete [] dA;
if (gaussCurvature) gaussCurvature->Delete();
/*******************************************************/
};
void vtkCurvatures::GetMaximumCurvature(vtkPolyData *input,vtkPolyData *output)
{
this->GetGaussCurvature(output);
this->GetMeanCurvature(output);
vtkIdType numPts = input->GetNumberOfPoints();
vtkDoubleArray *maximumCurvature = vtkDoubleArray::New();
maximumCurvature->SetNumberOfComponents(1);
maximumCurvature->SetNumberOfTuples(numPts);
maximumCurvature->SetName("Maximum_Curvature");
output->GetPointData()->AddArray(maximumCurvature);
output->GetPointData()->SetActiveScalars("Maximum_Curvature");
maximumCurvature->Delete();
vtkDoubleArray *gauss = (vtkDoubleArray *)output->GetPointData()->GetArray("Gauss_Curvature");
vtkDoubleArray *mean = (vtkDoubleArray *)output->GetPointData()->GetArray("Mean_Curvature");
double k, h, k_max,tmp;
for (vtkIdType i = 0; i<numPts; i++)
{
k = gauss->GetComponent(i,0);
h = mean->GetComponent(i,0);
tmp = h*h - k;
if (tmp >= 0)
{
k_max = h + sqrt(tmp);
}
else
{
vtkDebugMacro(<< "Maximum Curvature undefined at point: " << i);
// k_max can be any real number. Undefined points will be indistinguishable
// from points that actually have a k_max == 0
k_max = 0;
}
maximumCurvature->SetComponent(i, 0, k_max);
}
}
void vtkCurvatures::GetMinimumCurvature(vtkPolyData *input,vtkPolyData *output)
{
this->GetGaussCurvature(output);
this->GetMeanCurvature(output);
vtkIdType numPts = input->GetNumberOfPoints();
vtkDoubleArray *minimumCurvature = vtkDoubleArray::New();
minimumCurvature->SetNumberOfComponents(1);
minimumCurvature->SetNumberOfTuples(numPts);
minimumCurvature->SetName("Minimum_Curvature");
output->GetPointData()->AddArray(minimumCurvature);
output->GetPointData()->SetActiveScalars("Minimum_Curvature");
minimumCurvature->Delete();
vtkDoubleArray *gauss = (vtkDoubleArray *)output->GetPointData()->GetArray("Gauss_Curvature");
vtkDoubleArray *mean = (vtkDoubleArray *)output->GetPointData()->GetArray("Mean_Curvature");
double k, h, k_min,tmp;
for (vtkIdType i = 0; i<numPts; i++)
{
k = gauss->GetComponent(i,0);
h = mean->GetComponent(i,0);
tmp = h*h - k;
if (tmp >= 0)
{
k_min = h - sqrt(tmp);
}
else
{
vtkDebugMacro(<< "Minimum Curvature undefined at point: " << i);
// k_min can be any real number. Undefined points will be indistinguishable
// from points that actually have a k_min == 0
k_min = 0;
}
minimumCurvature->SetComponent(i, 0, k_min);
}
}
//-------------------------------------------------------
int vtkCurvatures::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()));
// Null input check
if (!input)
{
return 0;
}
output->CopyStructure(input);
output->GetPointData()->PassData(input->GetPointData());
output->GetFieldData()->PassData(input->GetFieldData());
//-------------------------------------------------------//
// Set Curvatures as PointData Scalars //
//-------------------------------------------------------//
if ( this->CurvatureType == VTK_CURVATURE_GAUSS )
{
this->GetGaussCurvature(output);
}
else if ( this->CurvatureType == VTK_CURVATURE_MEAN )
{
this->GetMeanCurvature(output);
}
else if ( this->CurvatureType == VTK_CURVATURE_MAXIMUM )
{
this->GetMaximumCurvature(input, output);
}
else if ( this->CurvatureType == VTK_CURVATURE_MINIMUM )
{
this->GetMinimumCurvature(input, output);
}
else
{
vtkErrorMacro("Only Gauss, Mean, Max, and Min Curvature type available");
return 1;
}
return 1;
}
/*-------------------------------------------------------*/
void vtkCurvatures::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "CurvatureType: " << this->CurvatureType << "\n";
os << indent << "InvertMeanCurvature: " << this->InvertMeanCurvature << "\n";
}