Fix Bounded Voronoi exception;
More code reorganization; git-svn-id: https://triangle.svn.codeplex.com/svn@74907 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -1,421 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Carver.cs">
|
||||
// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet
|
||||
{
|
||||
using TriangleNet.Data;
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Carves holes into the triangulation.
|
||||
/// </summary>
|
||||
class Carver
|
||||
{
|
||||
Mesh mesh;
|
||||
List<Triangle> viri;
|
||||
|
||||
public Carver(Mesh mesh)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
this.viri = new List<Triangle>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virally infect all of the triangles of the convex hull that are not
|
||||
/// protected by subsegments. Where there are subsegments, set boundary
|
||||
/// markers as appropriate.
|
||||
/// </summary>
|
||||
private void InfectHull()
|
||||
{
|
||||
Otri hulltri = default(Otri);
|
||||
Otri nexttri = default(Otri);
|
||||
Otri starttri = default(Otri);
|
||||
Osub hullsubseg = default(Osub);
|
||||
Vertex horg, hdest;
|
||||
|
||||
// Find a triangle handle on the hull.
|
||||
hulltri.triangle = Mesh.dummytri;
|
||||
hulltri.orient = 0;
|
||||
hulltri.SymSelf();
|
||||
// Remember where we started so we know when to stop.
|
||||
hulltri.Copy(ref starttri);
|
||||
// Go once counterclockwise around the convex hull.
|
||||
do
|
||||
{
|
||||
// Ignore triangles that are already infected.
|
||||
if (!hulltri.IsInfected())
|
||||
{
|
||||
// Is the triangle protected by a subsegment?
|
||||
hulltri.SegPivot(ref hullsubseg);
|
||||
if (hullsubseg.seg == Mesh.dummysub)
|
||||
{
|
||||
// The triangle is not protected; infect it.
|
||||
if (!hulltri.IsInfected())
|
||||
{
|
||||
hulltri.Infect();
|
||||
viri.Add(hulltri.triangle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The triangle is protected; set boundary markers if appropriate.
|
||||
if (hullsubseg.seg.boundary == 0)
|
||||
{
|
||||
hullsubseg.seg.boundary = 1;
|
||||
horg = hulltri.Org();
|
||||
hdest = hulltri.Dest();
|
||||
if (horg.mark == 0)
|
||||
{
|
||||
horg.mark = 1;
|
||||
}
|
||||
if (hdest.mark == 0)
|
||||
{
|
||||
hdest.mark = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// To find the next hull edge, go clockwise around the next vertex.
|
||||
hulltri.LnextSelf();
|
||||
hulltri.Oprev(ref nexttri);
|
||||
while (nexttri.triangle != Mesh.dummytri)
|
||||
{
|
||||
nexttri.Copy(ref hulltri);
|
||||
hulltri.Oprev(ref nexttri);
|
||||
}
|
||||
|
||||
} while (!hulltri.Equal(starttri));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spread the virus from all infected triangles to any neighbors not
|
||||
/// protected by subsegments. Delete all infected triangles.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the procedure that actually creates holes and concavities.
|
||||
///
|
||||
/// This procedure operates in two phases. The first phase identifies all
|
||||
/// the triangles that will die, and marks them as infected. They are
|
||||
/// marked to ensure that each triangle is added to the virus pool only
|
||||
/// once, so the procedure will terminate.
|
||||
///
|
||||
/// The second phase actually eliminates the infected triangles. It also
|
||||
/// eliminates orphaned vertices.
|
||||
/// </remarks>
|
||||
void Plague()
|
||||
{
|
||||
Otri testtri = default(Otri);
|
||||
Otri neighbor = default(Otri);
|
||||
Osub neighborsubseg = default(Osub);
|
||||
Vertex testvertex;
|
||||
Vertex norg, ndest;
|
||||
|
||||
bool killorg;
|
||||
|
||||
// Loop through all the infected triangles, spreading the virus to
|
||||
// their neighbors, then to their neighbors' neighbors.
|
||||
for (int i = 0; i < viri.Count; i++)
|
||||
{
|
||||
// WARNING: Don't use foreach, mesh.viri list may get modified.
|
||||
|
||||
testtri.triangle = viri[i];
|
||||
// A triangle is marked as infected by messing with one of its pointers
|
||||
// to subsegments, setting it to an illegal value. Hence, we have to
|
||||
// temporarily uninfect this triangle so that we can examine its
|
||||
// adjacent subsegments.
|
||||
// TODO: Not true in the C# version (so we could skip this).
|
||||
testtri.Uninfect();
|
||||
|
||||
// Check each of the triangle's three neighbors.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
// Find the neighbor.
|
||||
testtri.Sym(ref neighbor);
|
||||
// Check for a subsegment between the triangle and its neighbor.
|
||||
testtri.SegPivot(ref neighborsubseg);
|
||||
// Check if the neighbor is nonexistent or already infected.
|
||||
if ((neighbor.triangle == Mesh.dummytri) || neighbor.IsInfected())
|
||||
{
|
||||
if (neighborsubseg.seg != Mesh.dummysub)
|
||||
{
|
||||
// There is a subsegment separating the triangle from its
|
||||
// neighbor, but both triangles are dying, so the subsegment
|
||||
// dies too.
|
||||
mesh.SubsegDealloc(neighborsubseg.seg);
|
||||
if (neighbor.triangle != Mesh.dummytri)
|
||||
{
|
||||
// Make sure the subsegment doesn't get deallocated again
|
||||
// later when the infected neighbor is visited.
|
||||
neighbor.Uninfect();
|
||||
neighbor.SegDissolve();
|
||||
neighbor.Infect();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // The neighbor exists and is not infected.
|
||||
if (neighborsubseg.seg == Mesh.dummysub)
|
||||
{
|
||||
// There is no subsegment protecting the neighbor, so
|
||||
// the neighbor becomes infected.
|
||||
neighbor.Infect();
|
||||
// Ensure that the neighbor's neighbors will be infected.
|
||||
viri.Add(neighbor.triangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The neighbor is protected by a subsegment.
|
||||
// Remove this triangle from the subsegment.
|
||||
neighborsubseg.TriDissolve();
|
||||
// The subsegment becomes a boundary. Set markers accordingly.
|
||||
if (neighborsubseg.seg.boundary == 0)
|
||||
{
|
||||
neighborsubseg.seg.boundary = 1;
|
||||
}
|
||||
norg = neighbor.Org();
|
||||
ndest = neighbor.Dest();
|
||||
if (norg.mark == 0)
|
||||
{
|
||||
norg.mark = 1;
|
||||
}
|
||||
if (ndest.mark == 0)
|
||||
{
|
||||
ndest.mark = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remark the triangle as infected, so it doesn't get added to the
|
||||
// virus pool again.
|
||||
testtri.Infect();
|
||||
}
|
||||
|
||||
foreach (var virus in viri)
|
||||
{
|
||||
testtri.triangle = virus;
|
||||
|
||||
// Check each of the three corners of the triangle for elimination.
|
||||
// This is done by walking around each vertex, checking if it is
|
||||
// still connected to at least one live triangle.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
testvertex = testtri.Org();
|
||||
// Check if the vertex has already been tested.
|
||||
if (testvertex != null)
|
||||
{
|
||||
killorg = true;
|
||||
// Mark the corner of the triangle as having been tested.
|
||||
testtri.SetOrg(null);
|
||||
// Walk counterclockwise about the vertex.
|
||||
testtri.Onext(ref neighbor);
|
||||
// Stop upon reaching a boundary or the starting triangle.
|
||||
while ((neighbor.triangle != Mesh.dummytri) &&
|
||||
(!neighbor.Equal(testtri)))
|
||||
{
|
||||
if (neighbor.IsInfected())
|
||||
{
|
||||
// Mark the corner of this triangle as having been tested.
|
||||
neighbor.SetOrg(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A live triangle. The vertex survives.
|
||||
killorg = false;
|
||||
}
|
||||
// Walk counterclockwise about the vertex.
|
||||
neighbor.OnextSelf();
|
||||
}
|
||||
// If we reached a boundary, we must walk clockwise as well.
|
||||
if (neighbor.triangle == Mesh.dummytri)
|
||||
{
|
||||
// Walk clockwise about the vertex.
|
||||
testtri.Oprev(ref neighbor);
|
||||
// Stop upon reaching a boundary.
|
||||
while (neighbor.triangle != Mesh.dummytri)
|
||||
{
|
||||
if (neighbor.IsInfected())
|
||||
{
|
||||
// Mark the corner of this triangle as having been tested.
|
||||
neighbor.SetOrg(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A live triangle. The vertex survives.
|
||||
killorg = false;
|
||||
}
|
||||
// Walk clockwise about the vertex.
|
||||
neighbor.OprevSelf();
|
||||
}
|
||||
}
|
||||
if (killorg)
|
||||
{
|
||||
// Deleting vertex
|
||||
testvertex.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record changes in the number of boundary edges, and disconnect
|
||||
// dead triangles from their neighbors.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
testtri.Sym(ref neighbor);
|
||||
if (neighbor.triangle == Mesh.dummytri)
|
||||
{
|
||||
// There is no neighboring triangle on this edge, so this edge
|
||||
// is a boundary edge. This triangle is being deleted, so this
|
||||
// boundary edge is deleted.
|
||||
mesh.hullsize--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disconnect the triangle from its neighbor.
|
||||
neighbor.Dissolve();
|
||||
// There is a neighboring triangle on this edge, so this edge
|
||||
// becomes a boundary edge when this triangle is deleted.
|
||||
mesh.hullsize++;
|
||||
}
|
||||
}
|
||||
// Return the dead triangle to the pool of triangles.
|
||||
mesh.TriangleDealloc(testtri.triangle);
|
||||
}
|
||||
|
||||
// Empty the virus pool.
|
||||
viri.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the holes and infect them. Find the area constraints and infect
|
||||
/// them. Infect the convex hull. Spread the infection and kill triangles.
|
||||
/// Spread the area constraints.
|
||||
/// </summary>
|
||||
public void CarveHoles()
|
||||
{
|
||||
Otri searchtri = default(Otri);
|
||||
Vertex searchorg, searchdest;
|
||||
LocateResult intersect;
|
||||
|
||||
Triangle[] regionTris = null;
|
||||
|
||||
if (!mesh.behavior.Convex)
|
||||
{
|
||||
// Mark as infected any unprotected triangles on the boundary.
|
||||
// This is one way by which concavities are created.
|
||||
InfectHull();
|
||||
}
|
||||
|
||||
if (!mesh.behavior.NoHoles)
|
||||
{
|
||||
// Infect each triangle in which a hole lies.
|
||||
foreach (var hole in mesh.holes)
|
||||
{
|
||||
// Ignore holes that aren't within the bounds of the mesh.
|
||||
if (mesh.bounds.Contains(hole))
|
||||
{
|
||||
// Start searching from some triangle on the outer boundary.
|
||||
searchtri.triangle = Mesh.dummytri;
|
||||
searchtri.orient = 0;
|
||||
searchtri.SymSelf();
|
||||
// Ensure that the hole is to the left of this boundary edge;
|
||||
// otherwise, locate() will falsely report that the hole
|
||||
// falls within the starting triangle.
|
||||
searchorg = searchtri.Org();
|
||||
searchdest = searchtri.Dest();
|
||||
if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0)
|
||||
{
|
||||
// Find a triangle that contains the hole.
|
||||
intersect = mesh.locator.Locate(hole, ref searchtri);
|
||||
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
|
||||
{
|
||||
// Infect the triangle. This is done by marking the triangle
|
||||
// as infected and including the triangle in the virus pool.
|
||||
searchtri.Infect();
|
||||
viri.Add(searchtri.triangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, we have to find all the regions BEFORE we carve the holes, because locate() won't
|
||||
// work when the triangulation is no longer convex. (Incidentally, this is the reason why
|
||||
// regional attributes and area constraints can't be used when refining a preexisting mesh,
|
||||
// which might not be convex; they can only be used with a freshly triangulated PSLG.)
|
||||
if (mesh.regions.Count > 0)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
regionTris = new Triangle[mesh.regions.Count];
|
||||
|
||||
// Find the starting triangle for each region.
|
||||
foreach (var region in mesh.regions)
|
||||
{
|
||||
regionTris[i] = Mesh.dummytri;
|
||||
// Ignore region points that aren't within the bounds of the mesh.
|
||||
if (mesh.bounds.Contains(region.point))
|
||||
{
|
||||
// Start searching from some triangle on the outer boundary.
|
||||
searchtri.triangle = Mesh.dummytri;
|
||||
searchtri.orient = 0;
|
||||
searchtri.SymSelf();
|
||||
// Ensure that the region point is to the left of this boundary
|
||||
// edge; otherwise, locate() will falsely report that the
|
||||
// region point falls within the starting triangle.
|
||||
searchorg = searchtri.Org();
|
||||
searchdest = searchtri.Dest();
|
||||
if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0)
|
||||
{
|
||||
// Find a triangle that contains the region point.
|
||||
intersect = mesh.locator.Locate(region.point, ref searchtri);
|
||||
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
|
||||
{
|
||||
// Record the triangle for processing after the
|
||||
// holes have been carved.
|
||||
regionTris[i] = searchtri.triangle;
|
||||
regionTris[i].region = region.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (viri.Count > 0)
|
||||
{
|
||||
// Carve the holes and concavities.
|
||||
Plague();
|
||||
}
|
||||
|
||||
if (regionTris != null)
|
||||
{
|
||||
var iterator = new RegionIterator(mesh);
|
||||
|
||||
for (int i = 0; i < regionTris.Length; i++)
|
||||
{
|
||||
if (regionTris[i] != Mesh.dummytri)
|
||||
{
|
||||
// Make sure the triangle under consideration still exists.
|
||||
// It may have been eaten by the virus.
|
||||
if (!Otri.IsDead(regionTris[i]))
|
||||
{
|
||||
// Apply one region's attribute and/or area constraint.
|
||||
iterator.Process(regionTris[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free up memory (virus pool should be empty anyway).
|
||||
viri.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,11 @@
|
||||
namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Log;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
internal class ConstraintMesher
|
||||
{
|
||||
@@ -18,6 +20,8 @@ namespace TriangleNet
|
||||
Behavior behavior;
|
||||
TriangleLocator locator;
|
||||
|
||||
List<Triangle> viri;
|
||||
|
||||
ILog<SimpleLogItem> logger;
|
||||
|
||||
public ConstraintMesher(Mesh mesh)
|
||||
@@ -26,16 +30,141 @@ namespace TriangleNet
|
||||
this.behavior = mesh.behavior;
|
||||
this.locator = mesh.locator;
|
||||
|
||||
this.viri = new List<Triangle>();
|
||||
|
||||
logger = SimpleLog.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the holes and infect them. Find the area constraints and infect
|
||||
/// them. Infect the convex hull. Spread the infection and kill triangles.
|
||||
/// Spread the area constraints.
|
||||
/// </summary>
|
||||
public void CarveHoles()
|
||||
{
|
||||
Otri searchtri = default(Otri);
|
||||
Vertex searchorg, searchdest;
|
||||
LocateResult intersect;
|
||||
|
||||
Triangle[] regionTris = null;
|
||||
|
||||
if (!mesh.behavior.Convex)
|
||||
{
|
||||
// Mark as infected any unprotected triangles on the boundary.
|
||||
// This is one way by which concavities are created.
|
||||
InfectHull();
|
||||
}
|
||||
|
||||
if (!mesh.behavior.NoHoles)
|
||||
{
|
||||
// Infect each triangle in which a hole lies.
|
||||
foreach (var hole in mesh.holes)
|
||||
{
|
||||
// Ignore holes that aren't within the bounds of the mesh.
|
||||
if (mesh.bounds.Contains(hole))
|
||||
{
|
||||
// Start searching from some triangle on the outer boundary.
|
||||
searchtri.triangle = Mesh.dummytri;
|
||||
searchtri.orient = 0;
|
||||
searchtri.SymSelf();
|
||||
// Ensure that the hole is to the left of this boundary edge;
|
||||
// otherwise, locate() will falsely report that the hole
|
||||
// falls within the starting triangle.
|
||||
searchorg = searchtri.Org();
|
||||
searchdest = searchtri.Dest();
|
||||
if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0)
|
||||
{
|
||||
// Find a triangle that contains the hole.
|
||||
intersect = mesh.locator.Locate(hole, ref searchtri);
|
||||
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
|
||||
{
|
||||
// Infect the triangle. This is done by marking the triangle
|
||||
// as infected and including the triangle in the virus pool.
|
||||
searchtri.Infect();
|
||||
viri.Add(searchtri.triangle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, we have to find all the regions BEFORE we carve the holes, because locate() won't
|
||||
// work when the triangulation is no longer convex. (Incidentally, this is the reason why
|
||||
// regional attributes and area constraints can't be used when refining a preexisting mesh,
|
||||
// which might not be convex; they can only be used with a freshly triangulated PSLG.)
|
||||
if (mesh.regions.Count > 0)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
regionTris = new Triangle[mesh.regions.Count];
|
||||
|
||||
// Find the starting triangle for each region.
|
||||
foreach (var region in mesh.regions)
|
||||
{
|
||||
regionTris[i] = Mesh.dummytri;
|
||||
// Ignore region points that aren't within the bounds of the mesh.
|
||||
if (mesh.bounds.Contains(region.point))
|
||||
{
|
||||
// Start searching from some triangle on the outer boundary.
|
||||
searchtri.triangle = Mesh.dummytri;
|
||||
searchtri.orient = 0;
|
||||
searchtri.SymSelf();
|
||||
// Ensure that the region point is to the left of this boundary
|
||||
// edge; otherwise, locate() will falsely report that the
|
||||
// region point falls within the starting triangle.
|
||||
searchorg = searchtri.Org();
|
||||
searchdest = searchtri.Dest();
|
||||
if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0)
|
||||
{
|
||||
// Find a triangle that contains the region point.
|
||||
intersect = mesh.locator.Locate(region.point, ref searchtri);
|
||||
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
|
||||
{
|
||||
// Record the triangle for processing after the
|
||||
// holes have been carved.
|
||||
regionTris[i] = searchtri.triangle;
|
||||
regionTris[i].region = region.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (viri.Count > 0)
|
||||
{
|
||||
// Carve the holes and concavities.
|
||||
Plague();
|
||||
}
|
||||
|
||||
if (regionTris != null)
|
||||
{
|
||||
var iterator = new RegionIterator(mesh);
|
||||
|
||||
for (int i = 0; i < regionTris.Length; i++)
|
||||
{
|
||||
if (regionTris[i] != Mesh.dummytri)
|
||||
{
|
||||
// Make sure the triangle under consideration still exists.
|
||||
// It may have been eaten by the virus.
|
||||
if (!Otri.IsDead(regionTris[i]))
|
||||
{
|
||||
// Apply one region's attribute and/or area constraint.
|
||||
iterator.Process(regionTris[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Free up memory (virus pool should be empty anyway).
|
||||
viri.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the segments of a triangulation, including PSLG segments and edges
|
||||
/// on the convex hull.
|
||||
/// </summary>
|
||||
/// <param name="segmentlist"></param>
|
||||
/// <param name="segmentmarkerlist"></param>
|
||||
/// <param name="numberofsegments"></param>
|
||||
public void FormSkeleton(InputGeometry input)
|
||||
{
|
||||
Vertex endpoint1, endpoint2;
|
||||
@@ -116,6 +245,275 @@ namespace TriangleNet
|
||||
}
|
||||
}
|
||||
|
||||
#region Carving holes
|
||||
|
||||
/// <summary>
|
||||
/// Virally infect all of the triangles of the convex hull that are not
|
||||
/// protected by subsegments. Where there are subsegments, set boundary
|
||||
/// markers as appropriate.
|
||||
/// </summary>
|
||||
private void InfectHull()
|
||||
{
|
||||
Otri hulltri = default(Otri);
|
||||
Otri nexttri = default(Otri);
|
||||
Otri starttri = default(Otri);
|
||||
Osub hullsubseg = default(Osub);
|
||||
Vertex horg, hdest;
|
||||
|
||||
// Find a triangle handle on the hull.
|
||||
hulltri.triangle = Mesh.dummytri;
|
||||
hulltri.orient = 0;
|
||||
hulltri.SymSelf();
|
||||
// Remember where we started so we know when to stop.
|
||||
hulltri.Copy(ref starttri);
|
||||
// Go once counterclockwise around the convex hull.
|
||||
do
|
||||
{
|
||||
// Ignore triangles that are already infected.
|
||||
if (!hulltri.IsInfected())
|
||||
{
|
||||
// Is the triangle protected by a subsegment?
|
||||
hulltri.SegPivot(ref hullsubseg);
|
||||
if (hullsubseg.seg == Mesh.dummysub)
|
||||
{
|
||||
// The triangle is not protected; infect it.
|
||||
if (!hulltri.IsInfected())
|
||||
{
|
||||
hulltri.Infect();
|
||||
viri.Add(hulltri.triangle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The triangle is protected; set boundary markers if appropriate.
|
||||
if (hullsubseg.seg.boundary == 0)
|
||||
{
|
||||
hullsubseg.seg.boundary = 1;
|
||||
horg = hulltri.Org();
|
||||
hdest = hulltri.Dest();
|
||||
if (horg.mark == 0)
|
||||
{
|
||||
horg.mark = 1;
|
||||
}
|
||||
if (hdest.mark == 0)
|
||||
{
|
||||
hdest.mark = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// To find the next hull edge, go clockwise around the next vertex.
|
||||
hulltri.LnextSelf();
|
||||
hulltri.Oprev(ref nexttri);
|
||||
while (nexttri.triangle != Mesh.dummytri)
|
||||
{
|
||||
nexttri.Copy(ref hulltri);
|
||||
hulltri.Oprev(ref nexttri);
|
||||
}
|
||||
|
||||
} while (!hulltri.Equal(starttri));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spread the virus from all infected triangles to any neighbors not
|
||||
/// protected by subsegments. Delete all infected triangles.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the procedure that actually creates holes and concavities.
|
||||
///
|
||||
/// This procedure operates in two phases. The first phase identifies all
|
||||
/// the triangles that will die, and marks them as infected. They are
|
||||
/// marked to ensure that each triangle is added to the virus pool only
|
||||
/// once, so the procedure will terminate.
|
||||
///
|
||||
/// The second phase actually eliminates the infected triangles. It also
|
||||
/// eliminates orphaned vertices.
|
||||
/// </remarks>
|
||||
void Plague()
|
||||
{
|
||||
Otri testtri = default(Otri);
|
||||
Otri neighbor = default(Otri);
|
||||
Osub neighborsubseg = default(Osub);
|
||||
Vertex testvertex;
|
||||
Vertex norg, ndest;
|
||||
|
||||
bool killorg;
|
||||
|
||||
// Loop through all the infected triangles, spreading the virus to
|
||||
// their neighbors, then to their neighbors' neighbors.
|
||||
for (int i = 0; i < viri.Count; i++)
|
||||
{
|
||||
// WARNING: Don't use foreach, mesh.viri list may get modified.
|
||||
|
||||
testtri.triangle = viri[i];
|
||||
// A triangle is marked as infected by messing with one of its pointers
|
||||
// to subsegments, setting it to an illegal value. Hence, we have to
|
||||
// temporarily uninfect this triangle so that we can examine its
|
||||
// adjacent subsegments.
|
||||
// TODO: Not true in the C# version (so we could skip this).
|
||||
testtri.Uninfect();
|
||||
|
||||
// Check each of the triangle's three neighbors.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
// Find the neighbor.
|
||||
testtri.Sym(ref neighbor);
|
||||
// Check for a subsegment between the triangle and its neighbor.
|
||||
testtri.SegPivot(ref neighborsubseg);
|
||||
// Check if the neighbor is nonexistent or already infected.
|
||||
if ((neighbor.triangle == Mesh.dummytri) || neighbor.IsInfected())
|
||||
{
|
||||
if (neighborsubseg.seg != Mesh.dummysub)
|
||||
{
|
||||
// There is a subsegment separating the triangle from its
|
||||
// neighbor, but both triangles are dying, so the subsegment
|
||||
// dies too.
|
||||
mesh.SubsegDealloc(neighborsubseg.seg);
|
||||
if (neighbor.triangle != Mesh.dummytri)
|
||||
{
|
||||
// Make sure the subsegment doesn't get deallocated again
|
||||
// later when the infected neighbor is visited.
|
||||
neighbor.Uninfect();
|
||||
neighbor.SegDissolve();
|
||||
neighbor.Infect();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // The neighbor exists and is not infected.
|
||||
if (neighborsubseg.seg == Mesh.dummysub)
|
||||
{
|
||||
// There is no subsegment protecting the neighbor, so
|
||||
// the neighbor becomes infected.
|
||||
neighbor.Infect();
|
||||
// Ensure that the neighbor's neighbors will be infected.
|
||||
viri.Add(neighbor.triangle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The neighbor is protected by a subsegment.
|
||||
// Remove this triangle from the subsegment.
|
||||
neighborsubseg.TriDissolve();
|
||||
// The subsegment becomes a boundary. Set markers accordingly.
|
||||
if (neighborsubseg.seg.boundary == 0)
|
||||
{
|
||||
neighborsubseg.seg.boundary = 1;
|
||||
}
|
||||
norg = neighbor.Org();
|
||||
ndest = neighbor.Dest();
|
||||
if (norg.mark == 0)
|
||||
{
|
||||
norg.mark = 1;
|
||||
}
|
||||
if (ndest.mark == 0)
|
||||
{
|
||||
ndest.mark = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remark the triangle as infected, so it doesn't get added to the
|
||||
// virus pool again.
|
||||
testtri.Infect();
|
||||
}
|
||||
|
||||
foreach (var virus in viri)
|
||||
{
|
||||
testtri.triangle = virus;
|
||||
|
||||
// Check each of the three corners of the triangle for elimination.
|
||||
// This is done by walking around each vertex, checking if it is
|
||||
// still connected to at least one live triangle.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
testvertex = testtri.Org();
|
||||
// Check if the vertex has already been tested.
|
||||
if (testvertex != null)
|
||||
{
|
||||
killorg = true;
|
||||
// Mark the corner of the triangle as having been tested.
|
||||
testtri.SetOrg(null);
|
||||
// Walk counterclockwise about the vertex.
|
||||
testtri.Onext(ref neighbor);
|
||||
// Stop upon reaching a boundary or the starting triangle.
|
||||
while ((neighbor.triangle != Mesh.dummytri) &&
|
||||
(!neighbor.Equal(testtri)))
|
||||
{
|
||||
if (neighbor.IsInfected())
|
||||
{
|
||||
// Mark the corner of this triangle as having been tested.
|
||||
neighbor.SetOrg(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A live triangle. The vertex survives.
|
||||
killorg = false;
|
||||
}
|
||||
// Walk counterclockwise about the vertex.
|
||||
neighbor.OnextSelf();
|
||||
}
|
||||
// If we reached a boundary, we must walk clockwise as well.
|
||||
if (neighbor.triangle == Mesh.dummytri)
|
||||
{
|
||||
// Walk clockwise about the vertex.
|
||||
testtri.Oprev(ref neighbor);
|
||||
// Stop upon reaching a boundary.
|
||||
while (neighbor.triangle != Mesh.dummytri)
|
||||
{
|
||||
if (neighbor.IsInfected())
|
||||
{
|
||||
// Mark the corner of this triangle as having been tested.
|
||||
neighbor.SetOrg(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// A live triangle. The vertex survives.
|
||||
killorg = false;
|
||||
}
|
||||
// Walk clockwise about the vertex.
|
||||
neighbor.OprevSelf();
|
||||
}
|
||||
}
|
||||
if (killorg)
|
||||
{
|
||||
// Deleting vertex
|
||||
testvertex.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Record changes in the number of boundary edges, and disconnect
|
||||
// dead triangles from their neighbors.
|
||||
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
|
||||
{
|
||||
testtri.Sym(ref neighbor);
|
||||
if (neighbor.triangle == Mesh.dummytri)
|
||||
{
|
||||
// There is no neighboring triangle on this edge, so this edge
|
||||
// is a boundary edge. This triangle is being deleted, so this
|
||||
// boundary edge is deleted.
|
||||
mesh.hullsize--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disconnect the triangle from its neighbor.
|
||||
neighbor.Dissolve();
|
||||
// There is a neighboring triangle on this edge, so this edge
|
||||
// becomes a boundary edge when this triangle is deleted.
|
||||
mesh.hullsize++;
|
||||
}
|
||||
}
|
||||
// Return the dead triangle to the pool of triangles.
|
||||
mesh.TriangleDealloc(testtri.triangle);
|
||||
}
|
||||
|
||||
// Empty the virus pool.
|
||||
viri.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Segment insertion
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -335,13 +335,14 @@ namespace TriangleNet
|
||||
infvertex2 = null;
|
||||
infvertex3 = null;
|
||||
|
||||
// Insert segments, carving holes.
|
||||
var mesher = new ConstraintMesher(this);
|
||||
|
||||
if (behavior.useSegments)
|
||||
{
|
||||
// Segments will be introduced next.
|
||||
checksegments = true;
|
||||
|
||||
var mesher = new ConstraintMesher(this);
|
||||
|
||||
// Insert PSLG segments and/or convex hull segments.
|
||||
mesher.FormSkeleton(input);
|
||||
}
|
||||
@@ -363,8 +364,7 @@ namespace TriangleNet
|
||||
//dummytri.neighbors[2].triangle = dummytri;
|
||||
|
||||
// Carve out holes and concavities.
|
||||
Carver c = new Carver(this);
|
||||
c.CarveHoles();
|
||||
mesher.CarveHoles();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -618,8 +618,8 @@ namespace TriangleNet
|
||||
|
||||
Statistic.InCircleCount = 0;
|
||||
Statistic.CounterClockwiseCount = 0;
|
||||
Statistic.InCircleCountDecimal = 0;
|
||||
Statistic.CounterClockwiseCountDecimal = 0;
|
||||
Statistic.InCircleAdaptCount = 0;
|
||||
Statistic.CounterClockwiseAdaptCount = 0;
|
||||
Statistic.Orient3dCount = 0;
|
||||
Statistic.HyperbolaCount = 0;
|
||||
Statistic.CircleTopCount = 0;
|
||||
|
||||
@@ -147,6 +147,7 @@ namespace TriangleNet
|
||||
return det;
|
||||
}
|
||||
|
||||
Statistic.CounterClockwiseAdaptCount++;
|
||||
return CounterClockwiseAdapt(pa, pb, pc, detsum);
|
||||
}
|
||||
|
||||
@@ -209,6 +210,7 @@ namespace TriangleNet
|
||||
return det;
|
||||
}
|
||||
|
||||
Statistic.InCircleAdaptCount++;
|
||||
return InCircleAdapt(pa, pb, pc, pd, permanent);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@ namespace TriangleNet.Tools
|
||||
Point[] points;
|
||||
List<VoronoiRegion> regions;
|
||||
|
||||
// Used for new points on segments.
|
||||
List<Point> segPoints;
|
||||
int segIndex;
|
||||
|
||||
Dictionary<int, Segment> subsegMap;
|
||||
@@ -79,9 +81,11 @@ namespace TriangleNet.Tools
|
||||
mesh.MakeVertexMap();
|
||||
|
||||
// Allocate space for voronoi diagram
|
||||
this.points = new Point[mesh.triangles.Count + mesh.subsegs.Count * 5]; // This is an upper bound.
|
||||
this.regions = new List<VoronoiRegion>(mesh.vertices.Count);
|
||||
|
||||
this.points = new Point[mesh.triangles.Count];
|
||||
this.segPoints = new List<Point>(mesh.subsegs.Count * 4);
|
||||
|
||||
ComputeCircumCenters();
|
||||
|
||||
TagBlindTriangles();
|
||||
@@ -98,6 +102,19 @@ namespace TriangleNet.Tools
|
||||
ConstructBoundaryBvdCell(v);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new points on segments to the point array.
|
||||
int length = points.Length;
|
||||
|
||||
Array.Resize<Point>(ref points, length + segPoints.Count);
|
||||
|
||||
for (int i = 0; i < segPoints.Count; i++)
|
||||
{
|
||||
points[length + i] = segPoints[i];
|
||||
}
|
||||
|
||||
this.segPoints.Clear();
|
||||
this.segPoints = null;
|
||||
}
|
||||
|
||||
private void ComputeCircumCenters()
|
||||
@@ -297,10 +314,8 @@ namespace TriangleNet.Tools
|
||||
// Insert point Lf,f_next /\ Sf_next into P
|
||||
if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
@@ -316,10 +331,8 @@ namespace TriangleNet.Tools
|
||||
// Insert point Lf,f_next /\ Sf into P
|
||||
if (SegmentsIntersect(sf.SegOrg(), sf.SegDest(), cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
@@ -334,19 +347,15 @@ namespace TriangleNet.Tools
|
||||
// Insert Lf,fnext /\ Sf and Lf,fnext /\ Sfnext into P
|
||||
if (SegmentsIntersect(sf.SegOrg(), sf.SegDest(), cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
|
||||
if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
@@ -418,10 +427,9 @@ namespace TriangleNet.Tools
|
||||
// For vertices on the domain boundaray, add the vertex. For
|
||||
// internal boundaries don't add it.
|
||||
p = new Point(vertex.x, vertex.y);
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
|
||||
@@ -429,10 +437,9 @@ namespace TriangleNet.Tools
|
||||
torg = f.Org();
|
||||
tdest = f.Dest();
|
||||
p = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2);
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
|
||||
// repeat ... until f = f_init
|
||||
@@ -454,10 +461,9 @@ namespace TriangleNet.Tools
|
||||
torg = f.Org();
|
||||
tapex = f.Apex();
|
||||
p = new Point((torg.X + tapex.X) / 2, (torg.Y + tapex.Y) / 2);
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
|
||||
break;
|
||||
@@ -479,10 +485,8 @@ namespace TriangleNet.Tools
|
||||
// Insert point Lf,f_next /\ Sf_next into P
|
||||
if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
@@ -510,20 +514,16 @@ namespace TriangleNet.Tools
|
||||
// Find intersection of seg with line through f's bisector and circumcenter
|
||||
if (SegmentsIntersect(sorg, sdest, bisec, cc_f, out p, false))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
|
||||
// Insert point Lf,f_next /\ Sf into P
|
||||
if (SegmentsIntersect(sorg, sdest, cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
@@ -538,19 +538,15 @@ namespace TriangleNet.Tools
|
||||
// Insert Lf,fnext /\ Sf and Lf,fnext /\ Sfnext into P
|
||||
if (SegmentsIntersect(sorg, sdest, cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
|
||||
if (SegmentsIntersect(sfn.SegOrg(), sfn.SegDest(), cc_f, cc_f_next, out p, true))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
@@ -565,10 +561,8 @@ namespace TriangleNet.Tools
|
||||
// Find intersection of seg with line through f_next's bisector and circumcenter
|
||||
if (SegmentsIntersect(sorg, sdest, bisec, cc_f_next, out p, false))
|
||||
{
|
||||
p.id = n + segIndex;
|
||||
points[n + segIndex] = p;
|
||||
segIndex++;
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
vpoints.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,13 @@ namespace TriangleNet.Tools
|
||||
/// Number of incircle tests performed.
|
||||
/// </summary>
|
||||
public static long InCircleCount = 0;
|
||||
public static long InCircleCountDecimal = 0;
|
||||
public static long InCircleAdaptCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of counterclockwise tests performed.
|
||||
/// </summary>
|
||||
public static long CounterClockwiseCount = 0;
|
||||
public static long CounterClockwiseCountDecimal = 0;
|
||||
public static long CounterClockwiseAdaptCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of 3D orientation tests performed.
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
<Compile Include="Algorithm\ITriangulator.cs" />
|
||||
<Compile Include="BadTriQueue.cs" />
|
||||
<Compile Include="Behavior.cs" />
|
||||
<Compile Include="Carver.cs" />
|
||||
<Compile Include="ConstraintMesher.cs" />
|
||||
<Compile Include="Data\BadSubseg.cs" />
|
||||
<Compile Include="Data\BadTriangle.cs" />
|
||||
|
||||
Reference in New Issue
Block a user