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.

1477 lines
32 KiB

2 years ago
/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkMeshQuality.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.
=========================================================================*/
/*
* Copyright 2004 Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the
* U.S. Government. Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that this Notice and any
* statement of authorship are reproduced on all copies.
*/
#include "vtkMeshQuality.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkDataSet.h"
#include "vtkCellData.h"
#include "vtkDataArray.h"
#include "vtkDoubleArray.h"
#include "vtkCell.h"
#include "vtkCellTypes.h"
#include "vtkPoints.h"
#include "vtkMath.h"
#include "vtkTetra.h"
vtkCxxRevisionMacro(vtkMeshQuality,"$Revision: 1.31 $");
vtkStandardNewMacro(vtkMeshQuality);
typedef double (*CellQualityType)( vtkCell* );
double TetVolume( vtkCell* cell );
const char* QualityMeasureNames[] =
{
"EdgeRatio",
"AspectRatio",
"RadiusRatio",
"FrobeniusNorm",
"MedFrobeniusNorm",
"MaxFrobeniusNorm",
"MinAngle"
};
void vtkMeshQuality::PrintSelf(ostream& os, vtkIndent indent )
{
const char onStr[] = "On";
const char offStr[] = "Off";
this->Superclass::PrintSelf( os, indent );
os << indent << "SaveCellQuality: "
<< (this->SaveCellQuality ? onStr : offStr) << endl;
os << indent << "TriangleQualityMeasure: "
<< QualityMeasureNames[this->TriangleQualityMeasure] << endl;
os << indent << "QuadQualityMeasure: "
<< QualityMeasureNames[this->QuadQualityMeasure] << endl;
os << indent << "TetQualityMeasure: "
<< QualityMeasureNames[this->TetQualityMeasure] << endl;
os << indent << "HexQualityMeasure: "
<< QualityMeasureNames[this->HexQualityMeasure] << endl;
os << indent << "Volume: "
<< (this->Volume ? onStr : offStr) << endl;
os << indent << "CompatibilityMode: "
<< (this->CompatibilityMode ? onStr : offStr) << endl;
}
vtkMeshQuality::vtkMeshQuality()
{
this->SaveCellQuality = 1; // Default is On
this->TriangleQualityMeasure = VTK_QUALITY_ASPECT_RATIO;
this->QuadQualityMeasure = VTK_QUALITY_EDGE_RATIO;
this->TetQualityMeasure = VTK_QUALITY_ASPECT_RATIO;
this->HexQualityMeasure = VTK_QUALITY_EDGE_RATIO;
this->Volume = 0;
this->CompatibilityMode = 0;
}
vtkMeshQuality::~vtkMeshQuality()
{
// Nothing yet.
}
int vtkMeshQuality::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
vtkDataSet *in = vtkDataSet::SafeDownCast(
inInfo->Get(vtkDataObject::DATA_OBJECT()));
vtkDataSet *out = vtkDataSet::SafeDownCast(
outInfo->Get(vtkDataObject::DATA_OBJECT()));
CellQualityType TriangleQuality,QuadQuality,TetQuality,HexQuality;
vtkDoubleArray* quality = 0;
vtkDoubleArray* volume = 0;
vtkIdType N = in->GetNumberOfCells();
double qtrim,qtriM,Eqtri,Eqtri2;
double qquam,qquaM,Eqqua,Eqqua2;
double qtetm,qtetM,Eqtet,Eqtet2;
double qhexm,qhexM,Eqhex,Eqhex2;
double q;
double V = 0.;
vtkIdType ntri = 0;
vtkIdType nqua = 0;
vtkIdType ntet = 0;
vtkIdType nhex = 0;
vtkCell* cell;
// Initialize the min and max values, std deviations, etc.
qtriM = qquaM = qtetM = qhexM = VTK_DOUBLE_MIN;
qtrim = qquam = qtetm = qhexm = VTK_DOUBLE_MAX;
Eqtri = Eqtri2 = Eqqua = Eqqua2 = Eqtet = Eqtet2 = Eqhex = Eqhex2 = 0.;
switch ( this->GetTriangleQualityMeasure() )
{
case VTK_QUALITY_EDGE_RATIO:
TriangleQuality = TriangleEdgeRatio;
break;
case VTK_QUALITY_ASPECT_RATIO:
TriangleQuality = TriangleAspectRatio;
break;
case VTK_QUALITY_RADIUS_RATIO:
TriangleQuality = TriangleRadiusRatio;
break;
case VTK_QUALITY_FROBENIUS_NORM:
TriangleQuality = TriangleFrobeniusNorm;
break;
case VTK_QUALITY_MIN_ANGLE:
TriangleQuality = TriangleMinAngle;
break;
default:
vtkWarningMacro( "Bad TriangleQualityMeasure ("
<< this->GetTriangleQualityMeasure() << "), using RadiusRatio instead");
TriangleQuality = TriangleRadiusRatio;
break;
}
switch ( this->GetQuadQualityMeasure() )
{
case VTK_QUALITY_EDGE_RATIO:
QuadQuality = QuadEdgeRatio;
break;
case VTK_QUALITY_ASPECT_RATIO:
QuadQuality = QuadAspectRatio;
break;
case VTK_QUALITY_RADIUS_RATIO:
QuadQuality = QuadRadiusRatio;
break;
case VTK_QUALITY_MED_FROBENIUS_NORM:
QuadQuality = QuadMedFrobeniusNorm;
break;
case VTK_QUALITY_MAX_FROBENIUS_NORM:
QuadQuality = QuadMaxFrobeniusNorm;
break;
case VTK_QUALITY_MIN_ANGLE:
QuadQuality = QuadMinAngle;
break;
default:
vtkWarningMacro( "Bad QuadQualityMeasure ("
<< this->GetQuadQualityMeasure() << "), using EdgeRatio instead");
QuadQuality = QuadEdgeRatio;
break;
}
switch ( this->GetTetQualityMeasure() )
{
case VTK_QUALITY_EDGE_RATIO:
TetQuality = TetEdgeRatio;
break;
case VTK_QUALITY_ASPECT_RATIO:
TetQuality = TetAspectRatio;
break;
case VTK_QUALITY_RADIUS_RATIO:
TetQuality = TetRadiusRatio;
break;
case VTK_QUALITY_FROBENIUS_NORM:
TetQuality = TetFrobeniusNorm;
break;
case VTK_QUALITY_MIN_ANGLE:
TetQuality = TetMinAngle;
break;
default:
vtkWarningMacro( "Bad TetQualityMeasure ("
<< this->GetTetQualityMeasure() << "), using RadiusRatio instead");
TetQuality = TetRadiusRatio;
break;
}
switch ( this->GetHexQualityMeasure() )
{
case VTK_QUALITY_EDGE_RATIO:
HexQuality = HexEdgeRatio;
break;
default:
vtkWarningMacro( "Bad HexQualityMeasure ("
<< this->GetTetQualityMeasure() << "), using EdgeRatio instead");
HexQuality = HexEdgeRatio;
break;
}
out->ShallowCopy( in );
if ( this->SaveCellQuality )
{
quality = vtkDoubleArray::New();
if ( this->CompatibilityMode )
{
if ( this->Volume )
{
quality->SetNumberOfComponents(2);
}
else
{
quality->SetNumberOfComponents(1);
}
}
else
{
quality->SetNumberOfComponents(1);
}
quality->SetNumberOfTuples( N );
quality->SetName( "Quality" );
out->GetCellData()->AddArray( quality );
out->GetCellData()->SetActiveAttribute( "Quality", vtkDataSetAttributes::SCALARS );
quality->Delete();
if ( ! this->CompatibilityMode )
{
if ( this->Volume )
{
volume = vtkDoubleArray::New();
volume->SetNumberOfComponents(1);
volume->SetNumberOfTuples( N );
volume->SetName( "Volume" );
out->GetCellData()->AddArray( volume );
volume->Delete();
}
}
}
int p;
vtkIdType c = 0;
vtkIdType sz = N < 19 ? 1 : N / 19;
vtkIdType inner;
this->UpdateProgress( 0.01 );
for ( p = 0; p < 20; ++p )
{
for ( inner = 0; (inner < sz && c < N); ++c, ++inner )
{
cell = out->GetCell( c );
V = 0.;
switch ( cell->GetCellType() )
{
case VTK_TRIANGLE:
q = TriangleQuality( cell );
if ( q > qtriM )
{
if ( qtrim > qtriM )
{
qtrim = q;
}
qtriM = q;
}
else if ( q < qtrim )
{
qtrim = q;
}
Eqtri += q;
Eqtri2 += q * q;
ntri++;
break;
case VTK_QUAD:
q = QuadQuality( cell );
if ( q > qquaM )
{
if ( qquam > qquaM )
{
qquam = q;
}
qquaM = q;
}
else if ( q < qquam )
{
qquam = q;
}
Eqqua += q;
Eqqua2 += q * q;
nqua++;
break;
case VTK_TETRA:
q = TetQuality( cell );
if ( q > qtetM )
{
if ( qtetm > qtetM )
{
qtetm = q;
}
qtetM = q;
}
else if ( q < qtetm )
{
qtetm = q;
}
Eqtet += q;
Eqtet2 += q * q;
ntet++;
if ( this->Volume )
{
V = TetVolume( cell );
if ( ! this->CompatibilityMode )
{
volume->SetTuple1( 0, V );
}
}
break;
case VTK_HEXAHEDRON:
q = HexQuality( cell );
if ( q > qhexM )
{
if ( qhexm > qhexM )
{
qhexm = q;
}
qhexM = q;
}
else if ( q < qhexm )
{
qhexm = q;
}
Eqhex += q;
Eqhex2 += q * q;
nhex++;
break;
default:
q = 0.;
}
if ( this->SaveCellQuality )
{
if ( this->CompatibilityMode && this->Volume )
{
quality->SetTuple2( c, V, q );
}
else
{
quality->SetTuple1( c, q );
}
}
}
this->UpdateProgress( double(p+1)/20. );
}
if ( ntri )
{
Eqtri /= (double) ntri;
Eqtri2 /= (double) ntri;
}
else
{
qtrim = Eqtri = qtriM = Eqtri2 = 0.;
}
if ( nqua )
{
Eqqua /= (double) nqua;
Eqqua2 /= (double) nqua;
}
else
{
qquam = Eqqua = qquaM = Eqqua2 = 0.;
}
if ( ntet )
{
Eqtet /= (double) ntet;
Eqtet2 /= (double) ntet;
}
else
{
qtetm = Eqtet = qtetM = Eqtet2 = 0.;
}
if ( nhex )
{
Eqhex /= (double) nhex;
Eqhex2 /= (double) nhex;
}
else
{
qhexm = Eqhex = qhexM = Eqhex2 = 0.;
}
double tuple[5];
quality = vtkDoubleArray::New();
quality->SetName( "Mesh Triangle Quality" );
quality->SetNumberOfComponents(5);
tuple[0] = qtrim;
tuple[1] = Eqtri;
tuple[2] = qtriM;
tuple[3] = Eqtri2;
tuple[4] = ntri;
quality->InsertNextTuple( tuple );
out->GetFieldData()->AddArray( quality );
quality->Delete();
quality = vtkDoubleArray::New();
quality->SetName( "Mesh Quadrilateral Quality" );
quality->SetNumberOfComponents(5);
tuple[0] = qquam;
tuple[1] = Eqqua;
tuple[2] = qquaM;
tuple[3] = Eqqua2;
tuple[4] = nqua;
quality->InsertNextTuple( tuple );
out->GetFieldData()->AddArray( quality );
quality->Delete();
quality = vtkDoubleArray::New();
quality->SetName( "Mesh Tetrahedron Quality" );
quality->SetNumberOfComponents(5);
tuple[0] = qtetm;
tuple[1] = Eqtet;
tuple[2] = qtetM;
tuple[3] = Eqtet2;
tuple[4] = ntet;
quality->InsertNextTuple( tuple );
out->GetFieldData()->AddArray( quality );
quality->Delete();
quality = vtkDoubleArray::New();
quality->SetName( "Mesh Hexahedron Quality" );
quality->SetNumberOfComponents(5);
tuple[0] = qhexm;
tuple[1] = Eqhex;
tuple[2] = qhexM;
tuple[3] = Eqhex2;
tuple[4] = nhex;
quality->InsertNextTuple( tuple );
out->GetFieldData()->AddArray( quality );
quality->Delete();
return 1;
}
// Triangle quality measures:
// edge ratio, aspect ratio, radius ratio, Frobenius norm, minimal angle
double vtkMeshQuality::TriangleEdgeRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3];
double a[3],b[3],c[3];
double a2,b2,c2,m2,M2;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p2[0]-p0[0];
c[1] = p2[1]-p0[1];
c[2] = p2[2]-p0[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
if ( a2 < b2 )
{
if ( b2 < c2 )
{
m2 = a2;
M2 = c2;
}
else // b2 <= a2
{
if ( a2 < c2 )
{
m2 = a2;
M2 = b2;
}
else // c2 <= a2
{
m2 = c2;
M2 = b2;
}
}
}
else // b2 <= a2
{
if ( a2 < c2 )
{
m2 = b2;
M2 = c2;
}
else // c2 <= a2
{
if ( b2 < c2 )
{
m2 = b2;
M2 = a2;
}
else // c2 <= b2
{
m2 = c2;
M2 = a2;
}
}
}
return sqrt(M2 / m2);
}
double vtkMeshQuality::TriangleAspectRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3];
double a[3],b[3],c[3];
double a1,b1,c1,hm;
const double normal_coeff = sqrt(3.) / 6.;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p2[0]-p0[0];
c[1] = p2[1]-p0[1];
c[2] = p2[2]-p0[2];
a1 = sqrt(vtkMath::Dot(a,a));
b1 = sqrt(vtkMath::Dot(b,b));
c1 = sqrt(vtkMath::Dot(c,c));
hm = a1 > b1 ? a1 : b1;
hm = hm > c1 ? hm : c1;
vtkMath::Cross(a,b,c);
return normal_coeff * hm * (a1 + b1 + c1) / vtkMath::Norm(c);
}
double vtkMeshQuality::TriangleRadiusRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3];
double a[3],b[3],c[3];
double a1,b1,c1,ab;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p2[0]-p0[0];
c[1] = p2[1]-p0[1];
c[2] = p2[2]-p0[2];
a1 = sqrt(vtkMath::Dot(a,a));
b1 = sqrt(vtkMath::Dot(b,b));
c1 = sqrt(vtkMath::Dot(c,c));
vtkMath::Cross(a,b,c);
ab = vtkMath::Norm(c);
return .25 * a1 * b1 * c1 * (a1 + b1 + c1) / (ab * ab);
}
double vtkMeshQuality::TriangleFrobeniusNorm( vtkCell* cell )
{
double p0[3],p1[3],p2[3];
double a[3],b[3],c[3];
double t22;
const double normal_coeff = .5 / sqrt(3.);
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p2[0]-p0[0];
c[1] = p2[1]-p0[1];
c[2] = p2[2]-p0[2];
t22 = vtkMath::Dot(a,a);
t22 += vtkMath::Dot(b,b);
t22 += vtkMath::Dot(c,c);
vtkMath::Cross(a,b,c);
return normal_coeff * t22 / vtkMath::Norm(c);
}
double vtkMeshQuality::TriangleMinAngle( vtkCell* cell )
{
double p0[3],p1[3],p2[3];
double a[3],b[3],c[3];
double a2,b2,c2,alpha,beta,gamma;
const double normal_coeff = .3183098861837906715377675267450287;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p2[0]-p0[0];
c[1] = p2[1]-p0[1];
c[2] = p2[2]-p0[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
alpha = acos(vtkMath::Dot(b,c) / sqrt(b2 * c2));
beta = acos(vtkMath::Dot(c,a) / sqrt(c2 * a2));
gamma = acos(vtkMath::Dot(a,b) / sqrt(a2 * b2));
alpha = alpha < beta ? alpha : beta;
return (alpha < gamma ? alpha : gamma) * 180. * normal_coeff;
}
// Quadrangle quality measures:
// edge ratio, aspect ratio, radius ratio, average Frobenius norm,
// maximal Frobenius norm, minimal angle
// (only edge ratio and minimal angle are intended for nonplanar quads)
double vtkMeshQuality::QuadEdgeRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3];
double a2,b2,c2,d2,mab,Mab,mcd,Mcd,m2,M2;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
if ( a2 < b2 )
{
mab = a2;
Mab = b2;
}
else // b2 <= a2
{
mab = b2;
Mab = a2;
}
if ( c2 < d2 )
{
mcd = c2;
Mcd = d2;
}
else // d2 <= c2
{
mcd = d2;
Mcd = c2;
}
m2 = mab < mcd ? mab : mcd;
M2 = Mab > Mcd ? Mab : Mcd;
return sqrt(M2 / m2);
}
double vtkMeshQuality::QuadAspectRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3],ab[3],cd[3];
double a1,b1,c1,d1;
double ma,mb,hm;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
a1 = sqrt(vtkMath::Dot(a,a));
b1 = sqrt(vtkMath::Dot(b,b));
c1 = sqrt(vtkMath::Dot(c,c));
d1 = sqrt(vtkMath::Dot(d,d));
ma = a1 > b1 ? a1 : b1;
mb = c1 > d1 ? c1 : d1;
hm = ma > mb ? ma : mb;
vtkMath::Cross(a,b,ab);
vtkMath::Cross(c,d,cd);
return .5 * hm * (a1 + b1 + c1 + d1) / (vtkMath::Norm(ab) + vtkMath::Norm(cd));
}
double vtkMeshQuality::QuadRadiusRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3],m[3],n[3];
double ab[3],bc[3],cd[3],da[3];
double a2,b2,c2,d2,m2,n2,h2;
double t0,t1,t2,t3;
const double normal_coeff = 1. / (2.*sqrt(2.));
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
m[0] = p2[0]-p0[0];
m[1] = p2[1]-p0[1];
m[2] = p2[2]-p0[2];
n[0] = p3[0]-p1[0];
n[1] = p3[1]-p1[1];
n[2] = p3[2]-p1[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
m2 = vtkMath::Dot(m,m);
n2 = vtkMath::Dot(n,n);
t0 = a2 > b2 ? a2 : b2;
t1 = c2 > d2 ? c2 : d2;
t2 = m2 > n2 ? m2 : n2;
h2 = t0 > t1 ? t0 : t1;
h2 = h2 > t2 ? h2 : t2;
vtkMath::Cross(a,b,ab);
vtkMath::Cross(b,c,bc);
vtkMath::Cross(c,d,cd);
vtkMath::Cross(d,a,da);
t0 = vtkMath::Norm(da);
t1 = vtkMath::Norm(ab);
t2 = vtkMath::Norm(bc);
t3 = vtkMath::Norm(cd);
t0 = t0 < t1 ? t0 : t1;
t2 = t2 < t3 ? t2 : t3;
t0 = t0 < t2 ? t0 : t2;
return normal_coeff * sqrt((a2 + b2 + c2 + d2) * h2) / t0;
}
double vtkMeshQuality::QuadMedFrobeniusNorm( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3],ab[3],bc[3],cd[3],da[3];
double a2,b2,c2,d2;
double kappa2;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
vtkMath::Cross(a,b,ab);
vtkMath::Cross(b,c,bc);
vtkMath::Cross(c,d,cd);
vtkMath::Cross(d,a,da);
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
kappa2 = (a2 + b2) / vtkMath::Norm(ab);
kappa2 += (b2 + c2) / vtkMath::Norm(bc);
kappa2 += (c2 + d2) / vtkMath::Norm(cd);
kappa2 += (d2 + a2) / vtkMath::Norm(da);
return .125 * kappa2;
}
double vtkMeshQuality::QuadMaxFrobeniusNorm( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3],ab[3],bc[3],cd[3],da[3];
double a2,b2,c2,d2;
double kmax,kcur;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
vtkMath::Cross(a,b,ab);
vtkMath::Cross(b,c,bc);
vtkMath::Cross(c,d,cd);
vtkMath::Cross(d,a,da);
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
kmax = (a2 + b2) / vtkMath::Norm(ab);
kcur = (b2 + c2) / vtkMath::Norm(bc);
kmax = kmax > kcur ? kmax : kcur;
kcur = (c2 + d2) / vtkMath::Norm(cd);
kmax = kmax > kcur ? kmax : kcur;
kcur = (d2 + a2) / vtkMath::Norm(da);
kmax = kmax > kcur ? kmax : kcur;
return .5 * kmax;
}
double vtkMeshQuality::QuadMinAngle( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3];
double a2,b2,c2,d2,alpha,beta,gamma,delta;
const double normal_coeff = .3183098861837906715377675267450287;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
alpha = acos(vtkMath::Dot(b,c) / sqrt(b2 * c2));
beta = acos(vtkMath::Dot(c,d) / sqrt(c2 * d2));
gamma = acos(vtkMath::Dot(d,a) / sqrt(d2 * a2));
delta = acos(vtkMath::Dot(a,b) / sqrt(a2 * b2));
alpha = alpha < beta ? alpha : beta;
gamma = gamma < delta ? gamma : delta;
return (alpha < gamma ? alpha : gamma) * 180. * normal_coeff;
}
// Volume of a tetrahedron, for compatibility with the original vtkMeshQuality
double TetVolume( vtkCell* cell )
{
double x0[3];
double x1[3];
double x2[3];
double x3[3];
cell->Points->GetPoint( 0, x0 );
cell->Points->GetPoint( 1, x1 );
cell->Points->GetPoint( 2, x2 );
cell->Points->GetPoint( 3, x3 );
return vtkTetra::ComputeVolume( x0, x1, x2, x3 );
}
// Tetrahedron quality measures:
// edge ratio, aspect ratio, radius ratio, Frobenius norm, minimal angle
double vtkMeshQuality::TetEdgeRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double a[3],b[3],c[3],d[3],e[3],f[3];
double a2,b2,c2,d2,e2,f2;
double m2,M2,mab,mcd,mef,Mab,Mcd,Mef;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p2[0]-p0[0];
c[1] = p2[1]-p0[1];
c[2] = p2[2]-p0[2];
d[0] = p3[0]-p0[0];
d[1] = p3[1]-p0[1];
d[2] = p3[2]-p0[2];
e[0] = p3[0]-p1[0];
e[1] = p3[1]-p1[1];
e[2] = p3[2]-p1[2];
f[0] = p3[0]-p2[0];
f[1] = p3[1]-p2[1];
f[2] = p3[2]-p2[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
e2 = vtkMath::Dot(e,e);
f2 = vtkMath::Dot(f,f);
if ( a2 < b2 )
{
mab = a2;
Mab = b2;
}
else // b2 <= a2
{
mab = b2;
Mab = a2;
}
if ( c2 < d2 )
{
mcd = c2;
Mcd = d2;
}
else // d2 <= c2
{
mcd = d2;
Mcd = c2;
}
if ( e2 < f2 )
{
mef = e2;
Mef = f2;
}
else // f2 <= e2
{
mef = f2;
Mef = e2;
}
m2 = mab < mcd ? mab : mcd;
m2 = m2 < mef ? m2 : mef;
M2 = Mab > Mcd ? Mab : Mcd;
M2 = M2 > Mef ? M2 : Mef;
return sqrt(M2 / m2);
}
double vtkMeshQuality::TetAspectRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double ab[3],bc[3],ac[3],ad[3],bd[3],cd[3];
double t0,t1,t2,t3,t4,t5;
double ma,mb,mc,hm;
const double normal_coeff = sqrt(6.) / 12.;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
ab[0] = p1[0]-p0[0];
ab[1] = p1[1]-p0[1];
ab[2] = p1[2]-p0[2];
bc[0] = p2[0]-p1[0];
bc[1] = p2[1]-p1[1];
bc[2] = p2[2]-p1[2];
ac[0] = p2[0]-p0[0];
ac[1] = p2[1]-p0[1];
ac[2] = p2[2]-p0[2];
ad[0] = p3[0]-p0[0];
ad[1] = p3[1]-p0[1];
ad[2] = p3[2]-p0[2];
bd[0] = p3[0]-p1[0];
bd[1] = p3[1]-p1[1];
bd[2] = p3[2]-p1[2];
cd[0] = p3[0]-p2[0];
cd[1] = p3[1]-p2[1];
cd[2] = p3[2]-p2[2];
t0 = vtkMath::Dot(ab,ab);
t1 = vtkMath::Dot(bc,bc);
t2 = vtkMath::Dot(ac,ac);
t3 = vtkMath::Dot(ad,ad);
t4 = vtkMath::Dot(bd,bd);
t5 = vtkMath::Dot(cd,cd);
ma = t0 > t1 ? t0 : t1;
mb = t2 > t3 ? t2 : t3;
mc = t4 > t5 ? t4 : t5;
hm = ma > mb ? ma : mb;
hm = hm > mc ? sqrt(hm) : sqrt(mc);
vtkMath::Cross(ab,bc,bd);
t0 = vtkMath::Norm(bd);
vtkMath::Cross(ab,ad,bd);
t1 = vtkMath::Norm(bd);
vtkMath::Cross(ac,ad,bd);
t2 = vtkMath::Norm(bd);
vtkMath::Cross(bc,cd,bd);
t3 = vtkMath::Norm(bd);
t4 = fabs(vtkMath::Determinant3x3(ab,ac,ad));
return normal_coeff * hm * (t0 + t1 + t2 + t3) / t4;
}
double vtkMeshQuality::TetRadiusRatio( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double ab[3],bc[3],ac[3],ad[3],bd[3],cd[3],u[3];
double abc,abd,acd,bcd,a,b,c,det;
const double normal_coeff = 1. / 12.;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
ab[0] = p1[0]-p0[0];
ab[1] = p1[1]-p0[1];
ab[2] = p1[2]-p0[2];
bc[0] = p2[0]-p1[0];
bc[1] = p2[1]-p1[1];
bc[2] = p2[2]-p1[2];
ac[0] = p2[0]-p0[0];
ac[1] = p2[1]-p0[1];
ac[2] = p2[2]-p0[2];
ad[0] = p3[0]-p0[0];
ad[1] = p3[1]-p0[1];
ad[2] = p3[2]-p0[2];
bd[0] = p3[0]-p1[0];
bd[1] = p3[1]-p1[1];
bd[2] = p3[2]-p1[2];
cd[0] = p3[0]-p2[0];
cd[1] = p3[1]-p2[1];
cd[2] = p3[2]-p2[2];
a = sqrt(vtkMath::Dot(ab,ab) * vtkMath::Dot(cd,cd));
b = sqrt(vtkMath::Dot(ac,ac) * vtkMath::Dot(bd,bd));
c = sqrt(vtkMath::Dot(ad,ad) * vtkMath::Dot(bc,bc));
vtkMath::Cross(ab,bc,u);
abc = vtkMath::Norm(u);
vtkMath::Cross(ab,ad,u);
abd = vtkMath::Norm(u);
vtkMath::Cross(ac,ad,u);
acd = vtkMath::Norm(u);
vtkMath::Cross(bc,cd,u);
bcd = vtkMath::Norm(u);
det = vtkMath::Determinant3x3(ab,ac,ad);
return normal_coeff * sqrt((a+b+c) * (a+b-c) * (a+c-b) * (b+c-a)) * (abc + abd + acd + bcd) \
/ (det * det);
}
double vtkMeshQuality::TetFrobeniusNorm( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double u[3],v[3],w[3];
double numerator,radicand;
const double normal_exp = 1./3.;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
u[0] = p1[0]-p0[0];
u[1] = p1[1]-p0[1];
u[2] = p1[2]-p0[2];
v[0] = p2[0]-p0[0];
v[1] = p2[1]-p0[1];
v[2] = p2[2]-p0[2];
w[0] = p3[0]-p0[0];
w[1] = p3[1]-p0[1];
w[2] = p3[2]-p0[2];
numerator = u[0] * u[0] + u[1] * u[1] + u[2] * u[2];
numerator += v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
numerator += w[0] * w[0] + w[1] * w[1] + w[2] * w[2];
numerator *= 1.5;
numerator -= v[0] * u[0] + v[1] * u[1] + v[2] * u[2];
numerator -= w[0] * u[0] + w[1] * u[1] + w[2] * u[2];
numerator -= w[0] * v[0] + w[1] * v[1] + w[2] * v[2];
radicand = vtkMath::Determinant3x3(u,v,w);
radicand *= radicand;
radicand *= 2.;
return numerator / (3. * pow(radicand,normal_exp));
}
double vtkMeshQuality::TetMinAngle( vtkCell* cell )
{
double p0[3],p1[3],p2[3],p3[3];
double ab[3],bc[3],ad[3],cd[3];
double abc[3],abd[3],acd[3],bcd[3];
double nabc,nabd,nacd,nbcd;
double alpha,beta,gamma,delta,epsilon,zeta;
const double normal_coeff = .3183098861837906715377675267450287;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
ab[0] = p1[0]-p0[0];
ab[1] = p1[1]-p0[1];
ab[2] = p1[2]-p0[2];
bc[0] = p2[0]-p1[0];
bc[1] = p2[1]-p1[1];
bc[2] = p2[2]-p1[2];
ad[0] = p3[0]-p0[0];
ad[1] = p3[1]-p0[1];
ad[2] = p3[2]-p0[2];
cd[0] = p3[0]-p2[0];
cd[1] = p3[1]-p2[1];
cd[2] = p3[2]-p2[2];
vtkMath::Cross(ab,bc,abc);
nabc = vtkMath::Norm(abc);
vtkMath::Cross(ab,ad,abd);
nabd = vtkMath::Norm(abd);
vtkMath::Cross(ad,cd,acd);
nacd = vtkMath::Norm(acd);
vtkMath::Cross(bc,cd,bcd);
nbcd = vtkMath::Norm(bcd);
alpha = acos(vtkMath::Dot(abc,abd) / (nabc * nabd));
beta = acos(vtkMath::Dot(abc,acd) / (nabc * nacd));
gamma = acos(vtkMath::Dot(abc,bcd) / (nabc * nbcd));
delta = acos(vtkMath::Dot(abd,acd) / (nabd * nacd));
epsilon = acos(vtkMath::Dot(abd,bcd) / (nabd * nbcd));
zeta = acos(vtkMath::Dot(acd,bcd) / (nacd * nbcd));
alpha = alpha < beta ? alpha : beta;
alpha = alpha < gamma ? alpha : gamma;
alpha = alpha < delta ? alpha : delta;
alpha = alpha < epsilon ? alpha : epsilon;
return (alpha < zeta ? alpha : zeta) * 180. * normal_coeff;
}
// Hexahedron quality measure:
// edge ratio
double vtkMeshQuality::HexEdgeRatio( vtkCell* cell)
{
double p0[3],p1[3],p2[3],p3[3];
double p4[3],p5[3],p6[3],p7[3];
double a[3],b[3],c[3],d[3],e[3],f[3];
double g[3],h[3],i[3],j[3],k[3],l[3];
double a2,b2,c2,d2,e2,f2;
double g2,h2,i2,j2,k2,l2;
double mab,mcd,mef,Mab,Mcd,Mef;
double mgh,mij,mkl,Mgh,Mij,Mkl;
double m2,M2;
vtkPoints *p = cell->GetPoints();
p->GetPoint(0, p0);
p->GetPoint(1, p1);
p->GetPoint(2, p2);
p->GetPoint(3, p3);
p->GetPoint(4, p4);
p->GetPoint(5, p5);
p->GetPoint(6, p6);
p->GetPoint(7, p7);
a[0] = p1[0]-p0[0];
a[1] = p1[1]-p0[1];
a[2] = p1[2]-p0[2];
b[0] = p2[0]-p1[0];
b[1] = p2[1]-p1[1];
b[2] = p2[2]-p1[2];
c[0] = p3[0]-p2[0];
c[1] = p3[1]-p2[1];
c[2] = p3[2]-p2[2];
d[0] = p0[0]-p3[0];
d[1] = p0[1]-p3[1];
d[2] = p0[2]-p3[2];
e[0] = p4[0]-p0[0];
e[1] = p4[1]-p0[1];
e[2] = p4[2]-p0[2];
f[0] = p5[0]-p1[0];
f[1] = p5[1]-p1[1];
f[2] = p5[2]-p1[2];
g[0] = p6[0]-p2[0];
g[1] = p6[1]-p2[1];
g[2] = p6[2]-p2[2];
h[0] = p7[0]-p3[0];
h[1] = p7[1]-p3[1];
h[2] = p7[2]-p3[2];
i[0] = p5[0]-p4[0];
i[1] = p5[1]-p4[1];
i[2] = p5[2]-p4[2];
j[0] = p6[0]-p5[0];
j[1] = p6[1]-p5[1];
j[2] = p6[2]-p5[2];
k[0] = p7[0]-p6[0];
k[1] = p7[1]-p6[1];
k[2] = p7[2]-p6[2];
l[0] = p4[0]-p7[0];
l[1] = p4[1]-p7[1];
l[2] = p4[2]-p7[2];
a2 = vtkMath::Dot(a,a);
b2 = vtkMath::Dot(b,b);
c2 = vtkMath::Dot(c,c);
d2 = vtkMath::Dot(d,d);
e2 = vtkMath::Dot(e,e);
f2 = vtkMath::Dot(f,f);
g2 = vtkMath::Dot(g,g);
h2 = vtkMath::Dot(h,h);
i2 = vtkMath::Dot(i,i);
j2 = vtkMath::Dot(j,j);
k2 = vtkMath::Dot(k,k);
l2 = vtkMath::Dot(l,l);
if ( a2 < b2 )
{
mab = a2;
Mab = b2;
}
else // b2 <= a2
{
mab = b2;
Mab = a2;
}
if ( c2 < d2 )
{
mcd = c2;
Mcd = d2;
}
else // d2 <= c2
{
mcd = d2;
Mcd = c2;
}
if ( e2 < f2 )
{
mef = e2;
Mef = f2;
}
else // f2 <= e2
{
mef = f2;
Mef = e2;
}
if ( g2 < h2 )
{
mgh = g2;
Mgh = h2;
}
else // h2 <= g2
{
mgh = h2;
Mgh = g2;
}
if ( i2 < j2 )
{
mij = i2;
Mij = j2;
}
else // j2 <= i2
{
mij = j2;
Mij = i2;
}
if ( k2 < l2 )
{
mkl = k2;
Mkl = l2;
}
else // l2 <= k2
{
mkl = l2;
Mkl = k2;
}
m2 = mab < mcd ? mab : mcd;
m2 = m2 < mef ? m2 : mef;
m2 = m2 < mgh ? m2 : mgh;
m2 = m2 < mij ? m2 : mij;
m2 = m2 < mkl ? m2 : mkl;
M2 = Mab > Mcd ? Mab : Mcd;
M2 = M2 > Mef ? M2 : Mef;
M2 = M2 > Mgh ? M2 : Mgh;
M2 = M2 > Mij ? M2 : Mij;
M2 = M2 > Mkl ? M2 : Mkl;
return sqrt(M2 / m2);
}