Minor changes to (standard) Voronoi diagram

git-svn-id: https://triangle.svn.codeplex.com/svn@74966 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2014-05-12 17:13:51 +00:00
parent 4963b68eef
commit 94fafe03c0
16 changed files with 285 additions and 184 deletions
+8 -8
View File
@@ -69,10 +69,10 @@ namespace MeshRenderer.Core
}
this.Bounds = new BoundingBox(
(float)data.Bounds.Xmin,
(float)data.Bounds.Xmax,
(float)data.Bounds.Ymin,
(float)data.Bounds.Ymax);
(float)data.Bounds.MinX,
(float)data.Bounds.MaxX,
(float)data.Bounds.MinY,
(float)data.Bounds.MaxY);
}
/// <summary>
@@ -150,10 +150,10 @@ namespace MeshRenderer.Core
this.Triangles = triangles.ToArray();
this.Bounds = new BoundingBox(
(float)mesh.Bounds.Xmin,
(float)mesh.Bounds.Xmax,
(float)mesh.Bounds.Ymin,
(float)mesh.Bounds.Ymax);
(float)mesh.Bounds.MinX,
(float)mesh.Bounds.MaxX,
(float)mesh.Bounds.MinY,
(float)mesh.Bounds.MaxY);
}
/// <summary>
+40 -22
View File
@@ -8,6 +8,7 @@ using MeshExplorer.IO;
using MeshRenderer.Core;
using TriangleNet;
using TriangleNet.Geometry;
using TriangleNet.Log;
using TriangleNet.Tools;
namespace MeshExplorer
@@ -340,31 +341,38 @@ namespace MeshExplorer
private bool Open(string filename)
{
if (FileProcessor.ContainsMeshData(filename))
if (!FileProcessor.CanHandleFile(filename))
{
if (DarkMessageBox.Show("Import mesh", Settings.ImportString,
"Do you want to import the mesh?", MessageBoxButtons.YesNo) == DialogResult.OK)
{
input = null;
mesh = FileProcessor.Import(filename);
if (mesh != null)
{
statisticView.UpdateStatistic(mesh);
// Update settings
settings.CurrentFile = Path.GetFileName(filename);
HandleMeshImport();
btnSmooth.Enabled = true; // TODO: Remove
}
// else Message
return true;
}
// TODO: show message.
}
else
{
if (FileProcessor.ContainsMeshData(filename))
{
if (DarkMessageBox.Show("Import mesh", Settings.ImportString,
"Do you want to import the mesh?", MessageBoxButtons.YesNo) == DialogResult.OK)
{
input = null;
mesh = FileProcessor.Import(filename);
input = FileProcessor.Read(filename);
if (mesh != null)
{
statisticView.UpdateStatistic(mesh);
// Update settings
settings.CurrentFile = Path.GetFileName(filename);
HandleMeshImport();
btnSmooth.Enabled = true; // TODO: Remove
}
// else Message
return true;
}
}
input = FileProcessor.Read(filename);
}
if (input != null)
{
@@ -737,6 +745,16 @@ namespace MeshExplorer
Behavior.Verbose = save;
if (isConsistent)
{
SimpleLog.Instance.Info("Mesh topology appears to be consistent.");
}
if (isDelaunay)
{
SimpleLog.Instance.Info("Mesh is (conforming) Delaunay.");
}
ShowLog();
}
}
+4 -4
View File
@@ -321,10 +321,10 @@ namespace MeshExplorer.IO
private void UpdateMetrics(BoundingBox bounds)
{
x_max = bounds.Xmax;
x_min = bounds.Xmin;
y_max = bounds.Ymax;
y_min = bounds.Ymin;
x_max = bounds.MaxX;
x_min = bounds.MinX;
y_max = bounds.MaxY;
y_min = bounds.MinY;
// Enlarge width 5% on each side
x_scale = x_max - x_min;
+2 -2
View File
@@ -49,8 +49,8 @@ namespace MeshExplorer.IO
scale = width / ((float)bounds.Width + 2 * margin);
int x_offset = -(int)((bounds.Xmin - margin) * scale);
int y_offset = (int)((bounds.Ymax + margin) * scale);
int x_offset = -(int)((bounds.MinX - margin) * scale);
int y_offset = (int)((bounds.MaxY + margin) * scale);
int height = (int)((bounds.Height + 2 * margin) * scale);
@@ -48,8 +48,8 @@ namespace MeshExplorer.Topology
//zoom.ClipMargin = 10.0f;
var b = mesh.Bounds;
zoom.Update(new BoundingBox((float)b.Xmin, (float)b.Xmax,
(float)b.Ymin, (float)b.Ymax));
zoom.Update(new BoundingBox((float)b.MinX, (float)b.MaxX,
(float)b.MinY, (float)b.MaxY));
InitializeBuffer();
@@ -42,9 +42,9 @@ namespace TriangleNet.Algorithm
width = 1.0;
}
// Create the vertices of the bounding box.
mesh.infvertex1 = new Vertex(box.Xmin - 50.0 * width, box.Ymin - 40.0 * width);
mesh.infvertex2 = new Vertex(box.Xmax + 50.0 * width, box.Ymin - 40.0 * width);
mesh.infvertex3 = new Vertex(0.5 * (box.Xmin + box.Xmax), box.Ymax + 60.0 * width);
mesh.infvertex1 = new Vertex(box.MinX - 50.0 * width, box.MinY - 40.0 * width);
mesh.infvertex2 = new Vertex(box.MaxX + 50.0 * width, box.MinY - 40.0 * width);
mesh.infvertex3 = new Vertex(0.5 * (box.MinX + box.MaxX), box.MaxY + 60.0 * width);
// Create the bounding box.
mesh.MakeTriangle(ref inftri);
+2 -2
View File
@@ -525,7 +525,7 @@ namespace TriangleNet.Algorithm
// Nonexistent x value used as a flag to mark circle events in sweepline
// Delaunay algorithm.
xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax;
xminextreme = 10 * mesh.bounds.MinX - 9 * mesh.bounds.MaxX;
SweepEvent[] eventheap;
@@ -603,7 +603,7 @@ namespace TriangleNet.Algorithm
HeapDelete(eventheap, heapsize, 0);
heapsize--;
check4events = true;
if (nextevent.xkey < mesh.bounds.Xmin)
if (nextevent.xkey < mesh.bounds.MinX)
{
fliptri = nextevent.otriEvent;
fliptri.Oprev(ref farlefttri);
+53 -26
View File
@@ -19,11 +19,13 @@ namespace TriangleNet.Geometry
/// Initializes a new instance of the <see cref="BoundingBox" /> class.
/// </summary>
public BoundingBox()
: this(double.MaxValue, double.MaxValue, -double.MaxValue, -double.MaxValue)
{
}
public BoundingBox(BoundingBox other)
: this(other.MinX, other.MinY, other.MaxX, other.MaxY)
{
xmin = double.MaxValue;
ymin = double.MaxValue;
xmax = -double.MaxValue;
ymax = -double.MaxValue;
}
/// <summary>
@@ -37,39 +39,39 @@ namespace TriangleNet.Geometry
public BoundingBox(double xmin, double ymin, double xmax, double ymax)
{
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
this.ymin = ymin;
this.ymax = ymax;
}
/// <summary>
/// Gets the minimum x value (left boundary).
/// </summary>
public double Xmin
public double MinX
{
get { return xmin; }
}
/// <summary>
/// Gets the minimum y value (bottom boundary).
/// </summary>
public double Ymin
{
get { return ymin; }
}
/// <summary>
/// Gets the maximum x value (right boundary).
/// </summary>
public double Xmax
public double MaxX
{
get { return xmax; }
}
/// <summary>
/// Gets the minimum y value (bottom boundary).
/// </summary>
public double MinY
{
get { return ymin; }
}
/// <summary>
/// Gets the maximum y value (top boundary).
/// </summary>
public double Ymax
public double MaxY
{
get { return ymax; }
}
@@ -91,11 +93,24 @@ namespace TriangleNet.Geometry
}
/// <summary>
/// Update bounds.
/// Scale bounds.
/// </summary>
/// <param name="dx">Add dx to left and right bounds.</param>
/// <param name="dy">Add dy to top and bottom bounds.</param>
public void Resize(double dx, double dy)
{
xmin -= dx;
xmax += dx;
ymin -= dy;
ymax += dy;
}
/// <summary>
/// Expand rectangle to include given point.
/// </summary>
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
public void Update(double x, double y)
public void Expand(double x, double y)
{
xmin = Math.Min(xmin, x);
ymin = Math.Min(ymin, y);
@@ -104,16 +119,16 @@ namespace TriangleNet.Geometry
}
/// <summary>
/// Scale bounds.
/// Expand rectangle to include given rectangle.
/// </summary>
/// <param name="dx">Add dx to left and right bounds.</param>
/// <param name="dy">Add dy to top and bottom bounds.</param>
public void Scale(double dx, double dy)
/// <param name="x">X coordinate.</param>
/// <param name="y">Y coordinate.</param>
public void Expand(BoundingBox other)
{
xmin -= dx;
xmax += dx;
ymin -= dy;
ymax += dy;
xmin = Math.Min(xmin, other.xmin);
ymin = Math.Min(ymin, other.ymin);
xmax = Math.Max(xmax, other.xmax);
ymax = Math.Max(ymax, other.ymax);
}
/// <summary>
@@ -125,5 +140,17 @@ namespace TriangleNet.Geometry
{
return ((pt.x >= xmin) && (pt.x <= xmax) && (pt.y >= ymin) && (pt.y <= ymax));
}
public bool Contains(BoundingBox other)
{
return (xmin <= other.MinX && other.MaxX <= xmax
&& ymin <= other.MinY && other.MaxY <= ymax);
}
public bool Intersects(BoundingBox other)
{
return (other.MinX < xmax && xmin < other.MaxX
&& other.MinY < ymax && ymin < other.MaxY);
}
}
}
@@ -139,7 +139,7 @@ namespace TriangleNet.Geometry
public void AddPoint(double x, double y, int boundary)
{
points.Add(new Vertex(x, y, boundary));
bounds.Update(x, y);
bounds.Expand(x, y);
}
/// <summary>
@@ -177,7 +177,7 @@ namespace TriangleNet.Geometry
}
points.Add(new Vertex(x, y, boundary) { attributes = attribs });
bounds.Update(x, y);
bounds.Expand(x, y);
}
/// <summary>
@@ -202,7 +202,7 @@ namespace TriangleNet.Geometry
}
points.Add(v);
bounds.Update(v.x, v.y);
bounds.Expand(v.x, v.y);
}
/// <summary>
+61 -38
View File
@@ -43,16 +43,21 @@ namespace TriangleNet
triorg = tri.Org();
tridest = tri.Dest();
if (tri.orient == 0)
{ // Only test for inversion once.
{
// Only test for inversion once.
// Test if the triangle is flat or inverted.
triapex = tri.Apex();
if (Primitives.CounterClockwise(triorg, tridest, triapex) <= 0.0)
{
logger.Warning("Triangle is flat or inverted.",
"Quality.CheckMesh()");
if (Behavior.Verbose)
{
logger.Warning("Triangle is flat or inverted.", "Quality.CheckMesh()");
}
horrors++;
}
}
// Find the neighboring triangle on this edge.
tri.Sym(ref oppotri);
if (oppotri.triangle != Mesh.dummytri)
@@ -61,7 +66,7 @@ namespace TriangleNet
oppotri.Sym(ref oppooppotri);
if ((tri.triangle != oppooppotri.triangle) || (tri.orient != oppooppotri.orient))
{
if (tri.triangle == oppooppotri.triangle)
if (tri.triangle == oppooppotri.triangle && Behavior.Verbose)
{
logger.Warning("Asymmetric triangle-triangle bond: (Right triangle, wrong orientation)",
"Quality.CheckMesh()");
@@ -75,8 +80,11 @@ namespace TriangleNet
oppodest = oppotri.Dest();
if ((triorg != oppodest) || (tridest != oppoorg))
{
logger.Warning("Mismatched edge coordinates between two triangles.",
"Quality.CheckMesh()");
if (Behavior.Verbose)
{
logger.Warning("Mismatched edge coordinates between two triangles.",
"Quality.CheckMesh()");
}
horrors++;
}
@@ -88,18 +96,13 @@ namespace TriangleNet
mesh.MakeVertexMap();
foreach (var v in mesh.vertices.Values)
{
if (v.tri.triangle == null)
if (v.tri.triangle == null && Behavior.Verbose)
{
logger.Warning("Vertex (ID " + v.id + ") not connected to mesh (duplicate input vertex?)",
"Quality.CheckMesh()");
}
}
if (horrors == 0) // && Behavior.Verbose
{
logger.Info("Mesh topology appears to be consistent.");
}
// Restore the status of exact arithmetic.
Behavior.NoExact = saveexact;
@@ -107,15 +110,32 @@ namespace TriangleNet
}
/// <summary>
/// Ensure that the mesh is (constrained) Delaunay.
/// Check if the mesh is (conforming) Delaunay.
/// </summary>
public static bool IsDelaunay(Mesh mesh)
{
return IsDelaunay(mesh, false);
}
/// <summary>
/// Check if that the mesh is (constrained) Delaunay.
/// </summary>
public static bool IsConstrainedDelaunay(Mesh mesh)
{
return IsDelaunay(mesh, true);
}
/// <summary>
/// Ensure that the mesh is (constrained) Delaunay.
/// </summary>
private static bool IsDelaunay(Mesh mesh, bool constrained)
{
Otri loop = default(Otri);
Otri oppotri = default(Otri);
Osub opposubseg = default(Osub);
Vertex triorg, tridest, triapex;
Vertex org, dest, apex;
Vertex oppoapex;
Vertex inf1, inf2, inf3;
bool shouldbedelaunay;
int horrors;
bool saveexact;
@@ -127,49 +147,57 @@ namespace TriangleNet
Behavior.NoExact = false;
horrors = 0;
inf1 = mesh.infvertex1;
inf2 = mesh.infvertex2;
inf3 = mesh.infvertex3;
// Run through the list of triangles, checking each one.
foreach (var tri in mesh.triangles.Values)
{
loop.triangle = tri;
// Check all three edges of the triangle.
for (loop.orient = 0; loop.orient < 3;
loop.orient++)
for (loop.orient = 0; loop.orient < 3; loop.orient++)
{
triorg = loop.Org();
tridest = loop.Dest();
triapex = loop.Apex();
org = loop.Org();
dest = loop.Dest();
apex = loop.Apex();
loop.Sym(ref oppotri);
oppoapex = oppotri.Apex();
// Only test that the edge is locally Delaunay if there is an
// adjoining triangle whose pointer is larger (to ensure that
// each pair isn't tested twice).
shouldbedelaunay = (oppotri.triangle != Mesh.dummytri) &&
!Otri.IsDead(oppotri.triangle) && loop.triangle.id < oppotri.triangle.id &&
(triorg != mesh.infvertex1) && (triorg != mesh.infvertex2) &&
(triorg != mesh.infvertex3) &&
(tridest != mesh.infvertex1) && (tridest != mesh.infvertex2) &&
(tridest != mesh.infvertex3) &&
(triapex != mesh.infvertex1) && (triapex != mesh.infvertex2) &&
(triapex != mesh.infvertex3) &&
(oppoapex != mesh.infvertex1) && (oppoapex != mesh.infvertex2) &&
(oppoapex != mesh.infvertex3);
if (mesh.checksegments && shouldbedelaunay)
shouldbedelaunay = (loop.triangle.id < oppotri.triangle.id) &&
!Otri.IsDead(oppotri.triangle) && (oppotri.triangle != Mesh.dummytri) &&
(org != inf1) && (org != inf2) && (org != inf3) &&
(dest != inf1) && (dest != inf2) && (dest != inf3) &&
(apex != inf1) && (apex != inf2) && (apex != inf3) &&
(oppoapex != inf1) && (oppoapex != inf2) && (oppoapex != inf3);
if (constrained && mesh.checksegments && shouldbedelaunay)
{
// If a subsegment separates the triangles, then the edge is
// constrained, so no local Delaunay test should be done.
loop.SegPivot(ref opposubseg);
if (opposubseg.seg != Mesh.dummysub)
{
shouldbedelaunay = false;
}
}
if (shouldbedelaunay)
{
if (Primitives.NonRegular(triorg, tridest, triapex, oppoapex) > 0.0)
if (Primitives.NonRegular(org, dest, apex, oppoapex) > 0.0)
{
logger.Warning(String.Format("Non-regular pair of triangles found (IDs {0}/{1}).",
loop.triangle.id, oppotri.triangle.id), "Quality.CheckDelaunay()");
if (Behavior.Verbose)
{
logger.Warning(String.Format("Non-regular pair of triangles found (IDs {0}/{1}).",
loop.triangle.id, oppotri.triangle.id), "Quality.CheckDelaunay()");
}
horrors++;
}
}
@@ -177,11 +205,6 @@ namespace TriangleNet
}
if (horrors == 0) // && Behavior.Verbose
{
logger.Info("Mesh is Delaunay.");
}
// Restore the status of exact arithmetic.
Behavior.NoExact = saveexact;
@@ -1,5 +1,6 @@
// -----------------------------------------------------------------------
// <copyright file="AdjacencyMatrix.cs" company="">
// Original Matlab code by John Burkardt, Florida State University
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
@@ -67,7 +67,7 @@ namespace TriangleNet.Tools
/// <summary>
/// Gets the list of Voronoi regions.
/// </summary>
public List<VoronoiRegion> Regions
public ICollection<VoronoiRegion> Regions
{
get { return regions; }
}
@@ -95,11 +95,11 @@ namespace TriangleNet.Tools
// TODO: Need a reliable way to check if a vertex is on a segment
if (v.type == VertexType.FreeVertex || v.Boundary == 0)
{
ConstructBvdCell(v);
ConstructCell(v);
}
else if (includeBoundary)
{
ConstructBoundaryBvdCell(v);
ConstructBoundaryCell(v);
}
}
@@ -262,7 +262,7 @@ namespace TriangleNet.Tools
return false;
}
private void ConstructBvdCell(Vertex vertex)
private void ConstructCell(Vertex vertex)
{
VoronoiRegion region = new VoronoiRegion(vertex);
regions.Add(region);
@@ -374,7 +374,7 @@ namespace TriangleNet.Tools
region.Add(vpoints);
}
private void ConstructBoundaryBvdCell(Vertex vertex)
private void ConstructBoundaryCell(Vertex vertex)
{
VoronoiRegion region = new VoronoiRegion(vertex);
regions.Add(region);
+2 -2
View File
@@ -10,7 +10,7 @@ namespace TriangleNet.Tools
using TriangleNet.Geometry;
/// <summary>
/// TODO: Update summary.
/// Voronoi diagram interface.
/// </summary>
public interface IVoronoi
{
@@ -22,6 +22,6 @@ namespace TriangleNet.Tools
/// <summary>
/// Gets the list of Voronoi regions.
/// </summary>
List<VoronoiRegion> Regions { get; }
ICollection<VoronoiRegion> Regions { get; }
}
}
+22 -22
View File
@@ -150,8 +150,8 @@ namespace TriangleNet.Tools
{
this.tree = tree;
this.bounds = new BoundingBox(box.Xmin, box.Ymin, box.Xmax, box.Ymax);
this.pivot = new Point((box.Xmin + box.Xmax) / 2, (box.Ymin + box.Ymax) / 2);
this.bounds = new BoundingBox(box.MinX, box.MinY, box.MaxX, box.MaxY);
this.pivot = new Point((box.MinX + box.MaxX) / 2, (box.MinY + box.MaxY) / 2);
this.bitRegions = 0;
@@ -193,19 +193,19 @@ namespace TriangleNet.Tools
BoundingBox box;
// 1. region south west
box = new BoundingBox(bounds.Xmin, bounds.Ymin, pivot.X, pivot.Y);
box = new BoundingBox(bounds.MinX, bounds.MinY, pivot.X, pivot.Y);
regions[0] = new QuadNode(box, tree);
// 2. region south east
box = new BoundingBox(pivot.X, bounds.Ymin, bounds.Xmax, pivot.Y);
box = new BoundingBox(pivot.X, bounds.MinY, bounds.MaxX, pivot.Y);
regions[1] = new QuadNode(box, tree);
// 3. region north west
box = new BoundingBox(bounds.Xmin, pivot.Y, pivot.X, bounds.Ymax);
box = new BoundingBox(bounds.MinX, pivot.Y, pivot.X, bounds.MaxY);
regions[2] = new QuadNode(box, tree);
// 4. region north east
box = new BoundingBox(pivot.X, pivot.Y, bounds.Xmax, bounds.Ymax);
box = new BoundingBox(pivot.X, pivot.Y, bounds.MaxX, bounds.MaxY);
regions[3] = new QuadNode(box, tree);
Point[] triangle = new Point[3];
@@ -295,12 +295,12 @@ namespace TriangleNet.Tools
// we have an intersection
double yComponent = triangle[k].Y + t * dy;
if (yComponent < pivot.Y && yComponent >= bounds.Ymin)
if (yComponent < pivot.Y && yComponent >= bounds.MinY)
{
AddToRegion(index, SW);
AddToRegion(index, SE);
}
else if (yComponent <= bounds.Ymax)
else if (yComponent <= bounds.MaxY)
{
AddToRegion(index, NW);
AddToRegion(index, NE);
@@ -308,34 +308,34 @@ namespace TriangleNet.Tools
}
// find intersection with plane x = m_boundingBox[0].dX
t = (bounds.Xmin - triangle[k].X) / dx;
t = (bounds.MinX - triangle[k].X) / dx;
if (t < (1 + EPS) && t > -EPS)
{
// we have an intersection
double yComponent = triangle[k].Y + t * dy;
if (yComponent < pivot.Y && yComponent >= bounds.Ymin)
if (yComponent < pivot.Y && yComponent >= bounds.MinY)
{
AddToRegion(index, SW);
}
else if (yComponent <= bounds.Ymax) // TODO: check && yComponent >= pivot.Y
else if (yComponent <= bounds.MaxY) // TODO: check && yComponent >= pivot.Y
{
AddToRegion(index, NW);
}
}
// find intersection with plane x = m_boundingBox[1].dX
t = (bounds.Xmax - triangle[k].X) / dx;
t = (bounds.MaxX - triangle[k].X) / dx;
if (t < (1 + EPS) && t > -EPS)
{
// we have an intersection
double yComponent = triangle[k].Y + t * dy;
if (yComponent < pivot.Y && yComponent >= bounds.Ymin)
if (yComponent < pivot.Y && yComponent >= bounds.MinY)
{
AddToRegion(index, SE);
}
else if (yComponent <= bounds.Ymax)
else if (yComponent <= bounds.MaxY)
{
AddToRegion(index, NE);
}
@@ -353,12 +353,12 @@ namespace TriangleNet.Tools
// we have an intersection
xComponent = triangle[k].X + t * dx;
if (xComponent > pivot.X && xComponent <= bounds.Xmax)
if (xComponent > pivot.X && xComponent <= bounds.MaxX)
{
AddToRegion(index, SE);
AddToRegion(index, NE);
}
else if (xComponent >= bounds.Xmin)
else if (xComponent >= bounds.MinX)
{
AddToRegion(index, SW);
AddToRegion(index, NW);
@@ -366,34 +366,34 @@ namespace TriangleNet.Tools
}
// find intersection with plane y = m_boundingBox[0].dY
t = (bounds.Ymin - triangle[k].Y) / dy;
t = (bounds.MinY - triangle[k].Y) / dy;
if (t < (1 + EPS) && t > -EPS)
{
// we have an intersection
xComponent = triangle[k].X + t * dx;
if (xComponent > pivot.X && xComponent <= bounds.Xmax)
if (xComponent > pivot.X && xComponent <= bounds.MaxX)
{
AddToRegion(index, SE);
}
else if (xComponent >= bounds.Xmin)
else if (xComponent >= bounds.MinX)
{
AddToRegion(index, SW);
}
}
// find intersection with plane y = m_boundingBox[1].dY
t = (bounds.Ymax - triangle[k].Y) / dy;
t = (bounds.MaxY - triangle[k].Y) / dy;
if (t < (1 + EPS) && t > -EPS)
{
// we have an intersection
xComponent = triangle[k].X + t * dx;
if (xComponent > pivot.X && xComponent <= bounds.Xmax)
if (xComponent > pivot.X && xComponent <= bounds.MaxX)
{
AddToRegion(index, NE);
}
else if (xComponent >= bounds.Xmin)
else if (xComponent >= bounds.MinX)
{
AddToRegion(index, NW);
}
+44 -41
View File
@@ -20,9 +20,9 @@ namespace TriangleNet.Tools
Mesh mesh;
Point[] points;
List<VoronoiRegion> regions;
Dictionary<int, VoronoiRegion> regions;
// Stores the endpoints of rays of infinite Voronoi cells
// Stores the endpoints of rays of unbounded Voronoi cells
Dictionary<int, Point> rayPoints;
int rayIndex;
@@ -54,9 +54,9 @@ namespace TriangleNet.Tools
/// <summary>
/// Gets the list of Voronoi regions.
/// </summary>
public List<VoronoiRegion> Regions
public ICollection<VoronoiRegion> Regions
{
get { return regions; }
get { return regions.Values; }
}
/// <summary>
@@ -77,7 +77,7 @@ namespace TriangleNet.Tools
// Allocate space for voronoi diagram
this.points = new Point[mesh.triangles.Count + mesh.hullsize];
this.regions = new List<VoronoiRegion>(mesh.vertices.Count);
this.regions = new Dictionary<int, VoronoiRegion>(mesh.vertices.Count);
rayPoints = new Dictionary<int, Point>();
rayIndex = 0;
@@ -87,12 +87,18 @@ namespace TriangleNet.Tools
// Compute triangles circumcenters and setup bounding box
ComputeCircumCenters();
// Add all Voronoi regions to the map.
foreach (var vertex in mesh.vertices.Values)
{
regions.Add(vertex.id, new VoronoiRegion(vertex));
}
// Loop over the mesh vertices (Voronoi generators).
foreach (var item in mesh.vertices.Values)
foreach (var region in regions.Values)
{
//if (item.Boundary == 0)
{
ConstructVoronoiRegion(item);
ConstructVoronoiRegion(region);
}
}
}
@@ -113,11 +119,11 @@ namespace TriangleNet.Tools
points[item.id] = pt;
bounds.Update(pt.x, pt.y);
bounds.Expand(pt.x, pt.y);
}
double ds = Math.Max(bounds.Width, bounds.Height);
bounds.Scale(ds, ds);
bounds.Resize(ds, ds);
}
/// <summary>
@@ -125,12 +131,11 @@ namespace TriangleNet.Tools
/// </summary>
/// <param name="vertex"></param>
/// <returns>The circumcenter indices which make up the cell.</returns>
private void ConstructVoronoiRegion(Vertex vertex)
private void ConstructVoronoiRegion(VoronoiRegion region)
{
VoronoiRegion region = new VoronoiRegion(vertex);
regions.Add(region);
var vertex = region.Generator as Vertex;
List<Point> vpoints = new List<Point>();
var vpoints = new List<Point>();
Otri f = default(Otri);
Otri f_init = default(Otri);
@@ -165,6 +170,8 @@ namespace TriangleNet.Tools
// Add circumcenter of current triangle
vpoints.Add(points[f.triangle.id]);
region.AddNeighbor(f.triangle.id, regions[f.Apex().id]);
if (f_next.Equal(f_init))
{
// Voronoi cell is complete (bounded case).
@@ -179,23 +186,21 @@ namespace TriangleNet.Tools
// Voronoi cell is unbounded
region.Bounded = false;
Vertex torg, tdest, tapex, intersection;
Vertex torg, tdest, tapex;
Point intersection;
int sid, n = mesh.triangles.Count;
// Find the boundary segment id.
// Find the boundary segment id (we use this id to number the endpoints of infinit rays).
f.Lprev(ref f_next);
f_next.SegPivot(ref sub);
sid = sub.seg.hash;
// Last valid f lies at the boundary. Add the circumcenter.
vpoints.Add(points[f.triangle.id]);
region.AddNeighbor(f.triangle.id, regions[f.Apex().id]);
// Check if the intersection with the bounding box has already been computed.
if (rayPoints.ContainsKey(sid))
{
vpoints.Add(rayPoints[sid]);
}
else
if (!rayPoints.TryGetValue(sid, out intersection))
{
torg = f.Org();
tapex = f.Apex();
@@ -205,13 +210,13 @@ namespace TriangleNet.Tools
intersection.id = n + rayIndex;
points[n + rayIndex] = intersection;
rayIndex++;
vpoints.Add(intersection);
rayPoints.Add(sid, intersection);
}
vpoints.Add(intersection);
// Now walk from f_init clockwise till we reach the boundary.
vpoints.Reverse();
@@ -221,6 +226,7 @@ namespace TriangleNet.Tools
while (f_prev.triangle != Mesh.dummytri)
{
vpoints.Add(points[f_prev.triangle.id]);
region.AddNeighbor(f_prev.triangle.id, regions[f_prev.Apex().id]);
f_prev.Copy(ref f);
f_prev.OprevSelf();
@@ -229,12 +235,8 @@ namespace TriangleNet.Tools
// Find the boundary segment id.
f.SegPivot(ref sub);
sid = sub.seg.hash;
if (rayPoints.ContainsKey(sid))
{
vpoints.Add(rayPoints[sid]);
}
else
if (!rayPoints.TryGetValue(sid, out intersection))
{
// Intersection has not been computed yet.
torg = f.Org();
@@ -245,20 +247,21 @@ namespace TriangleNet.Tools
// Set the correct id for the vertex
intersection.id = n + rayIndex;
points[n + rayIndex] = intersection;
rayIndex++;
vpoints.Add(intersection);
rayPoints.Add(sid, intersection);
points[n + rayIndex] = intersection;
rayIndex++;
}
vpoints.Add(intersection);
region.AddNeighbor(intersection.id, regions[f.Dest().id]);
// Add the new points to the region (in counter-clockwise order)
vpoints.Reverse();
region.Add(vpoints);
}
private bool BoxRayIntersection(Point pt, double dx, double dy, out Vertex intersect)
private bool BoxRayIntersection(Point pt, double dx, double dy, out Point intersect)
{
double x = pt.X;
double y = pt.Y;
@@ -266,10 +269,10 @@ namespace TriangleNet.Tools
double t1, x1, y1, t2, x2, y2;
// Bounding box
double minX = bounds.Xmin;
double maxX = bounds.Xmax;
double minY = bounds.Ymin;
double maxY = bounds.Ymax;
double minX = bounds.MinX;
double maxX = bounds.MaxX;
double minY = bounds.MinY;
double maxY = bounds.MaxY;
// Check if point is inside the bounds
if (x < minX || x > maxX || y < minY || y > maxY)
@@ -308,7 +311,7 @@ namespace TriangleNet.Tools
x2 = x + t2 * dx;
y2 = minY;
}
else if (dx > 0)
else if (dy > 0)
{
// Line going upwards: intersect with y = maxY
t2 = (maxY - y) / dy;
@@ -324,11 +327,11 @@ namespace TriangleNet.Tools
if (t1 < t2)
{
intersect = new Vertex(x1, y1, -1);
intersect = new Point(x1, y1);
}
else
{
intersect = new Vertex(x2, y2, -1);
intersect = new Point(x2, y2);
}
return true;
+33 -4
View File
@@ -1,6 +1,6 @@
// -----------------------------------------------------------------------
// <copyright file="VoronoiRegion.cs" company="">
// TODO: Update copyright text.
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
@@ -8,10 +8,8 @@ namespace TriangleNet.Tools
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
using TriangleNet.Data;
using TriangleNet.Geometry;
/// <summary>
/// Represents a region in the Voronoi diagram.
@@ -23,6 +21,9 @@ namespace TriangleNet.Tools
List<Point> vertices;
bool bounded;
// A map (vertex id) -> (neighbor across adjacent edge)
Dictionary<int, VoronoiRegion> neighbors;
/// <summary>
/// Gets the Voronoi region id (which is the same as the generators vertex id).
/// </summary>
@@ -62,6 +63,8 @@ namespace TriangleNet.Tools
this.generator = generator;
this.vertices = new List<Point>();
this.bounded = true;
this.neighbors = new Dictionary<int, VoronoiRegion>();
}
public void Add(Point point)
@@ -74,6 +77,32 @@ namespace TriangleNet.Tools
this.vertices.AddRange(points);
}
/// <summary>
/// Returns the neighbouring Voronoi region, that lies across the edge starting at
/// given vertex.
/// </summary>
/// <param name="p">Vertex defining an edge of the region.</param>
/// <returns>Neighbouring Voronoi region</returns>
/// <remarks>
/// The edge starting at p is well defined (vertices are ordered counterclockwise).
/// </remarks>
public VoronoiRegion GetNeighbor(Point p)
{
VoronoiRegion neighbor;
if (neighbors.TryGetValue(p.id, out neighbor))
{
return neighbor;
}
return null;
}
internal void AddNeighbor(int id, VoronoiRegion neighbor)
{
this.neighbors.Add(id, neighbor);
}
public override string ToString()
{
return String.Format("R-ID {0}", id);