271 lines
5.5 KiB
C#
271 lines
5.5 KiB
C#
using System;
|
|
using TriangleNet.Geometry;
|
|
using TriangleNet.Topology;
|
|
|
|
namespace TriangleNet.Tools
|
|
{
|
|
public class QualityMeasure
|
|
{
|
|
private class AreaMeasure
|
|
{
|
|
public double area_min = double.MaxValue;
|
|
|
|
public double area_max = double.MinValue;
|
|
|
|
public double area_total;
|
|
|
|
public int area_zero;
|
|
|
|
public void Reset()
|
|
{
|
|
area_min = double.MaxValue;
|
|
area_max = double.MinValue;
|
|
area_total = 0.0;
|
|
area_zero = 0;
|
|
}
|
|
|
|
public double Measure(Point a, Point b, Point c)
|
|
{
|
|
double num = 0.5 * Math.Abs(a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y));
|
|
area_min = Math.Min(area_min, num);
|
|
area_max = Math.Max(area_max, num);
|
|
area_total += num;
|
|
if (num == 0.0)
|
|
{
|
|
area_zero++;
|
|
}
|
|
return num;
|
|
}
|
|
}
|
|
|
|
private class AlphaMeasure
|
|
{
|
|
public double alpha_min;
|
|
|
|
public double alpha_max;
|
|
|
|
public double alpha_ave;
|
|
|
|
public double alpha_area;
|
|
|
|
public void Reset()
|
|
{
|
|
alpha_min = double.MaxValue;
|
|
alpha_max = double.MinValue;
|
|
alpha_ave = 0.0;
|
|
alpha_area = 0.0;
|
|
}
|
|
|
|
private double acos(double c)
|
|
{
|
|
if (c <= -1.0)
|
|
{
|
|
return Math.PI;
|
|
}
|
|
if (1.0 <= c)
|
|
{
|
|
return 0.0;
|
|
}
|
|
return Math.Acos(c);
|
|
}
|
|
|
|
public double Measure(double ab, double bc, double ca, double area)
|
|
{
|
|
double val = double.MaxValue;
|
|
double num = ab * ab;
|
|
double num2 = bc * bc;
|
|
double num3 = ca * ca;
|
|
double val2;
|
|
double val3;
|
|
double val4;
|
|
if (ab != 0.0 || bc != 0.0 || ca != 0.0)
|
|
{
|
|
val2 = ((ca != 0.0 && ab != 0.0) ? acos((num3 + num - num2) / (2.0 * ca * ab)) : Math.PI);
|
|
val3 = ((ab != 0.0 && bc != 0.0) ? acos((num + num2 - num3) / (2.0 * ab * bc)) : Math.PI);
|
|
val4 = ((bc != 0.0 && ca != 0.0) ? acos((num2 + num3 - num) / (2.0 * bc * ca)) : Math.PI);
|
|
}
|
|
else
|
|
{
|
|
val2 = Math.PI * 2.0 / 3.0;
|
|
val3 = Math.PI * 2.0 / 3.0;
|
|
val4 = Math.PI * 2.0 / 3.0;
|
|
}
|
|
val = Math.Min(val, val2);
|
|
val = Math.Min(val, val3);
|
|
val = Math.Min(val, val4);
|
|
val = val * 3.0 / Math.PI;
|
|
alpha_ave += val;
|
|
alpha_area += area * val;
|
|
alpha_min = Math.Min(val, alpha_min);
|
|
alpha_max = Math.Max(val, alpha_max);
|
|
return val;
|
|
}
|
|
|
|
public void Normalize(int n, double area_total)
|
|
{
|
|
if (n > 0)
|
|
{
|
|
alpha_ave /= n;
|
|
}
|
|
else
|
|
{
|
|
alpha_ave = 0.0;
|
|
}
|
|
if (0.0 < area_total)
|
|
{
|
|
alpha_area /= area_total;
|
|
}
|
|
else
|
|
{
|
|
alpha_area = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class Q_Measure
|
|
{
|
|
public double q_min;
|
|
|
|
public double q_max;
|
|
|
|
public double q_ave;
|
|
|
|
public double q_area;
|
|
|
|
public void Reset()
|
|
{
|
|
q_min = double.MaxValue;
|
|
q_max = double.MinValue;
|
|
q_ave = 0.0;
|
|
q_area = 0.0;
|
|
}
|
|
|
|
public double Measure(double ab, double bc, double ca, double area)
|
|
{
|
|
double num = (bc + ca - ab) * (ca + ab - bc) * (ab + bc - ca) / (ab * bc * ca);
|
|
q_min = Math.Min(q_min, num);
|
|
q_max = Math.Max(q_max, num);
|
|
q_ave += num;
|
|
q_area += num * area;
|
|
return num;
|
|
}
|
|
|
|
public void Normalize(int n, double area_total)
|
|
{
|
|
if (n > 0)
|
|
{
|
|
q_ave /= n;
|
|
}
|
|
else
|
|
{
|
|
q_ave = 0.0;
|
|
}
|
|
if (area_total > 0.0)
|
|
{
|
|
q_area /= area_total;
|
|
}
|
|
else
|
|
{
|
|
q_area = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
private AreaMeasure areaMeasure;
|
|
|
|
private AlphaMeasure alphaMeasure;
|
|
|
|
private Q_Measure qMeasure;
|
|
|
|
private Mesh mesh;
|
|
|
|
public double AreaMinimum => areaMeasure.area_min;
|
|
|
|
public double AreaMaximum => areaMeasure.area_max;
|
|
|
|
public double AreaRatio => areaMeasure.area_max / areaMeasure.area_min;
|
|
|
|
public double AlphaMinimum => alphaMeasure.alpha_min;
|
|
|
|
public double AlphaMaximum => alphaMeasure.alpha_max;
|
|
|
|
public double AlphaAverage => alphaMeasure.alpha_ave;
|
|
|
|
public double AlphaArea => alphaMeasure.alpha_area;
|
|
|
|
public double Q_Minimum => qMeasure.q_min;
|
|
|
|
public double Q_Maximum => qMeasure.q_max;
|
|
|
|
public double Q_Average => qMeasure.q_ave;
|
|
|
|
public double Q_Area => qMeasure.q_area;
|
|
|
|
public QualityMeasure()
|
|
{
|
|
areaMeasure = new AreaMeasure();
|
|
alphaMeasure = new AlphaMeasure();
|
|
qMeasure = new Q_Measure();
|
|
}
|
|
|
|
public void Update(Mesh mesh)
|
|
{
|
|
this.mesh = mesh;
|
|
areaMeasure.Reset();
|
|
alphaMeasure.Reset();
|
|
qMeasure.Reset();
|
|
Compute();
|
|
}
|
|
|
|
private void Compute()
|
|
{
|
|
int num = 0;
|
|
foreach (Triangle triangle in mesh.triangles)
|
|
{
|
|
num++;
|
|
Point point = triangle.vertices[0];
|
|
Point point2 = triangle.vertices[1];
|
|
Point point3 = triangle.vertices[2];
|
|
double num2 = point.x - point2.x;
|
|
double num3 = point.y - point2.y;
|
|
double ab = Math.Sqrt(num2 * num2 + num3 * num3);
|
|
double num4 = point2.x - point3.x;
|
|
num3 = point2.y - point3.y;
|
|
double bc = Math.Sqrt(num4 * num4 + num3 * num3);
|
|
double num5 = point3.x - point.x;
|
|
num3 = point3.y - point.y;
|
|
double ca = Math.Sqrt(num5 * num5 + num3 * num3);
|
|
double area = areaMeasure.Measure(point, point2, point3);
|
|
alphaMeasure.Measure(ab, bc, ca, area);
|
|
qMeasure.Measure(ab, bc, ca, area);
|
|
}
|
|
alphaMeasure.Normalize(num, areaMeasure.area_total);
|
|
qMeasure.Normalize(num, areaMeasure.area_total);
|
|
}
|
|
|
|
public int Bandwidth()
|
|
{
|
|
if (mesh == null)
|
|
{
|
|
return 0;
|
|
}
|
|
int num = 0;
|
|
int num2 = 0;
|
|
foreach (Triangle triangle in mesh.triangles)
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
int id = triangle.GetVertex(i).id;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
int id2 = triangle.GetVertex(j).id;
|
|
num2 = Math.Max(num2, id2 - id);
|
|
num = Math.Max(num, id - id2);
|
|
}
|
|
}
|
|
}
|
|
return num + 1 + num2;
|
|
}
|
|
}
|
|
}
|