Files
2026-03-04 10:03:45 +08:00

247 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using TriangleNet.Geometry;
using TriangleNet.Topology;
namespace TriangleNet.Voronoi.Legacy
{
[Obsolete("Use TriangleNet.Voronoi.StandardVoronoi class instead.")]
public class SimpleVoronoi : IVoronoi
{
private IPredicates predicates = RobustPredicates.Default;
private Mesh mesh;
private Point[] points;
private Dictionary<int, VoronoiRegion> regions;
private Dictionary<int, Point> rayPoints;
private int rayIndex;
private Rectangle bounds;
public Point[] Points => points;
public ICollection<VoronoiRegion> Regions => regions.Values;
public IEnumerable<IEdge> Edges => EnumerateEdges();
public SimpleVoronoi(Mesh mesh)
{
this.mesh = mesh;
Generate();
}
private void Generate()
{
mesh.Renumber();
mesh.MakeVertexMap();
points = new Point[mesh.triangles.Count + mesh.hullsize];
regions = new Dictionary<int, VoronoiRegion>(mesh.vertices.Count);
rayPoints = new Dictionary<int, Point>();
rayIndex = 0;
bounds = new Rectangle();
ComputeCircumCenters();
foreach (Vertex value in mesh.vertices.Values)
{
regions.Add(value.id, new VoronoiRegion(value));
}
foreach (VoronoiRegion value2 in regions.Values)
{
ConstructCell(value2);
}
}
private void ComputeCircumCenters()
{
Otri otri = default(Otri);
double xi = 0.0;
double eta = 0.0;
foreach (Triangle triangle2 in mesh.triangles)
{
Triangle triangle = (otri.tri = triangle2);
Point point = predicates.FindCircumcenter(otri.Org(), otri.Dest(), otri.Apex(), ref xi, ref eta);
point.id = triangle.id;
points[triangle.id] = point;
bounds.Expand(point);
}
double num = Math.Max(bounds.Width, bounds.Height);
bounds.Resize(num, num);
}
private void ConstructCell(VoronoiRegion region)
{
Vertex obj = region.Generator as Vertex;
List<Point> list = new List<Point>();
Otri ot = default(Otri);
Otri ot2 = default(Otri);
Otri ot3 = default(Otri);
Otri ot4 = default(Otri);
Osub os = default(Osub);
obj.tri.Copy(ref ot2);
ot2.Copy(ref ot);
ot2.Onext(ref ot3);
if (ot3.tri.id == -1)
{
ot2.Oprev(ref ot4);
if (ot4.tri.id != -1)
{
ot2.Copy(ref ot3);
ot2.Oprev();
ot2.Copy(ref ot);
}
}
while (ot3.tri.id != -1)
{
list.Add(points[ot.tri.id]);
region.AddNeighbor(ot.tri.id, regions[ot.Apex().id]);
if (ot3.Equals(ot2))
{
region.Add(list);
return;
}
ot3.Copy(ref ot);
ot3.Onext();
}
region.Bounded = false;
int count = mesh.triangles.Count;
ot.Lprev(ref ot3);
ot3.Pivot(ref os);
int hash = os.seg.hash;
list.Add(points[ot.tri.id]);
region.AddNeighbor(ot.tri.id, regions[ot.Apex().id]);
if (!rayPoints.TryGetValue(hash, out var value))
{
Vertex vertex = ot.Org();
Vertex vertex2 = ot.Apex();
BoxRayIntersection(points[ot.tri.id], vertex.y - vertex2.y, vertex2.x - vertex.x, out value);
value.id = count + rayIndex;
points[count + rayIndex] = value;
rayIndex++;
rayPoints.Add(hash, value);
}
list.Add(value);
list.Reverse();
ot2.Copy(ref ot);
ot.Oprev(ref ot4);
while (ot4.tri.id != -1)
{
list.Add(points[ot4.tri.id]);
region.AddNeighbor(ot4.tri.id, regions[ot4.Apex().id]);
ot4.Copy(ref ot);
ot4.Oprev();
}
ot.Pivot(ref os);
hash = os.seg.hash;
if (!rayPoints.TryGetValue(hash, out value))
{
Vertex vertex = ot.Org();
Vertex vertex3 = ot.Dest();
BoxRayIntersection(points[ot.tri.id], vertex3.y - vertex.y, vertex.x - vertex3.x, out value);
value.id = count + rayIndex;
rayPoints.Add(hash, value);
points[count + rayIndex] = value;
rayIndex++;
}
list.Add(value);
region.AddNeighbor(value.id, regions[ot.Dest().id]);
list.Reverse();
region.Add(list);
}
private bool BoxRayIntersection(Point pt, double dx, double dy, out Point intersect)
{
double x = pt.x;
double y = pt.y;
double left = bounds.Left;
double right = bounds.Right;
double bottom = bounds.Bottom;
double top = bounds.Top;
if (x < left || x > right || y < bottom || y > top)
{
intersect = null;
return false;
}
double num;
double x2;
double y2;
if (dx < 0.0)
{
num = (left - x) / dx;
x2 = left;
y2 = y + num * dy;
}
else if (dx > 0.0)
{
num = (right - x) / dx;
x2 = right;
y2 = y + num * dy;
}
else
{
num = double.MaxValue;
x2 = (y2 = 0.0);
}
double num2;
double x3;
double y3;
if (dy < 0.0)
{
num2 = (bottom - y) / dy;
x3 = x + num2 * dx;
y3 = bottom;
}
else if (dy > 0.0)
{
num2 = (top - y) / dy;
x3 = x + num2 * dx;
y3 = top;
}
else
{
num2 = double.MaxValue;
x3 = (y3 = 0.0);
}
if (num < num2)
{
intersect = new Point(x2, y2);
}
else
{
intersect = new Point(x3, y3);
}
return true;
}
private IEnumerable<IEdge> EnumerateEdges()
{
List<IEdge> list = new List<IEdge>(Regions.Count * 2);
foreach (VoronoiRegion region in Regions)
{
Point point = null;
Point point2 = null;
foreach (Point vertex in region.Vertices)
{
if (point == null)
{
point = vertex;
point2 = vertex;
}
else
{
list.Add(new Edge(point2.id, vertex.id));
point2 = vertex;
}
}
if (region.Bounded && point != null)
{
list.Add(new Edge(point2.id, point.id));
}
}
return list;
}
}
}