Make fixed vertex ids work (changed IPolygon interface)

git-svn-id: https://triangle.svn.codeplex.com/svn@77167 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2015-08-26 11:13:09 +00:00
parent 2f388438cc
commit da90ca5d0e
29 changed files with 618 additions and 375 deletions
+10 -4
View File
@@ -7,6 +7,7 @@
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using TriangleNet.Geometry;
/// <summary>
@@ -54,15 +55,19 @@ namespace MeshExplorer.Generators
double ro, r = 10;
double step = 2 * Math.PI / m;
var inner = new List<Vertex>(m);
// Inner ring
for (int i = 0; i < m; i++)
{
input.Add(new Vertex(r * Math.Cos(i * step), r * Math.Sin(i * step)));
input.Add(new Edge(i, (i + 1) % m, 1));
inner.Add(new Vertex(r * Math.Cos(i * step), r * Math.Sin(i * step)));
}
input.AddContour(inner, 1);
r = 1.5 * r;
var outer = new List<Vertex>(n);
step = 2 * Math.PI / n;
double offset = step / 2;
@@ -77,10 +82,11 @@ namespace MeshExplorer.Generators
ro = r + r * Util.Random.NextDouble() * (param1 / 100);
}
input.Add(new Vertex(ro * Math.Cos(i * step + offset), ro * Math.Sin(i * step + offset)));
input.Add(new Edge(m + i, m + ((i + 1) % n), 2));
outer.Add(new Vertex(ro * Math.Cos(i * step + offset), ro * Math.Sin(i * step + offset)));
}
input.AddContour(outer, 2);
input.Holes.Add(new Point(0, 0));
return input;
+14 -14
View File
@@ -29,9 +29,9 @@ namespace MeshExplorer.Generators
{
int numRays = GetParamValueInt(0, param0);
var input = new Polygon(numRays + 4);
var g = new Polygon(numRays + 4);
input.Add(new Vertex(0, 0)); // Center
g.Add(new Vertex(0, 0)); // Center
double x, y, r, e, step = 2 * Math.PI / numRays;
@@ -42,22 +42,22 @@ namespace MeshExplorer.Generators
x = r * Math.Cos(i * step + e);
y = r * Math.Sin(i * step + e);
input.Add(new Vertex(x, y, 2));
input.Add(new Edge(0, i + 1, 2));
g.Add(new Vertex(x, y, 2));
g.Add(new Segment(g.Points[0], g.Points[i + 1], 2));
}
input.Add(new Vertex(-1, -1, 1)); // Box
input.Add(new Vertex(1, -1, 1));
input.Add(new Vertex(1, 1, 1));
input.Add(new Vertex(-1, 1, 1));
g.Add(new Vertex(-1, -1, 1)); // Box
g.Add(new Vertex(1, -1, 1));
g.Add(new Vertex(1, 1, 1));
g.Add(new Vertex(-1, 1, 1));
numRays = input.Count;
input.Add(new Edge(numRays - 1, numRays - 2, 1));
input.Add(new Edge(numRays - 2, numRays - 3, 1));
input.Add(new Edge(numRays - 3, numRays - 4, 1));
input.Add(new Edge(numRays - 4, numRays - 1, 1));
numRays = g.Count;
g.Add(new Segment(g.Points[numRays - 1], g.Points[numRays - 2], 1));
g.Add(new Segment(g.Points[numRays - 2], g.Points[numRays - 3], 1));
g.Add(new Segment(g.Points[numRays - 3], g.Points[numRays - 4], 1));
g.Add(new Segment(g.Points[numRays - 4], g.Points[numRays - 1], 1));
return input;
return g;
}
}
}
+7 -4
View File
@@ -154,7 +154,7 @@ namespace MeshExplorer.IO.Formats
}
}
public void Write(IMesh mesh, StreamWriter stream)
public void Write(IMesh mesh, Stream stream)
{
throw new NotImplementedException();
}
@@ -226,7 +226,7 @@ namespace MeshExplorer.IO.Formats
throw new NotImplementedException();
}
public void Write(IPolygon polygon, StreamWriter stream)
public void Write(IPolygon polygon, Stream stream)
{
throw new NotImplementedException();
}
@@ -315,6 +315,9 @@ namespace MeshExplorer.IO.Formats
int p0, p1;
throw new NotImplementedException();
// TODO: Fix JSON format
for (int i = 0; i < n; i += 2)
{
mark = 0;
@@ -332,7 +335,7 @@ namespace MeshExplorer.IO.Formats
throw new Exception("JSON format error (segment index).");
}
geometry.Add(new Edge(p0, p1, mark));
//geometry.Add(new Edge(p0, p1, mark));
}
}
}
@@ -497,7 +500,7 @@ namespace MeshExplorer.IO.Formats
writer.Write("]");
}
private void WriteSegments(IEnumerable<Segment> data, StreamWriter writer, int ns)
private void WriteSegments(IEnumerable<SubSegment> data, StreamWriter writer, int ns)
{
int i = 0;
@@ -57,7 +57,7 @@ namespace MeshExplorer.IO.Formats
format.Write(polygon, filename);
}
public void Write(IPolygon polygon, StreamWriter stream)
public void Write(IPolygon polygon, Stream stream)
{
format.Write(polygon, stream);
}
@@ -75,7 +75,7 @@ namespace MeshExplorer.IO.Formats
}
}
public void Write(IMesh mesh, StreamWriter stream)
public void Write(IMesh mesh, Stream stream)
{
format.Write(mesh, stream);
}
@@ -145,7 +145,7 @@ namespace TriangleNet.Rendering
}
}
internal void Dispose(Dictionary<int, Brush> brushes)
internal void Dispose(Dictionary<int, SolidBrush> brushes)
{
foreach (var brush in brushes.Values)
{
@@ -153,9 +153,9 @@ namespace TriangleNet.Rendering
}
}
internal Dictionary<int, Brush> GetBrushDictionary()
internal Dictionary<int, SolidBrush> GetBrushDictionary()
{
var brushes = new Dictionary<int, Brush>();
var brushes = new Dictionary<int, SolidBrush>();
foreach (var item in ColorDictionary)
{
@@ -115,7 +115,12 @@ namespace TriangleNet.Rendering.GDI
if (filled)
{
g.FillPolygon(brushes[partition[i]], tri);
var b = brushes[partition[i]];
if (b.Color.A > 0)
{
g.FillPolygon(b, tri);
}
}
else
{
@@ -80,6 +80,14 @@ namespace TriangleNet.Rendering
// Always clear voronoi layer.
RenderLayers[4].Reset(true);
int i = 0;
// Ensure linear numbering of polygon vertices.
foreach (var p in data.Points)
{
p.ID = i++;
}
this.bounds = RenderLayers[2].SetPoints(data);
this.zoom.Initialize(bounds);
+166
View File
@@ -0,0 +1,166 @@
// -----------------------------------------------------------------------
// <copyright file="Contour.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Geometry
{
using System;
using System.Collections.Generic;
public class Contour
{
int marker;
public List<Vertex> Points { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Contour" /> class.
/// </summary>
public Contour(IEnumerable<Vertex> points, int marker)
{
this.Points = new List<Vertex>(points);
int count = Points.Count;
// Check if first vertex equals last vertex.
if (Points[0] == Points[count - 1])
{
count--;
Points.RemoveAt(count);
}
this.marker = marker;
}
public Point FindInteriorPoint(bool convex)
{
if (convex)
{
int count = this.Points.Count;
var centroid = new Point(0.0, 0.0);
for (int i = 0; i < count; i++)
{
centroid.x += this.Points[i].x;
centroid.y += this.Points[i].y;
}
// If the hole is convex, use its centroid.
centroid.x /= count;
centroid.y /= count;
return centroid;
}
return FindPointInPolygon(this.Points);
}
public List<ISegment> GetSegments()
{
var segments = new List<ISegment>();
var p = this.Points;
int count = p.Count - 1;
for (int i = 0; i < count; i++)
{
// Add segments to polygon.
segments.Add(new Segment(p[i], p[i + 1], marker));
}
// Close the contour.
segments.Add(new Segment(p[count], p[0], marker));
return segments;
}
private static Point FindPointInPolygon(List<Vertex> contour)
{
var bounds = new Rectangle();
bounds.Expand(contour);
int length = contour.Count;
int limit = 8;
var test = new Point();
Point a, b; // Current edge.
double cx, cy; // Center of current edge.
double dx, dy; // Direction perpendicular to edge.
for (int i = 0; i < length; i++)
{
a = contour[i];
b = contour[(i + 1) % length];
cx = (a.x + b.x) / 2;
cy = (a.y + b.y) / 2;
dx = (b.y - a.y) / 1.374;
dy = (a.x - b.x) / 1.374;
for (int j = 1; j <= limit; j++)
{
// Search to the right of the segment.
test.x = cx + dx / j;
test.y = cy + dy / j;
if (bounds.Contains(test) && IsPointInPolygon(test, contour))
{
return test;
}
// Search on the other side of the segment.
test.x = cx - dx / j;
test.y = cy - dy / j;
if (bounds.Contains(test) && IsPointInPolygon(test, contour))
{
return test;
}
}
}
throw new Exception();
}
/// <summary>
/// Return true if the given point is inside the polygon, or false if it is not.
/// </summary>
/// <param name="point">The point to check.</param>
/// <param name="poly">The polygon (list of contour points).</param>
/// <returns></returns>
/// <remarks>
/// WARNING: If the point is exactly on the edge of the polygon, then the function
/// may return true or false.
///
/// See http://alienryderflex.com/polygon/
/// </remarks>
private static bool IsPointInPolygon(Point point, List<Vertex> poly)
{
bool inside = false;
double x = point.x;
double y = point.y;
int count = poly.Count;
for (int i = 0, j = count - 1; i < count; i++)
{
if (((poly[i].y < y && poly[j].y >= y) || (poly[j].y < y && poly[i].y >= y))
&& (poly[i].x <= x || poly[j].x <= x))
{
inside ^= (poly[i].x + (y - poly[i].y) / (poly[j].y - poly[i].y) * (poly[j].x - poly[i].x) < x);
}
j = i;
}
return inside;
}
}
}
+6 -1
View File
@@ -1,4 +1,9 @@
// -----------------------------------------------------------------------
// <copyright file="IEdge.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Geometry
{
public interface IEdge
+9 -4
View File
@@ -1,4 +1,9 @@
// -----------------------------------------------------------------------
// <copyright file="IPolygon.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Geometry
{
using System.Collections.Generic;
@@ -17,7 +22,7 @@ namespace TriangleNet.Geometry
/// <summary>
/// Gets the segments of the polygon.
/// </summary>
List<IEdge> Segments { get; }
List<ISegment> Segments { get; }
/// <summary>
/// Gets a list of points defining the holes of the polygon.
@@ -30,12 +35,12 @@ namespace TriangleNet.Geometry
List<RegionPointer> Regions { get; }
/// <summary>
/// Gets or sets value indicating wether the vertices have marks or not.
/// Gets or sets a value indicating whether the vertices have marks or not.
/// </summary>
bool HasPointMarkers { get; set; }
/// <summary>
/// Gets or sets value indicating wether the segments have marks or not.
/// Gets or sets a value indicating whether the segments have marks or not.
/// </summary>
bool HasSegmentMarkers { get; set; }
+1 -1
View File
@@ -1,5 +1,5 @@
// -----------------------------------------------------------------------
// <copyright file="Segment.cs" company="">
// <copyright file="ISegment.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
+18 -159
View File
@@ -1,4 +1,9 @@
// -----------------------------------------------------------------------
// <copyright file="Polygon.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Geometry
{
using System;
@@ -14,7 +19,7 @@ namespace TriangleNet.Geometry
List<Point> holes;
List<RegionPointer> regions;
List<IEdge> segments;
List<ISegment> segments;
/// <inherit />
public List<Vertex> Points
@@ -35,7 +40,7 @@ namespace TriangleNet.Geometry
}
/// <inherit />
public List<IEdge> Segments
public List<ISegment> Segments
{
get { return segments; }
}
@@ -80,7 +85,7 @@ namespace TriangleNet.Geometry
holes = new List<Point>();
regions = new List<RegionPointer>();
segments = new List<IEdge>();
segments = new List<ISegment>();
HasPointMarkers = markers;
HasSegmentMarkers = markers;
@@ -90,76 +95,27 @@ namespace TriangleNet.Geometry
public void AddContour(IEnumerable<Vertex> points, int marker = 0,
bool hole = false, bool convex = false)
{
// Copy input to list.
var contour = new List<Vertex>(points);
var c = new Contour(points, marker);
int offset = this.points.Count;
int count = contour.Count;
this.points.AddRange(c.Points);
// Check if first vertex equals last vertex.
if (contour[0] == contour[count - 1])
{
count--;
contour.RemoveAt(count);
}
// Add points to polygon.
this.points.AddRange(contour);
var centroid = new Point(0.0, 0.0);
for (int i = 0; i < count; i++)
{
centroid.x += contour[i].x;
centroid.y += contour[i].y;
// Add segments to polygon.
this.segments.Add(new Edge(offset + i, offset + ((i + 1) % count), marker));
}
this.segments.AddRange(c.GetSegments());
if (hole)
{
if (convex)
{
// If the hole is convex, use its centroid.
centroid.x /= count;
centroid.y /= count;
this.holes.Add(centroid);
}
else
{
this.holes.Add(FindPointInPolygon(contour));
}
this.holes.Add(c.FindInteriorPoint(convex));
}
}
/// <inherit />
public void AddContour(IEnumerable<Vertex> points, int marker, Point hole)
{
// Copy input to list.
var contour = new List<Vertex>(points);
var c = new Contour(points, marker);
int offset = this.points.Count;
int count = contour.Count;
this.points.AddRange(c.Points);
// Check if first vertex equals last vertex.
if (contour[0] == contour[count - 1])
{
count--;
contour.RemoveAt(count);
}
this.segments.AddRange(c.GetSegments());
// Add points to polygon.
this.points.AddRange(contour);
for (int i = 0; i < count; i++)
{
// Add segments to polygon.
this.segments.Add(new Edge(offset + i, offset + ((i + 1) % count), marker));
}
// TODO: check if hole is actually inside contour?
this.holes.Add(hole);
}
@@ -180,109 +136,12 @@ namespace TriangleNet.Geometry
this.points.Add(vertex);
}
/// <summary>
/// Add a vertex to the polygon.
/// </summary>
public void Add(Vertex vertex, double[] attributes)
{
// TODO: check attibutes
vertex.attributes = attributes;
this.points.Add(vertex);
}
/// <summary>
/// Add a segment to the polygon.
/// </summary>
public void Add(Edge edge)
public void Add(ISegment segment)
{
this.segments.Add(edge);
}
private Point FindPointInPolygon(List<Vertex> contour)
{
var bounds = new Rectangle();
bounds.Expand(contour);
int length = contour.Count;
int limit = 8;
var test = new Point();
Point a, b; // Current edge.
double cx, cy; // Center of current edge.
double dx, dy; // Direction perpendicular to edge.
for (int i = 0; i < length; i++)
{
a = contour[i];
b = contour[(i + 1) % length];
cx = (a.x + b.x) / 2;
cy = (a.y + b.y) / 2;
dx = (b.y - a.y) / 1.374;
dy = (a.x - b.x) / 1.374;
for (int j = 1; j <= limit; j++)
{
// Search to the right of the segment.
test.x = cx + dx / j;
test.y = cy + dy / j;
if (bounds.Contains(test) && IsPointInPolygon(test, contour))
{
return test;
}
// Search on the other side of the segment.
test.x = cx - dx / j;
test.y = cy - dy / j;
if (bounds.Contains(test) && IsPointInPolygon(test, contour))
{
return test;
}
}
}
throw new Exception();
}
/// <summary>
/// Return true if the given point is inside the polygon, or false if it is not.
/// </summary>
/// <param name="point">The point to check.</param>
/// <param name="poly">The polygon (list of contour points).</param>
/// <returns></returns>
/// <remarks>
/// WARNING: If the point is exactly on the edge of the polygon, then the function
/// may return true or false.
///
/// See http://alienryderflex.com/polygon/
/// </remarks>
private bool IsPointInPolygon(Point point, List<Vertex> poly)
{
bool inside = false;
double x = point.x;
double y = point.y;
int count = poly.Count;
for (int i = 0, j = count - 1; i < count; i++)
{
if (((poly[i].y < y && poly[j].y >= y) || (poly[j].y < y && poly[i].y >= y))
&& (poly[i].x <= x || poly[j].x <= x))
{
inside ^= (poly[i].x + (y - poly[i].y) / (poly[j].y - poly[i].y) * (poly[j].x - poly[i].x) < x);
}
j = i;
}
return inside;
this.segments.Add(segment);
}
}
}
+93
View File
@@ -0,0 +1,93 @@
// -----------------------------------------------------------------------
// <copyright file="Segment.cs" company="">
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Geometry
{
using System;
/// <summary>
/// Represents a straight line segment in 2D space.
/// </summary>
public class Segment : ISegment
{
Vertex v0;
Vertex v1;
int boundary;
/// <summary>
/// Initializes a new instance of the <see cref="Segment" /> class.
/// </summary>
public Segment(Vertex v0, Vertex v1)
: this (v0, v1, 0)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Segment" /> class.
/// </summary>
public Segment(Vertex v0, Vertex v1, int boundary)
{
this.v0 = v0;
this.v1 = v1;
this.boundary = boundary;
}
/// <summary>
/// Gets the specified segment endpoint.
/// </summary>
/// <param name="index">The endpoint index (0 or 1).</param>
/// <returns></returns>
public Vertex GetVertex(int index)
{
if (index == 0)
{
return v0;
}
if (index == 1)
{
return v1;
}
throw new IndexOutOfRangeException();
}
/// <summary>
/// WARNING: not implemented.
/// </summary>
public ITriangle GetTriangle(int index)
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the first endpoints index.
/// </summary>
public int P0
{
get { return v0.id; }
}
/// <summary>
/// Gets the second endpoints index.
/// </summary>
public int P1
{
get { return v1.id; }
}
/// <summary>
/// Gets or sets the segments boundary mark.
/// </summary>
public int Boundary
{
get { return boundary; }
set { boundary = value; }
}
}
}
+2 -2
View File
@@ -29,10 +29,10 @@ namespace TriangleNet.IO
void Write(IMesh mesh, string filename);
/// <summary>
/// Save a mesh to a <see cref="StreamWriter" />.
/// Save a mesh to a <see cref="Stream" />.
/// </summary>
/// <param name="mesh">An instance of the <see cref="IMesh" /> interface.</param>
/// <param name="stream">The stream to save to.</param>
void Write(IMesh mesh, StreamWriter stream);
void Write(IMesh mesh, Stream stream);
}
}
+2 -2
View File
@@ -29,10 +29,10 @@ namespace TriangleNet.IO
void Write(IPolygon polygon, string filename);
/// <summary>
/// Save a polygon geometry to a <see cref="StreamWriter" />.
/// Save a polygon geometry to a <see cref="Stream" />.
/// </summary>
/// <param name="polygon">An instance of the <see cref="IPolygon" /> class.</param>
/// <param name="stream">The stream to save to.</param>
void Write(IPolygon polygon, StreamWriter stream);
void Write(IPolygon polygon, Stream stream);
}
}
+2 -2
View File
@@ -55,7 +55,7 @@ namespace TriangleNet.IO
TriangleWriter.WriteElements((Mesh)mesh, Path.ChangeExtension(filename, ".ele"));
}
public void Write(IMesh mesh, StreamWriter stream)
public void Write(IMesh mesh, Stream stream)
{
throw new NotImplementedException();
}
@@ -83,7 +83,7 @@ namespace TriangleNet.IO
TriangleWriter.WritePoly(polygon, filename);
}
public void Write(IPolygon polygon, StreamWriter stream)
public void Write(IPolygon polygon, Stream stream)
{
throw new NotImplementedException();
}
+28 -19
View File
@@ -59,29 +59,36 @@ namespace TriangleNet.IO
/// <param name="line">The current line.</param>
/// <param name="attributes">Number of point attributes</param>
/// <param name="marks">Number of point markers (0 or 1)</param>
static void ReadVertex(Polygon data, int index, string[] line, int attributes, int marks)
static void ReadVertex(List<Vertex> data, int index, string[] line, int attributes, int marks)
{
double x = double.Parse(line[1], nfi);
double y = double.Parse(line[2], nfi);
int mark = 0;
double[] attribs = attributes == 0 ? null : new double[attributes];
// Read the vertex attributes.
for (int j = 0; j < attributes; j++)
{
if (line.Length > 3 + j)
{
attribs[j] = double.Parse(line[3 + j], nfi);
}
}
var v = new Vertex(x, y);
// Read a vertex marker.
if (marks > 0 && line.Length > 3 + attributes)
{
mark = int.Parse(line[3 + attributes]);
v.Boundary = int.Parse(line[3 + attributes]);
}
data.Add(new Vertex(x, y, mark), attribs);
if (attributes > 0)
{
var attribs = new double[attributes];
// Read the vertex attributes.
for (int j = 0; j < attributes; j++)
{
if (line.Length > 3 + j)
{
attribs[j] = double.Parse(line[3 + j], nfi);
}
}
v.attributes = attribs;
}
data.Add(v);
}
#endregion
@@ -219,7 +226,7 @@ namespace TriangleNet.IO
startIndex = int.Parse(line[0], nfi);
}
ReadVertex(data, i, line, attributes, nodemarkers);
ReadVertex(data.Points, i, line, attributes, nodemarkers);
}
}
}
@@ -326,19 +333,21 @@ namespace TriangleNet.IO
startIndex = int.Parse(line[0], nfi);
}
ReadVertex(data, i, line, attributes, nodemarkers);
ReadVertex(data.Points, i, line, attributes, nodemarkers);
}
}
else
{
// If the .poly file claims there are zero vertices, that means that
// the vertices should be read from a separate .node file.
string nodefile = Path.ChangeExtension(polyfilename, ".node");
data = ReadNodeFile(nodefile);
data = ReadNodeFile(Path.ChangeExtension(polyfilename, ".node"));
invertices = data.Points.Count;
}
if (data.Points == null)
var points = data.Points;
if (points.Count == 0)
{
throw new Exception("No nodes available.");
}
@@ -401,7 +410,7 @@ namespace TriangleNet.IO
}
else
{
data.Add(new Edge(end1, end2, mark));
data.Add(new Segment(points[end1], points[end2], mark));
}
}
+7 -2
View File
@@ -202,17 +202,22 @@ namespace TriangleNet.IO
// Number of segments, number of boundary markers (zero or one).
writer.WriteLine("{0} {1}", polygon.Segments.Count, hasMarkers ? "1" : "0");
Vertex p, q;
int j = 0;
foreach (var seg in polygon.Segments)
{
p = seg.GetVertex(0);
q = seg.GetVertex(1);
// Segment number, indices of its two endpoints, and possibly a marker.
if (hasMarkers)
{
writer.WriteLine("{0} {1} {2} {3}", j, seg.P0, seg.P1, seg.Boundary);
writer.WriteLine("{0} {1} {2} {3}", j, p.ID, q.ID, seg.Boundary);
}
else
{
writer.WriteLine("{0} {1} {2}", j, seg.P0, seg.P1);
writer.WriteLine("{0} {1} {2}", j, p.ID, q.ID);
}
j++;
+10 -10
View File
@@ -35,7 +35,7 @@ namespace TriangleNet
// Using hashsets for memory management should quite fast.
internal Dictionary<int, Triangle> triangles;
internal Dictionary<int, Segment> subsegs;
internal Dictionary<int, SubSegment> subsegs;
internal Dictionary<int, Vertex> vertices;
// Hash seeds (should belong to mesh instance)
@@ -111,7 +111,7 @@ namespace TriangleNet
/// <summary>
/// Gets the mesh segments.
/// </summary>
public ICollection<Segment> Segments
public ICollection<SubSegment> Segments
{
get { return this.subsegs.Values; }
}
@@ -183,11 +183,11 @@ namespace TriangleNet
// triangle side or subsegment end that isn't attached to a real
// subsegment.
internal Segment dummysub;
internal SubSegment dummysub;
private void Initialize()
{
dummysub = new Segment();
dummysub = new SubSegment();
dummysub.hash = DUMMY;
// Initialize the two adjoining subsegments to be the omnipresent
@@ -231,7 +231,7 @@ namespace TriangleNet
vertices = new Dictionary<int, Vertex>();
triangles = new Dictionary<int, Triangle>();
subsegs = new Dictionary<int, Segment>();
subsegs = new Dictionary<int, SubSegment>();
flipstack = new Stack<Otri>();
@@ -287,13 +287,13 @@ namespace TriangleNet
}
else if (num == NodeNumbering.CuthillMcKee)
{
CuthillMcKee rcm = new CuthillMcKee();
int[] perm_inv = rcm.Renumber(this);
var rcm = new CuthillMcKee();
var iperm = rcm.Renumber(this);
// Permute the node indices.
foreach (var node in this.vertices.Values)
{
node.id = perm_inv[node.id];
node.id = iperm[node.id];
}
}
@@ -689,7 +689,7 @@ namespace TriangleNet
/// <param name="newsubseg">Reference to the new subseg.</param>
internal void MakeSegment(ref Osub newsubseg)
{
Segment seg = new Segment();
var seg = new SubSegment();
seg.hash = this.hash_seg++;
@@ -1924,7 +1924,7 @@ namespace TriangleNet
/// Deallocate space for a subsegment, marking it dead.
/// </summary>
/// <param name="dyingsubseg"></param>
internal void SubsegDealloc(Segment dyingsubseg)
internal void SubsegDealloc(SubSegment dyingsubseg)
{
// Mark the subsegment as dead. This makes it possible to detect dead
// subsegments when traversing the list of all subsegments.
@@ -169,9 +169,10 @@ namespace TriangleNet.Meshing
/// </summary>
public void FormSkeleton(IPolygon input)
{
Vertex endpoint1, endpoint2;
int end1, end2;
int boundmarker;
// The segment endpoints.
Vertex p, q;
int label;
mesh.insegments = 0;
@@ -191,51 +192,31 @@ namespace TriangleNet.Meshing
mesh.MakeVertexMap();
}
boundmarker = 0;
label = 0;
// Read and insert the segments.
foreach (var seg in input.Segments)
{
mesh.insegments++;
end1 = seg.P0;
end2 = seg.P1;
boundmarker = seg.Boundary;
label = seg.Boundary;
if ((end1 < 0) || (end1 >= mesh.invertices))
// TODO: wrap segment dictionary access in try / catch?
p = seg.GetVertex(0);
q = seg.GetVertex(1);
if ((p.x == q.x) && (p.y == q.y))
{
if (Log.Verbose)
{
logger.Warning("Invalid first endpoint of segment.", "Mesh.FormSkeleton().1");
}
}
else if ((end2 < 0) || (end2 >= mesh.invertices))
{
if (Log.Verbose)
{
logger.Warning("Invalid second endpoint of segment.", "Mesh.FormSkeleton().2");
logger.Warning("Endpoints of segment (IDs " + p.id + "/" + q.id + ") are coincident.",
"Mesh.FormSkeleton()");
}
}
else
{
// TODO: Is using the vertex ID reliable???
// It should be. The ID gets appropriately set in TransferNodes().
// Find the vertices numbered 'end1' and 'end2'.
endpoint1 = mesh.vertices[end1];
endpoint2 = mesh.vertices[end2];
if ((endpoint1.x == endpoint2.x) && (endpoint1.y == endpoint2.y))
{
if (Log.Verbose)
{
logger.Warning("Endpoints of segment (IDs " + end1 + "/" + end2 + ") are coincident.",
"Mesh.FormSkeleton()");
}
}
else
{
InsertSegment(endpoint1, endpoint2, boundmarker);
}
InsertSegment(p, q, label);
}
}
}
+20 -20
View File
@@ -213,10 +213,12 @@ namespace TriangleNet.Meshing
Otri checkneighbor = default(Otri);
Osub subseg = default(Osub);
Otri prevlink; // Triangle
TVertex shorg;
TVertex segmentorg, segmentdest;
int[] end = new int[2];
TVertex tmp;
TVertex sorg, sdest;
bool notfound;
//bool segmentmarkers = false;
int boundmarker;
int aroundvertex;
@@ -234,40 +236,38 @@ namespace TriangleNet.Meshing
{
subseg.seg = item;
end[0] = polygon.Segments[i].P0;
end[1] = polygon.Segments[i].P1;
sorg = polygon.Segments[i].GetVertex(0);
sdest = polygon.Segments[i].GetVertex(1);
boundmarker = polygon.Segments[i].Boundary;
for (int j = 0; j < 2; j++)
if ((sorg.id < 0 || sorg.id >= mesh.invertices) || (sdest.id < 0 || sdest.id >= mesh.invertices))
{
if ((end[j] < 0) || (end[j] >= mesh.invertices))
{
Log.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()");
throw new Exception("Segment has an invalid vertex index.");
}
Log.Instance.Error("Segment has an invalid vertex index.", "MeshReader.Reconstruct()");
throw new Exception("Segment has an invalid vertex index.");
}
// set the subsegment's vertices.
subseg.orient = 0;
segmentorg = mesh.vertices[end[0]];
segmentdest = mesh.vertices[end[1]];
subseg.SetOrg(segmentorg);
subseg.SetDest(segmentdest);
subseg.SetSegOrg(segmentorg);
subseg.SetSegDest(segmentdest);
subseg.SetOrg(sorg);
subseg.SetDest(sdest);
subseg.SetSegOrg(sorg);
subseg.SetSegDest(sdest);
subseg.seg.boundary = boundmarker;
// Try linking the subsegment to triangles that share these vertices.
for (subseg.orient = 0; subseg.orient < 2; subseg.orient++)
{
// Take the number for the destination of subsegloop.
aroundvertex = end[1 - subseg.orient];
aroundvertex = subseg.orient == 1 ? sorg.id : sdest.id;
int index = vertexarray[aroundvertex].Count - 1;
// Look for triangles having this vertex.
prevlink = vertexarray[aroundvertex][index];
nexttri = vertexarray[aroundvertex][index];
checktri = nexttri;
shorg = subseg.Org();
tmp = subseg.Org();
notfound = true;
// Look for triangles having this edge. Note that I'm only
// comparing each triangle's destination with the subsegment;
@@ -280,7 +280,7 @@ namespace TriangleNet.Meshing
{
checkdest = checktri.Dest();
if (shorg == checkdest)
if (tmp == checkdest)
{
// We have a match. Remove this triangle from the list.
//prevlink = vertexarray[aroundvertex][index];
+31 -7
View File
@@ -100,10 +100,10 @@ namespace TriangleNet.Meshing
left = bounds.Left;
bottom = bounds.Bottom;
int i, j, k, l, n;
int i, j, k, l, n = 0;
// Add vertices.
var points = polygon.Points;
var points = new Vertex[(nx + 1) * (ny + 1)];
for (i = 0; i <= nx; i++)
{
@@ -113,10 +113,12 @@ namespace TriangleNet.Meshing
{
y = bottom + j * dy;
points.Add(new Vertex(x, y));
points[n++] = new Vertex(x, y);
}
}
polygon.Points.AddRange(points);
n = 0;
// Set vertex hash and id.
@@ -130,22 +132,44 @@ namespace TriangleNet.Meshing
segments.Capacity = 2 * (nx + ny);
Vertex a, b;
for (j = 0; j < ny; j++)
{
// Left
segments.Add(new Edge(j, j + 1));
a = points[j];
b = points[j + 1];
segments.Add(new Segment(a, b, 1));
a.Boundary = b.Boundary = 1;
// Right
segments.Add(new Edge(nx * (ny + 1) + j, nx * (ny + 1) + (j + 1)));
a = points[nx * (ny + 1) + j];
b = points[nx * (ny + 1) + (j + 1)];
segments.Add(new Segment(a, b, 1));
a.Boundary = b.Boundary = 1;
}
for (i = 0; i < nx; i++)
{
// Bottom
segments.Add(new Edge(i * (ny + 1), (i + 1) * (ny + 1)));
a = points[i * (ny + 1)];
b = points[(i + 1) * (ny + 1)];
segments.Add(new Segment(a, b, 1));
a.Boundary = b.Boundary = 1;
// Top
segments.Add(new Edge(i * (ny + 1) + nx, (i + 1) * (ny + 1) + nx));
a = points[i * (ny + 1) + nx];
b = points[(i + 1) * (ny + 1) + nx];
segments.Add(new Segment(a, b, 1));
a.Boundary = b.Boundary = 1;
}
// Add triangles.
+1 -1
View File
@@ -23,7 +23,7 @@ namespace TriangleNet.Meshing
/// <summary>
/// Gets the segments (constraint edges) of the mesh.
/// </summary>
ICollection<Segment> Segments { get; }
ICollection<SubSegment> Segments { get; }
/// <summary>
/// Gets the triangles of the mesh.
+93 -20
View File
@@ -7,6 +7,7 @@
namespace TriangleNet.Tools
{
using System;
using System.Collections.Generic;
using TriangleNet.Geometry;
public static class PolygonValidator
@@ -18,23 +19,37 @@ namespace TriangleNet.Tools
{
var logger = Log.Instance;
var points = poly.Points;
int horrors = 0;
int i = 0;
int count = poly.Points.Count;
int count = points.Count;
foreach (var p in poly.Points)
if (count < 3)
{
logger.Warning("Polygon must have at least 3 vertices.", "PolygonValidator.IsConsistent()");
return false;
}
foreach (var p in points)
{
if (p == null)
{
horrors++;
logger.Warning(String.Format("Point {0} is null.", i), "PolygonValidator.IsConsistent()");
}
else if (double.IsNaN(p.x + p.y) || double.IsInfinity(p.x + p.y))
else if (double.IsNaN(p.x) || double.IsNaN(p.y))
{
horrors++;
logger.Warning(String.Format("Point {0} has invalid coordinates.", i), "PolygonValidator.IsConsistent()");
}
else if (double.IsInfinity(p.x) || double.IsInfinity(p.y))
{
horrors++;
logger.Warning(String.Format("Point {0} has invalid coordinates.", i), "PolygonValidator.IsConsistent()");
}
i++;
}
@@ -46,27 +61,33 @@ namespace TriangleNet.Tools
{
horrors++;
logger.Warning(String.Format("Segment {0} is null.", i), "PolygonValidator.IsConsistent()");
}
else
{
if (seg.P0 < 0 || seg.P0 >= count)
{
horrors++;
logger.Warning(String.Format("Segment {0} has invalid startpoint.", i),
"PolygonValidator.IsConsistent()");
}
if (seg.P1 < 0 || seg.P1 >= count)
{
horrors++;
logger.Warning(String.Format("Segment {0} has invalid endpoint.", i),
"PolygonValidator.IsConsistent()");
}
// Always abort if a NULL-segment is found.
return false;
}
var p = seg.GetVertex(0);
var q = seg.GetVertex(1);
if ((p.x == q.x) && (p.y == q.y))
{
horrors++;
logger.Warning(String.Format("Endpoints of segment {0} are coincident (IDs {1} / {2}).", i, p.id, q.id),
"PolygonValidator.IsConsistent()");
}
i++;
}
if (points[0].ID == points[1].ID)
{
horrors += CheckVertexIDs(poly, count);
}
else
{
horrors += CheckDuplicateIDs(poly);
}
return horrors == 0;
}
@@ -116,8 +137,8 @@ namespace TriangleNet.Tools
q0 = p0;
q1 = p1;
p0 = (seg.P0 >= 0 && seg.P0 < count) ? poly.Points[seg.P0] : null;
p1 = (seg.P1 >= 0 && seg.P1 < count) ? poly.Points[seg.P1] : null;
p0 = seg.GetVertex(0);
p1 = seg.GetVertex(1);
if (q0 != null && q1 != null)
{
@@ -160,5 +181,57 @@ namespace TriangleNet.Tools
// Calculate the Z coordinate of the cross product.
return (a.X - b.X) * (c.Y - b.Y) - (a.Y - b.Y) * (c.X - b.X);
}
private static int CheckVertexIDs(IPolygon poly, int count)
{
var logger = Log.Instance;
int horrors = 0;
int i = 0;
Vertex p, q;
foreach (var seg in poly.Segments)
{
p = seg.GetVertex(0);
q = seg.GetVertex(1);
if (p.ID < 0 || p.ID >= count)
{
horrors++;
logger.Warning(String.Format("Segment {0} has invalid startpoint.", i),
"PolygonValidator.IsConsistent()");
}
if (q.ID < 0 || q.ID >= count)
{
horrors++;
logger.Warning(String.Format("Segment {0} has invalid endpoint.", i),
"PolygonValidator.IsConsistent()");
}
i++;
}
return horrors;
}
private static int CheckDuplicateIDs(IPolygon poly)
{
var ids = new HashSet<int>();
// Check for duplicate ids.
foreach (var p in poly.Points)
{
if (!ids.Add(p.ID))
{
Log.Instance.Warning("Found duplicate vertex ids.", "PolygonValidator.IsConsistent()");
return 1;
}
}
return 0;
}
}
}
+5 -5
View File
@@ -20,10 +20,10 @@ namespace TriangleNet.Topology
/// </remarks>
public struct Osub
{
internal Segment seg;
internal SubSegment seg;
internal int orient; // Ranges from 0 to 1.
public Segment Segment
public SubSegment Segment
{
get { return seg; }
}
@@ -213,7 +213,7 @@ namespace TriangleNet.Topology
/// </summary>
/// <remarks>Note that the other subsegment will still think it's
/// connected to this subsegment.</remarks>
internal void Dissolve(Segment dummy)
internal void Dissolve(SubSegment dummy)
{
seg.subsegs[orient].seg = dummy;
}
@@ -237,7 +237,7 @@ namespace TriangleNet.Topology
/// <summary>
/// Check a subsegment's deallocation.
/// </summary>
internal static bool IsDead(Segment sub)
internal static bool IsDead(SubSegment sub)
{
return sub.subsegs[0].seg == null;
}
@@ -245,7 +245,7 @@ namespace TriangleNet.Topology
/// <summary>
/// Set a subsegment's deallocation.
/// </summary>
internal static void Kill(Segment sub)
internal static void Kill(SubSegment sub)
{
sub.subsegs[0].seg = null;
sub.subsegs[1].seg = null;
+1 -1
View File
@@ -454,7 +454,7 @@ namespace TriangleNet.Topology
/// <summary>
/// Dissolve a bond (from the triangle side).
/// </summary>
internal void SegDissolve(Segment dummy)
internal void SegDissolve(SubSegment dummy)
{
tri.subsegs[orient].seg = dummy;
}
@@ -13,7 +13,7 @@ namespace TriangleNet.Topology
/// <summary>
/// The subsegment data structure.
/// </summary>
public class Segment : ISegment
public class SubSegment : ISegment
{
// Hash for dictionary. Will be set by mesh instance.
internal int hash;
@@ -23,7 +23,7 @@ namespace TriangleNet.Topology
internal Otri[] triangles;
internal int boundary;
public Segment()
public SubSegment()
{
// Four NULL vertices.
vertices = new Vertex[4];
+54 -53
View File
@@ -38,15 +38,31 @@
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="Geometry\Contour.cs" />
<Compile Include="Geometry\Edge.cs" />
<Compile Include="Geometry\ExtensionMethods.cs" />
<Compile Include="Geometry\IEdge.cs" />
<Compile Include="Geometry\IPolygon.cs" />
<Compile Include="Geometry\ExtensionMethods.cs" />
<Compile Include="Geometry\ISegment.cs" />
<Compile Include="Geometry\ITriangle.cs" />
<Compile Include="Geometry\Point.cs" />
<Compile Include="Geometry\Polygon.cs" />
<Compile Include="Geometry\Rectangle.cs" />
<Compile Include="Geometry\RegionPointer.cs" />
<Compile Include="Geometry\Segment.cs" />
<Compile Include="Geometry\Vertex.cs" />
<Compile Include="IO\DebugWriter.cs" />
<Compile Include="IO\FileProcessor.cs" />
<Compile Include="IO\IFileFormat.cs" />
<Compile Include="IO\IMeshFormat.cs" />
<Compile Include="IO\InputTriangle.cs" />
<Compile Include="IO\IPolygonFormat.cs" />
<Compile Include="IO\TriangleFormat.cs" />
<Compile Include="IO\TriangleReader.cs" />
<Compile Include="IO\TriangleWriter.cs" />
<Compile Include="Meshing\ConstraintMesher.cs" />
<Compile Include="Meshing\ConstraintOptions.cs" />
<Compile Include="Meshing\Converter.cs" />
<Compile Include="Meshing\GenericMesher.cs" />
@@ -54,69 +70,54 @@
<Compile Include="Meshing\IMesh.cs" />
<Compile Include="Meshing\IQualityMesher.cs" />
<Compile Include="Meshing\ITriangulator.cs" />
<Compile Include="Meshing\Data\BadTriQueue.cs" />
<Compile Include="Behavior.cs" />
<Compile Include="Meshing\ConstraintMesher.cs" />
<Compile Include="Meshing\QualityOptions.cs" />
<Compile Include="Meshing\QualityMesher.cs" />
<Compile Include="Meshing\Algorithm\Dwyer.cs" />
<Compile Include="Meshing\Algorithm\Incremental.cs" />
<Compile Include="Meshing\Algorithm\SweepLine.cs" />
<Compile Include="Meshing\Data\BadSubseg.cs" />
<Compile Include="Meshing\Data\BadTriangle.cs" />
<Compile Include="Meshing\Data\BadTriQueue.cs" />
<Compile Include="Meshing\Iterators\EdgeIterator.cs" />
<Compile Include="Meshing\Iterators\RegionIterator.cs" />
<Compile Include="Tools\AdjacencyMatrix.cs" />
<Compile Include="Tools\CuthillMcKee.cs" />
<Compile Include="Tools\IntersectionHelper.cs" />
<Compile Include="Tools\PointSorter.cs" />
<Compile Include="Tools\PolygonValidator.cs" />
<Compile Include="Topology\DCEL\DcelMesh.cs" />
<Compile Include="Tools\QualityMeasure.cs" />
<Compile Include="Tools\TriangleQuadTree.cs" />
<Compile Include="Tools\Statistic.cs" />
<Compile Include="Topology\Osub.cs" />
<Compile Include="Topology\Otri.cs" />
<Compile Include="Topology\Segment.cs" />
<Compile Include="Topology\SubSegment.cs" />
<Compile Include="Topology\Triangle.cs" />
<Compile Include="Geometry\Vertex.cs" />
<Compile Include="Meshing\Algorithm\Dwyer.cs" />
<Compile Include="Geometry\Rectangle.cs" />
<Compile Include="Geometry\Edge.cs" />
<Compile Include="Meshing\Iterators\EdgeIterator.cs" />
<Compile Include="Geometry\ITriangle.cs" />
<Compile Include="Geometry\Point.cs" />
<Compile Include="Geometry\RegionPointer.cs" />
<Compile Include="Geometry\ISegment.cs" />
<Compile Include="IO\DebugWriter.cs" />
<Compile Include="IO\TriangleWriter.cs" />
<Compile Include="IO\IPolygonFormat.cs" />
<Compile Include="IO\IMeshFormat.cs" />
<Compile Include="IO\InputTriangle.cs" />
<Compile Include="IO\TriangleReader.cs" />
<Compile Include="IO\TriangleFormat.cs" />
<Compile Include="Logging\ILog.cs" />
<Compile Include="Logging\ILogItem.cs" />
<Compile Include="Log.cs" />
<Compile Include="Logging\LogItem.cs" />
<Compile Include="Meshing\QualityOptions.cs" />
<Compile Include="MeshValidator.cs" />
<Compile Include="NewLocation.cs" />
<Compile Include="Meshing\QualityMesher.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Meshing\Algorithm\Incremental.cs" />
<Compile Include="Mesh.cs" />
<Compile Include="RobustPredicates.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Sampler.cs" />
<Compile Include="Smoothing\ISmoother.cs" />
<Compile Include="Smoothing\SimpleSmoother.cs" />
<Compile Include="Tools\AdjacencyMatrix.cs" />
<Compile Include="Tools\PointSorter.cs" />
<Compile Include="Voronoi\Legacy\BoundedVoronoiLegacy.cs" />
<Compile Include="Tools\CuthillMcKee.cs" />
<Compile Include="Voronoi\Legacy\IVoronoi.cs" />
<Compile Include="Tools\TriangleQuadTree.cs" />
<Compile Include="Tools\QualityMeasure.cs" />
<Compile Include="Meshing\Iterators\RegionIterator.cs" />
<Compile Include="Tools\Statistic.cs" />
<Compile Include="Meshing\Algorithm\SweepLine.cs" />
<Compile Include="Voronoi\Legacy\SimpleVoronoi.cs" />
<Compile Include="Voronoi\Legacy\VoronoiRegion.cs" />
<Compile Include="TriangleLocator.cs" />
<Compile Include="Voronoi\BoundedVoronoi.cs" />
<Compile Include="Topology\DCEL\DcelMesh.cs" />
<Compile Include="Topology\DCEL\Face.cs" />
<Compile Include="Topology\DCEL\HalfEdge.cs" />
<Compile Include="Topology\DCEL\Vertex.cs" />
<Compile Include="Smoothing\ISmoother.cs" />
<Compile Include="Smoothing\SimpleSmoother.cs" />
<Compile Include="Voronoi\BoundedVoronoi.cs" />
<Compile Include="Voronoi\StandardVoronoi.cs" />
<Compile Include="Voronoi\VoronoiBase.cs" />
<Compile Include="Voronoi\Legacy\BoundedVoronoiLegacy.cs" />
<Compile Include="Voronoi\Legacy\IVoronoi.cs" />
<Compile Include="Voronoi\Legacy\SimpleVoronoi.cs" />
<Compile Include="Voronoi\Legacy\VoronoiRegion.cs" />
<Compile Include="Logging\ILog.cs" />
<Compile Include="Logging\ILogItem.cs" />
<Compile Include="Logging\LogItem.cs" />
<Compile Include="Behavior.cs" />
<Compile Include="Log.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Mesh.cs" />
<Compile Include="MeshValidator.cs" />
<Compile Include="NewLocation.cs" />
<Compile Include="RobustPredicates.cs" />
<Compile Include="Sampler.cs" />
<Compile Include="TriangleLocator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
@@ -30,7 +30,7 @@ namespace TriangleNet.Voronoi.Legacy
List<Point> segPoints;
int segIndex;
Dictionary<int, Segment> subsegMap;
Dictionary<int, SubSegment> subsegMap;
bool includeBoundary = true;
@@ -151,7 +151,7 @@ namespace TriangleNet.Voronoi.Legacy
int blinded = 0;
Stack<Triangle> triangles;
subsegMap = new Dictionary<int, Segment>();
subsegMap = new Dictionary<int, SubSegment>();
Otri f = default(Otri);
Otri f0 = default(Otri);