Code documentation updates.
This commit is contained in:
@@ -13,16 +13,28 @@ namespace TriangleNet
|
||||
/// </summary>
|
||||
public class Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
||||
/// </summary>
|
||||
public Configuration()
|
||||
: this(() => RobustPredicates.Default, () => new TrianglePool())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
||||
/// </summary>
|
||||
/// <param name="predicates">Factory method for <see cref="IPredicates" />.</param>
|
||||
public Configuration(Func<IPredicates> predicates)
|
||||
: this(predicates, () => new TrianglePool())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Configuration" /> class.
|
||||
/// </summary>
|
||||
/// <param name="predicates">Factory method for <see cref="IPredicates" />.</param>
|
||||
/// <param name="trianglePool">Factory method for <see cref="TrianglePool" />.</param>
|
||||
public Configuration(Func<IPredicates> predicates, Func<TrianglePool> trianglePool)
|
||||
{
|
||||
Predicates = predicates;
|
||||
|
||||
@@ -10,6 +10,9 @@ namespace TriangleNet.Geometry
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a contour of a polygon (outer boundary or internal holes).
|
||||
/// </summary>
|
||||
public class Contour
|
||||
{
|
||||
int marker;
|
||||
@@ -54,6 +57,10 @@ namespace TriangleNet.Geometry
|
||||
this.convex = convex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of segments of the contour.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ISegment> GetSegments()
|
||||
{
|
||||
var segments = new List<ISegment>();
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace TriangleNet.Geometry
|
||||
using System;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods.
|
||||
/// </summary>
|
||||
public static class ExtensionMethods
|
||||
{
|
||||
#region IPolygon extensions
|
||||
@@ -19,6 +22,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying constraint options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">Polygon instance.</param>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options)
|
||||
{
|
||||
@@ -28,6 +32,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">Polygon instance.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, QualityOptions quality)
|
||||
{
|
||||
@@ -37,6 +42,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality and constraint options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">Polygon instance.</param>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
public static IMesh Triangulate(this IPolygon polygon, ConstraintOptions options, QualityOptions quality)
|
||||
@@ -47,6 +53,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Triangulates a polygon, applying quality and constraint options.
|
||||
/// </summary>
|
||||
/// <param name="polygon">Polygon instance.</param>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
/// <param name="quality">Quality options.</param>
|
||||
/// <param name="triangulator">The triangulation algorithm.</param>
|
||||
@@ -67,6 +74,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Test whether a given point lies inside a triangle or not.
|
||||
/// </summary>
|
||||
/// <param name="triangle">Triangle instance.</param>
|
||||
/// <param name="p">Point to locate.</param>
|
||||
/// <returns>True, if point is inside or on the edge of this triangle.</returns>
|
||||
public static bool Contains(this ITriangle triangle, Point p)
|
||||
@@ -77,6 +85,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Test whether a given point lies inside a triangle or not.
|
||||
/// </summary>
|
||||
/// <param name="triangle">Triangle instance.</param>
|
||||
/// <param name="x">Point to locate.</param>
|
||||
/// <param name="y">Point to locate.</param>
|
||||
/// <returns>True, if point is inside or on the edge of this triangle.</returns>
|
||||
@@ -117,6 +126,11 @@ namespace TriangleNet.Geometry
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the bounding box of the triangle.
|
||||
/// </summary>
|
||||
/// <param name="triangle">Triangle instance.</param>
|
||||
/// <returns></returns>
|
||||
public static Rectangle Bounds(this ITriangle triangle)
|
||||
{
|
||||
var bounds = new Rectangle();
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple edge interface.
|
||||
/// </summary>
|
||||
public interface IEdge
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -28,16 +28,30 @@ namespace TriangleNet.Geometry
|
||||
internal double z;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Point" /> class.
|
||||
/// </summary>
|
||||
public Point()
|
||||
: this(0.0, 0.0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Point" /> class.
|
||||
/// </summary>
|
||||
/// <param name="x">The x coordinate.</param>
|
||||
/// <param name="y">The y coordinate.</param>
|
||||
public Point(double x, double y)
|
||||
: this(x, y, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Point" /> class.
|
||||
/// </summary>
|
||||
/// <param name="x">The x coordinate.</param>
|
||||
/// <param name="y">The y coordinate.</param>
|
||||
/// <param name="label">The point label.</param>
|
||||
public Point(double x, double y, int label)
|
||||
{
|
||||
this.x = x;
|
||||
@@ -101,6 +115,7 @@ namespace TriangleNet.Geometry
|
||||
|
||||
#region Overriding Equals() and == Operator
|
||||
|
||||
/// <inheritdoc />
|
||||
public static bool operator ==(Point a, Point b)
|
||||
{
|
||||
if (a is null)
|
||||
@@ -118,13 +133,16 @@ namespace TriangleNet.Geometry
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public static bool operator !=(Point a, Point b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj) => Equals(obj as Point);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(Point p)
|
||||
{
|
||||
// If object is null return false.
|
||||
@@ -139,6 +157,7 @@ namespace TriangleNet.Geometry
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public int CompareTo(Point other)
|
||||
{
|
||||
if (x == other.x && y == other.y)
|
||||
@@ -149,6 +168,7 @@ namespace TriangleNet.Geometry
|
||||
return (x < other.x || (x == other.x && y < other.y)) ? -1 : 1;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 19;
|
||||
|
||||
@@ -25,6 +25,10 @@ namespace TriangleNet.Geometry
|
||||
xmax = ymax = -double.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Rectangle" /> class.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
public Rectangle(Rectangle other)
|
||||
: this(other.Left, other.Bottom, other.Right, other.Top)
|
||||
{
|
||||
@@ -125,8 +129,7 @@ namespace TriangleNet.Geometry
|
||||
/// <summary>
|
||||
/// Expand rectangle to include given rectangle.
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate.</param>
|
||||
/// <param name="y">Y coordinate.</param>
|
||||
/// <param name="other">The other rectangle.</param>
|
||||
public void Expand(Rectangle other)
|
||||
{
|
||||
xmin = Math.Min(xmin, other.xmin);
|
||||
|
||||
@@ -106,6 +106,7 @@ namespace TriangleNet.Geometry
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode() => hash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Save a polygon geometry to disk.
|
||||
/// </summary>
|
||||
/// <param name="mesh">An instance of the <see cref="IPolygon" /> class.</param>
|
||||
/// <param name="polygon">An instance of the <see cref="IPolygon" /> class.</param>
|
||||
/// <param name="filename">The path of the file to save.</param>
|
||||
public static void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace TriangleNet.IO
|
||||
internal int label;
|
||||
internal double area;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InputTriangle" /> class.
|
||||
/// </summary>
|
||||
public InputTriangle(int p0, int p1, int p2)
|
||||
{
|
||||
vertices = new int[] { p0, p1, p2 };
|
||||
|
||||
@@ -17,6 +17,11 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
public class TriangleFormat : IPolygonFormat, IMeshFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a value indicating whether the given file is supported by this format.
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsSupported(string file)
|
||||
{
|
||||
string ext = Path.GetExtension(file).ToLower();
|
||||
@@ -29,6 +34,7 @@ namespace TriangleNet.IO
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMesh Import(string filename)
|
||||
{
|
||||
string ext = Path.GetExtension(filename);
|
||||
@@ -49,6 +55,7 @@ namespace TriangleNet.IO
|
||||
throw new NotSupportedException("Could not load '" + filename + "' file.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Write(IMesh mesh, string filename)
|
||||
{
|
||||
var writer = new TriangleWriter();
|
||||
@@ -57,11 +64,13 @@ namespace TriangleNet.IO
|
||||
writer.WriteElements((Mesh)mesh, Path.ChangeExtension(filename, ".ele"));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Write(IMesh mesh, Stream stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPolygon Read(string filename)
|
||||
{
|
||||
string ext = Path.GetExtension(filename);
|
||||
@@ -79,11 +88,13 @@ namespace TriangleNet.IO
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
(new TriangleWriter()).WritePoly(polygon, filename);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Write(IPolygon polygon, Stream stream)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <param name="readElements">If true, look for an associated .ele file.</param>
|
||||
/// <param name="readElements">If true, look for an associated .area file.</param>
|
||||
/// <param name="readArea">If true, look for an associated .area file.</param>
|
||||
public Polygon ReadPolyFile(string polyfilename, bool readElements, bool readArea)
|
||||
{
|
||||
// Read poly file
|
||||
@@ -603,7 +603,6 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="areafilename"></param>
|
||||
/// <param name="intriangles"></param>
|
||||
/// <param name="data"></param>
|
||||
private double[] ReadAreaFile(string areafilename, int intriangles)
|
||||
{
|
||||
double[] data = null;
|
||||
|
||||
@@ -100,8 +100,11 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Write the vertices to a stream.
|
||||
/// </summary>
|
||||
/// <param name="nodes"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="nodes"></param>
|
||||
/// <param name="markers"></param>
|
||||
/// <param name="attribs"></param>
|
||||
/// <param name="jettison"></param>
|
||||
private void WriteNodes(StreamWriter writer, IEnumerable<Vertex> nodes, bool markers,
|
||||
int attribs, bool jettison)
|
||||
{
|
||||
|
||||
@@ -3,14 +3,68 @@ namespace TriangleNet
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Geometric predicates interface.
|
||||
/// </summary>
|
||||
public interface IPredicates
|
||||
{
|
||||
/// <summary>
|
||||
/// Check, if the three points appear in counterclockwise order. The result is
|
||||
/// also a rough approximation of twice the signed area of the triangle defined
|
||||
/// by the three points.
|
||||
/// </summary>
|
||||
/// <param name="a">Point a.</param>
|
||||
/// <param name="b">Point b.</param>
|
||||
/// <param name="c">Point c.</param>
|
||||
/// <returns>Return a positive value if the points pa, pb, and pc occur in
|
||||
/// counterclockwise order; a negative value if they occur in clockwise order;
|
||||
/// and zero if they are collinear.</returns>
|
||||
double CounterClockwise(Point a, Point b, Point c);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the point pd lies inside the circle passing through pa, pb, and pc. The
|
||||
/// points pa, pb, and pc must be in counterclockwise order, or the sign of the result
|
||||
/// will be reversed.
|
||||
/// </summary>
|
||||
/// <param name="a">Point a.</param>
|
||||
/// <param name="b">Point b.</param>
|
||||
/// <param name="c">Point c.</param>
|
||||
/// <param name="p">Point d.</param>
|
||||
/// <returns>Return a positive value if the point pd lies inside the circle passing through
|
||||
/// pa, pb, and pc; a negative value if it lies outside; and zero if the four points
|
||||
/// are cocircular.</returns>
|
||||
double InCircle(Point a, Point b, Point c, Point p);
|
||||
|
||||
/// <summary>
|
||||
/// Find the circumcenter of a triangle.
|
||||
/// </summary>
|
||||
/// <param name="org">Triangle point.</param>
|
||||
/// <param name="dest">Triangle point.</param>
|
||||
/// <param name="apex">Triangle point.</param>
|
||||
/// <param name="xi">Relative coordinate of new location.</param>
|
||||
/// <param name="eta">Relative coordinate of new location.</param>
|
||||
/// <returns>Coordinates of the circumcenter</returns>
|
||||
/// <remarks>
|
||||
/// The result is returned both in terms of x-y coordinates and xi-eta
|
||||
/// (barycentric) coordinates. The xi-eta coordinate system is defined in
|
||||
/// terms of the triangle: the origin of the triangle is the origin of the
|
||||
/// coordinate system; the destination of the triangle is one unit along the
|
||||
/// xi axis; and the apex of the triangle is one unit along the eta axis.
|
||||
/// This procedure also returns the square of the length of the triangle's
|
||||
/// shortest edge.
|
||||
/// </remarks>
|
||||
Point FindCircumcenter(Point org, Point dest, Point apex, ref double xi, ref double eta);
|
||||
|
||||
/// <summary>
|
||||
/// Find the circumcenter of a triangle.
|
||||
/// </summary>
|
||||
/// <param name="org">Triangle point.</param>
|
||||
/// <param name="dest">Triangle point.</param>
|
||||
/// <param name="apex">Triangle point.</param>
|
||||
/// <param name="xi">Relative coordinate of new location.</param>
|
||||
/// <param name="eta">Relative coordinate of new location.</param>
|
||||
/// <param name="offconstant">Off-center constant.</param>
|
||||
/// <returns>Coordinates of the circumcenter (or off-center)</returns>
|
||||
Point FindCircumcenter(Point org, Point dest, Point apex, ref double xi, ref double eta,
|
||||
double offconstant);
|
||||
}
|
||||
|
||||
+8
-7
@@ -9,6 +9,9 @@ namespace TriangleNet
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// The log level.
|
||||
/// </summary>
|
||||
public enum LogLevel { Info, Warning, Error }
|
||||
|
||||
/// <summary>
|
||||
@@ -68,6 +71,7 @@ namespace TriangleNet
|
||||
|
||||
/// <summary>
|
||||
/// A simple logger, which logs messages to a List.
|
||||
/// </summary>
|
||||
public sealed class Log
|
||||
{
|
||||
/// <summary>
|
||||
@@ -95,13 +99,10 @@ namespace TriangleNet
|
||||
|
||||
private Log() { }
|
||||
|
||||
public static Log Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Log"/> instance.
|
||||
/// </summary>
|
||||
public static Log Instance => instance;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
+57
-54
@@ -219,6 +219,11 @@ namespace TriangleNet
|
||||
TransferNodes(points);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refine the mesh to match given quality options.
|
||||
/// </summary>
|
||||
/// <param name="quality">The quality constraints.</param>
|
||||
/// <param name="delaunay">A value indicating, whether the refined mesh should be Conforming Delaunay.</param>
|
||||
public void Refine(QualityOptions quality, bool delaunay = false)
|
||||
{
|
||||
invertices = vertices.Count;
|
||||
@@ -319,10 +324,8 @@ namespace TriangleNet
|
||||
target.hullsize = this.hullsize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset all the mesh data. This method will also wipe
|
||||
/// out all mesh data.
|
||||
/// </summary>
|
||||
|
||||
// TODO: Remove unused method.
|
||||
private void ResetData()
|
||||
{
|
||||
vertices.Clear();
|
||||
@@ -369,7 +372,7 @@ namespace TriangleNet
|
||||
/// <summary>
|
||||
/// Read the vertices from memory.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <param name="points">The input data.</param>
|
||||
private void TransferNodes(IList<Vertex> points)
|
||||
{
|
||||
invertices = points.Count;
|
||||
@@ -1392,55 +1395,55 @@ namespace TriangleNet
|
||||
/// <param name="triflaws">A flag that determines whether the new triangles should
|
||||
/// be tested for quality, and enqueued if they are bad.</param>
|
||||
/// <remarks>
|
||||
// This is a conceptually difficult routine. The starting assumption is
|
||||
// that we have a polygon with n sides. n - 1 of these sides are currently
|
||||
// represented as edges in the mesh. One side, called the "base", need not
|
||||
// be.
|
||||
//
|
||||
// Inside the polygon is a structure I call a "fan", consisting of n - 1
|
||||
// triangles that share a common origin. For each of these triangles, the
|
||||
// edge opposite the origin is one of the sides of the polygon. The
|
||||
// primary edge of each triangle is the edge directed from the origin to
|
||||
// the destination; note that this is not the same edge that is a side of
|
||||
// the polygon. 'firstedge' is the primary edge of the first triangle.
|
||||
// From there, the triangles follow in counterclockwise order about the
|
||||
// polygon, until 'lastedge', the primary edge of the last triangle.
|
||||
// 'firstedge' and 'lastedge' are probably connected to other triangles
|
||||
// beyond the extremes of the fan, but their identity is not important, as
|
||||
// long as the fan remains connected to them.
|
||||
//
|
||||
// Imagine the polygon oriented so that its base is at the bottom. This
|
||||
// puts 'firstedge' on the far right, and 'lastedge' on the far left.
|
||||
// The right vertex of the base is the destination of 'firstedge', and the
|
||||
// left vertex of the base is the apex of 'lastedge'.
|
||||
//
|
||||
// The challenge now is to find the right sequence of edge flips to
|
||||
// transform the fan into a Delaunay triangulation of the polygon. Each
|
||||
// edge flip effectively removes one triangle from the fan, committing it
|
||||
// to the polygon. The resulting polygon has one fewer edge. If 'doflip'
|
||||
// is set, the final flip will be performed, resulting in a fan of one
|
||||
// (useless?) triangle. If 'doflip' is not set, the final flip is not
|
||||
// performed, resulting in a fan of two triangles, and an unfinished
|
||||
// triangular polygon that is not yet filled out with a single triangle.
|
||||
// On completion of the routine, 'lastedge' is the last remaining triangle,
|
||||
// or the leftmost of the last two.
|
||||
//
|
||||
// Although the flips are performed in the order described above, the
|
||||
// decisions about what flips to perform are made in precisely the reverse
|
||||
// order. The recursive triangulatepolygon() procedure makes a decision,
|
||||
// uses up to two recursive calls to triangulate the "subproblems"
|
||||
// (polygons with fewer edges), and then performs an edge flip.
|
||||
//
|
||||
// The "decision" it makes is which vertex of the polygon should be
|
||||
// connected to the base. This decision is made by testing every possible
|
||||
// vertex. Once the best vertex is found, the two edges that connect this
|
||||
// vertex to the base become the bases for two smaller polygons. These
|
||||
// are triangulated recursively. Unfortunately, this approach can take
|
||||
// O(n^2) time not only in the worst case, but in many common cases. It's
|
||||
// rarely a big deal for vertex deletion, where n is rarely larger than
|
||||
// ten, but it could be a big deal for segment insertion, especially if
|
||||
// there's a lot of long segments that each cut many triangles. I ought to
|
||||
// code a faster algorithm some day.
|
||||
/// This is a conceptually difficult routine. The starting assumption is
|
||||
/// that we have a polygon with n sides. n - 1 of these sides are currently
|
||||
/// represented as edges in the mesh. One side, called the "base", need not
|
||||
/// be.
|
||||
///
|
||||
/// Inside the polygon is a structure I call a "fan", consisting of n - 1
|
||||
/// triangles that share a common origin. For each of these triangles, the
|
||||
/// edge opposite the origin is one of the sides of the polygon. The
|
||||
/// primary edge of each triangle is the edge directed from the origin to
|
||||
/// the destination; note that this is not the same edge that is a side of
|
||||
/// the polygon. 'firstedge' is the primary edge of the first triangle.
|
||||
/// From there, the triangles follow in counterclockwise order about the
|
||||
/// polygon, until 'lastedge', the primary edge of the last triangle.
|
||||
/// 'firstedge' and 'lastedge' are probably connected to other triangles
|
||||
/// beyond the extremes of the fan, but their identity is not important, as
|
||||
/// long as the fan remains connected to them.
|
||||
///
|
||||
/// Imagine the polygon oriented so that its base is at the bottom. This
|
||||
/// puts 'firstedge' on the far right, and 'lastedge' on the far left.
|
||||
/// The right vertex of the base is the destination of 'firstedge', and the
|
||||
/// left vertex of the base is the apex of 'lastedge'.
|
||||
///
|
||||
/// The challenge now is to find the right sequence of edge flips to
|
||||
/// transform the fan into a Delaunay triangulation of the polygon. Each
|
||||
/// edge flip effectively removes one triangle from the fan, committing it
|
||||
/// to the polygon. The resulting polygon has one fewer edge. If 'doflip'
|
||||
/// is set, the final flip will be performed, resulting in a fan of one
|
||||
/// (useless?) triangle. If 'doflip' is not set, the final flip is not
|
||||
/// performed, resulting in a fan of two triangles, and an unfinished
|
||||
/// triangular polygon that is not yet filled out with a single triangle.
|
||||
/// On completion of the routine, 'lastedge' is the last remaining triangle,
|
||||
/// or the leftmost of the last two.
|
||||
///
|
||||
/// Although the flips are performed in the order described above, the
|
||||
/// decisions about what flips to perform are made in precisely the reverse
|
||||
/// order. The recursive triangulatepolygon() procedure makes a decision,
|
||||
/// uses up to two recursive calls to triangulate the "subproblems"
|
||||
/// (polygons with fewer edges), and then performs an edge flip.
|
||||
///
|
||||
/// The "decision" it makes is which vertex of the polygon should be
|
||||
/// connected to the base. This decision is made by testing every possible
|
||||
/// vertex. Once the best vertex is found, the two edges that connect this
|
||||
/// vertex to the base become the bases for two smaller polygons. These
|
||||
/// are triangulated recursively. Unfortunately, this approach can take
|
||||
/// O(n^2) time not only in the worst case, but in many common cases. It's
|
||||
/// rarely a big deal for vertex deletion, where n is rarely larger than
|
||||
/// ten, but it could be a big deal for segment insertion, especially if
|
||||
/// there's a lot of long segments that each cut many triangles. I ought to
|
||||
/// code a faster algorithm some day.
|
||||
/// </remarks>
|
||||
private void TriangulatePolygon(Otri firstedge, Otri lastedge,
|
||||
int edgecount, bool doflip, bool triflaws)
|
||||
|
||||
@@ -14,6 +14,9 @@ namespace TriangleNet
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Mesh validation helper.
|
||||
/// </summary>
|
||||
public static class MeshValidator
|
||||
{
|
||||
private static RobustPredicates predicates = RobustPredicates.Default;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
Mesh mesh;
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// Compute a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
|
||||
@@ -19,10 +19,9 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
Mesh mesh;
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by incrementally inserting vertices.
|
||||
/// Compute a Delaunay triangulation by incrementally inserting vertices.
|
||||
/// </summary>
|
||||
/// <returns>Returns the number of edges on the convex hull of the
|
||||
/// triangulation.</returns>
|
||||
/// <returns></returns>
|
||||
public IMesh Triangulate(IList<Vertex> points, Configuration config)
|
||||
{
|
||||
mesh = new Mesh(config, points);
|
||||
|
||||
@@ -33,6 +33,9 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
double xminextreme; // Nonexistent x value used as a flag in sweepline.
|
||||
List<SplayNode> splaynodes;
|
||||
|
||||
/// <summary>
|
||||
/// Compute a Delaunay triangulation by the sweepline method.
|
||||
/// </summary>
|
||||
public IMesh Triangulate(IList<Vertex> points, Configuration config)
|
||||
{
|
||||
predicates = config.Predicates();
|
||||
|
||||
@@ -351,6 +351,11 @@ namespace TriangleNet.Meshing
|
||||
|
||||
#region DCEL conversion
|
||||
|
||||
/// <summary>
|
||||
/// Convert the triangle mesh topology to DCEL.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <returns></returns>
|
||||
public DcelMesh ToDCEL(Mesh mesh)
|
||||
{
|
||||
var dcel = new DcelMesh();
|
||||
|
||||
@@ -14,9 +14,9 @@ namespace TriangleNet.Meshing.Data
|
||||
/// A (priority) queue for bad triangles.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
// The queue is actually a set of 4096 queues. I use multiple queues to
|
||||
// give priority to smaller angles. I originally implemented a heap, but
|
||||
// the queues are faster by a larger margin than I'd suspected.
|
||||
/// The queue is actually a set of 4096 queues. I use multiple queues to
|
||||
/// give priority to smaller angles. I originally implemented a heap, but
|
||||
/// the queues are faster by a larger margin than I'd suspected.
|
||||
/// </remarks>
|
||||
class BadTriQueue
|
||||
{
|
||||
|
||||
@@ -15,26 +15,45 @@ namespace TriangleNet.Meshing
|
||||
/// <summary>
|
||||
/// Create meshes of point sets or polygons.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If not specified otherwise, the default triangulation algorithm used is <see cref="Dwyer" />.
|
||||
/// </remarks>
|
||||
public class GenericMesher
|
||||
{
|
||||
Configuration config;
|
||||
ITriangulator triangulator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GenericMesher" /> class.
|
||||
/// </summary>
|
||||
public GenericMesher()
|
||||
: this(new Dwyer(), new Configuration())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GenericMesher" /> class.
|
||||
/// </summary>
|
||||
/// <param name="triangulator">The <see cref="ITriangulator" /> algorithm implementation.</param>
|
||||
public GenericMesher(ITriangulator triangulator)
|
||||
: this(triangulator, new Configuration())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GenericMesher" /> class.
|
||||
/// </summary>
|
||||
/// <param name="config">The <see cref="Configuration" />.</param>
|
||||
public GenericMesher(Configuration config)
|
||||
: this(new Dwyer(), config)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GenericMesher" /> class.
|
||||
/// </summary>
|
||||
/// <param name="triangulator">The <see cref="ITriangulator" /> algorithm implementation.</param>
|
||||
/// <param name="config">The <see cref="Configuration" />.</param>
|
||||
public GenericMesher(ITriangulator triangulator, Configuration config)
|
||||
{
|
||||
this.config = config;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace TriangleNet.Meshing
|
||||
/// Refine the mesh.
|
||||
/// </summary>
|
||||
/// <param name="quality">The quality constraints.</param>
|
||||
/// <param name="conforming">
|
||||
/// <param name="delaunay">
|
||||
/// A value indicating, if the refined mesh should be Conforming Delaunay.
|
||||
/// </param>
|
||||
void Refine(QualityOptions quality, bool delaunay);
|
||||
|
||||
@@ -15,6 +15,11 @@ namespace TriangleNet.Meshing.Iterators
|
||||
/// </summary>
|
||||
public class EdgeIterator
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerate all edges of the given mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<Edge> EnumerateEdges(IMesh mesh)
|
||||
{
|
||||
Otri tri = default;
|
||||
@@ -51,7 +56,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerate the edges of the mesh.
|
||||
/// Enumerate all edges of the given mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="skipSegments"></param>
|
||||
|
||||
@@ -22,6 +22,9 @@ namespace TriangleNet.Meshing.Iterators
|
||||
{
|
||||
List<Triangle> region;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegionIterator" /> class.
|
||||
/// </summary>
|
||||
public RegionIterator(Mesh mesh)
|
||||
{
|
||||
this.region = new List<Triangle>();
|
||||
|
||||
@@ -10,10 +10,16 @@ namespace TriangleNet.Meshing.Iterators
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Vertex circulator to enumerate the vertices connected to a mesh vertex.
|
||||
/// </summary>
|
||||
public class VertexCirculator
|
||||
{
|
||||
List<Otri> cache = new List<Otri>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VertexCirculator" /> class.
|
||||
/// </summary>
|
||||
public VertexCirculator(Mesh mesh)
|
||||
{
|
||||
mesh.MakeVertexMap();
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace TriangleNet.Meshing
|
||||
/// Apply quality constraints to a mesh.
|
||||
/// </summary>
|
||||
/// <param name="quality">The quality constraints.</param>
|
||||
/// <param name="delaunay">A value indicating, if the refined mesh should be Conforming Delaunay.</param>
|
||||
/// <param name="delaunay">A value indicating, whether the refined mesh should be Conforming Delaunay.</param>
|
||||
public void Apply(QualityOptions quality, bool delaunay = false)
|
||||
{
|
||||
// Copy quality options
|
||||
|
||||
+257
-259
File diff suppressed because it is too large
Load Diff
@@ -121,22 +121,15 @@ namespace TriangleNet
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RobustPredicates" /> class.
|
||||
/// </summary>
|
||||
public RobustPredicates()
|
||||
{
|
||||
AllocateWorkspace();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check, if the three points appear in counterclockwise order. The result is
|
||||
/// also a rough approximation of twice the signed area of the triangle defined
|
||||
/// by the three points.
|
||||
/// </summary>
|
||||
/// <param name="pa">Point a.</param>
|
||||
/// <param name="pb">Point b.</param>
|
||||
/// <param name="pc">Point c.</param>
|
||||
/// <returns>Return a positive value if the points pa, pb, and pc occur in
|
||||
/// counterclockwise order; a negative value if they occur in clockwise order;
|
||||
/// and zero if they are collinear.</returns>
|
||||
/// <inheritdoc/>
|
||||
public double CounterClockwise(Point pa, Point pb, Point pc)
|
||||
{
|
||||
double detleft, detright, det;
|
||||
@@ -190,18 +183,7 @@ namespace TriangleNet
|
||||
return CounterClockwiseAdapt(pa, pb, pc, detsum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the point pd lies inside the circle passing through pa, pb, and pc. The
|
||||
/// points pa, pb, and pc must be in counterclockwise order, or the sign of the result
|
||||
/// will be reversed.
|
||||
/// </summary>
|
||||
/// <param name="pa">Point a.</param>
|
||||
/// <param name="pb">Point b.</param>
|
||||
/// <param name="pc">Point c.</param>
|
||||
/// <param name="pd">Point d.</param>
|
||||
/// <returns>Return a positive value if the point pd lies inside the circle passing through
|
||||
/// pa, pb, and pc; a negative value if it lies outside; and zero if the four points
|
||||
/// are cocircular.</returns>
|
||||
/// <inheritdoc/>
|
||||
public double InCircle(Point pa, Point pb, Point pc, Point pd)
|
||||
{
|
||||
double adx, bdx, cdx, ady, bdy, cdy;
|
||||
@@ -273,16 +255,7 @@ namespace TriangleNet
|
||||
return InCircle(pa, pb, pc, pd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the circumcenter of a triangle.
|
||||
/// </summary>
|
||||
/// <param name="org">Triangle point.</param>
|
||||
/// <param name="dest">Triangle point.</param>
|
||||
/// <param name="apex">Triangle point.</param>
|
||||
/// <param name="xi">Relative coordinate of new location.</param>
|
||||
/// <param name="eta">Relative coordinate of new location.</param>
|
||||
/// <param name="offconstant">Off-center constant.</param>
|
||||
/// <returns>Coordinates of the circumcenter (or off-center)</returns>
|
||||
/// <inheritdoc/>
|
||||
public Point FindCircumcenter(Point org, Point dest, Point apex,
|
||||
ref double xi, ref double eta, double offconstant)
|
||||
{
|
||||
@@ -384,24 +357,7 @@ namespace TriangleNet
|
||||
return new Point(org.x + dx, org.y + dy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the circumcenter of a triangle.
|
||||
/// </summary>
|
||||
/// <param name="org">Triangle point.</param>
|
||||
/// <param name="dest">Triangle point.</param>
|
||||
/// <param name="apex">Triangle point.</param>
|
||||
/// <param name="xi">Relative coordinate of new location.</param>
|
||||
/// <param name="eta">Relative coordinate of new location.</param>
|
||||
/// <returns>Coordinates of the circumcenter</returns>
|
||||
/// <remarks>
|
||||
/// The result is returned both in terms of x-y coordinates and xi-eta
|
||||
/// (barycentric) coordinates. The xi-eta coordinate system is defined in
|
||||
/// terms of the triangle: the origin of the triangle is the origin of the
|
||||
/// coordinate system; the destination of the triangle is one unit along the
|
||||
/// xi axis; and the apex of the triangle is one unit along the eta axis.
|
||||
/// This procedure also returns the square of the length of the triangle's
|
||||
/// shortest edge.
|
||||
/// </remarks>
|
||||
/// <inheritdoc/>
|
||||
public Point FindCircumcenter(Point org, Point dest, Point apex,
|
||||
ref double xi, ref double eta)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,10 @@ namespace TriangleNet.Tools
|
||||
get { return irow; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AdjacencyMatrix" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
public AdjacencyMatrix(Mesh mesh)
|
||||
{
|
||||
this.N = mesh.vertices.Count;
|
||||
@@ -60,6 +64,12 @@ namespace TriangleNet.Tools
|
||||
SortIndices();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AdjacencyMatrix" /> class.
|
||||
/// </summary>
|
||||
/// <param name="pcol">The column pointers.</param>
|
||||
/// <param name="irow">The row indices.</param>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public AdjacencyMatrix(int[] pcol, int[] irow)
|
||||
{
|
||||
this.N = pcol.Length - 1;
|
||||
@@ -265,6 +275,9 @@ namespace TriangleNet.Tools
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort indices.
|
||||
/// </summary>
|
||||
public void SortIndices()
|
||||
{
|
||||
int k1, k2, n = N;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace TriangleNet.Tools
|
||||
/// <summary>
|
||||
/// Gets the permutation vector for the Reverse Cuthill-McKee numbering.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="matrix">The adjacency matrix.</param>
|
||||
/// <returns>Permutation vector.</returns>
|
||||
public int[] Renumber(AdjacencyMatrix matrix)
|
||||
{
|
||||
@@ -89,11 +89,11 @@ namespace TriangleNet.Tools
|
||||
int iccsze = 0;
|
||||
int level_num = 0;
|
||||
|
||||
/// Index vector for a level structure. The level structure is stored in the
|
||||
/// currently unused spaces in the permutation vector PERM.
|
||||
// Index vector for a level structure. The level structure is stored in the
|
||||
// currently unused spaces in the permutation vector PERM.
|
||||
int[] level_row = new int[n + 1];
|
||||
|
||||
/// Marks variables that have been numbered.
|
||||
// Marks variables that have been numbered.
|
||||
int[] mask = new int[n];
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
@@ -139,8 +139,8 @@ namespace TriangleNet.Tools
|
||||
/// nonzero input mask values are considered by the routine. The nodes numbered by RCM will have
|
||||
/// their mask values set to zero.</param>
|
||||
/// <param name="perm">Output, int PERM(NODE_NUM), the RCM ordering.</param>
|
||||
/// <param name="offset">Internal array offset.</param>
|
||||
/// <param name="iccsze">Output, int ICCSZE, the size of the connected component that has been numbered.</param>
|
||||
/// <param name="node_num">the number of nodes.</param>
|
||||
/// <remarks>
|
||||
/// The connected component is specified by a node ROOT and a mask.
|
||||
/// The numbering starts at the root node.
|
||||
@@ -169,8 +169,8 @@ namespace TriangleNet.Tools
|
||||
// Number of nodes in the mesh.
|
||||
int n = matrix.N;
|
||||
|
||||
/// Workspace, int DEG[NODE_NUM], a temporary vector used to hold
|
||||
/// the degree of the nodes in the section graph specified by mask and root.
|
||||
// Workspace, int DEG[NODE_NUM], a temporary vector used to hold
|
||||
// the degree of the nodes in the section graph specified by mask and root.
|
||||
int[] deg = new int[n];
|
||||
|
||||
// Find the degrees of the nodes in the component specified by MASK and ROOT.
|
||||
@@ -269,7 +269,7 @@ namespace TriangleNet.Tools
|
||||
/// containing the level structure found.</param>
|
||||
/// <param name="level">Output, int LEVEL(NODE_NUM), the level structure array pair
|
||||
/// containing the level structure found.</param>
|
||||
/// <param name="node_num">the number of nodes.</param>
|
||||
/// <param name="offset">Internal array offset.</param>
|
||||
/// <remarks>
|
||||
/// The diameter of a graph is the maximum distance (number of edges)
|
||||
/// between any two nodes of the graph.
|
||||
@@ -409,7 +409,7 @@ namespace TriangleNet.Tools
|
||||
/// in level 1. The neighbors of ROOT are in level 2, and so on.</param>
|
||||
/// <param name="level_row">Output, int LEVEL_ROW[NODE_NUM+1], the rooted level structure.</param>
|
||||
/// <param name="level">Output, int LEVEL[NODE_NUM], the rooted level structure.</param>
|
||||
/// <param name="node_num">the number of nodes.</param>
|
||||
/// <param name="offset">Internal array offset.</param>
|
||||
/// <remarks>
|
||||
/// Only nodes for which MASK is nonzero will be considered.
|
||||
///
|
||||
@@ -502,7 +502,7 @@ namespace TriangleNet.Tools
|
||||
/// <param name="iccsze">Output, int ICCSIZE, the number of nodes in the connected component.</param>
|
||||
/// <param name="ls">Output, int LS[NODE_NUM], stores in entries 1 through ICCSIZE the nodes in the
|
||||
/// connected component, starting with ROOT, and proceeding by levels.</param>
|
||||
/// <param name="node_num">the number of nodes.</param>
|
||||
/// <param name="offset">Internal array offset.</param>
|
||||
/// <remarks>
|
||||
/// The connected component is specified by MASK and ROOT.
|
||||
/// Nodes for which MASK is zero are ignored.
|
||||
@@ -621,7 +621,6 @@ namespace TriangleNet.Tools
|
||||
/// <summary>
|
||||
/// Produces the inverse of a given permutation.
|
||||
/// </summary>
|
||||
/// <param name="n">Number of items permuted.</param>
|
||||
/// <param name="perm">PERM[N], a permutation.</param>
|
||||
/// <returns>The inverse permutation.</returns>
|
||||
int[] PermInverse(int[] perm)
|
||||
@@ -642,6 +641,7 @@ namespace TriangleNet.Tools
|
||||
/// Reverses the elements of an integer vector.
|
||||
/// </summary>
|
||||
/// <param name="size">number of entries in the array.</param>
|
||||
/// <param name="offset">Internal array offset.</param>
|
||||
/// <param name="a">the array to be reversed.</param>
|
||||
/// <example>
|
||||
/// Input:
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace TriangleNet.Tools
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Interpolation helper.
|
||||
/// </summary>
|
||||
public static class Interpolation
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace TriangleNet.Tools
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Segment intersection helper.
|
||||
/// </summary>
|
||||
public static class IntersectionHelper
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -10,6 +10,9 @@ namespace TriangleNet.Tools
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Polygon validation helper.
|
||||
/// </summary>
|
||||
public static class PolygonValidator
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -59,6 +59,9 @@ namespace TriangleNet.Tools
|
||||
|
||||
Mesh mesh;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QualityMeasure" /> class.
|
||||
/// </summary>
|
||||
public QualityMeasure()
|
||||
{
|
||||
areaMeasure = new AreaMeasure();
|
||||
@@ -158,6 +161,9 @@ namespace TriangleNet.Tools
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Update all quality measures.
|
||||
/// </summary>
|
||||
public void Update(Mesh mesh)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
|
||||
@@ -22,12 +22,20 @@ namespace TriangleNet.Tools
|
||||
/// Number of incircle tests performed.
|
||||
/// </summary>
|
||||
public static long InCircleCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of adaptive incircle tests performed.
|
||||
/// </summary>
|
||||
public static long InCircleAdaptCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of counterclockwise tests performed.
|
||||
/// </summary>
|
||||
public static long CounterClockwiseCount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Number of adaptive counterclockwise tests performed.
|
||||
/// </summary>
|
||||
public static long CounterClockwiseAdaptCount = 0;
|
||||
|
||||
/// <summary>
|
||||
@@ -201,6 +209,8 @@ namespace TriangleNet.Tools
|
||||
/// Update statistics about the quality of the mesh.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="sampleDegrees">Number of degrees to sample
|
||||
/// (currently fixed to 60 = sample every 3 degrees).</param>
|
||||
public void Update(Mesh mesh, int sampleDegrees)
|
||||
{
|
||||
Point[] p = new Point[3];
|
||||
|
||||
@@ -50,6 +50,12 @@ namespace TriangleNet.Tools
|
||||
root.CreateSubRegion(++currentDepth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Query the quadtree a given point.
|
||||
/// </summary>
|
||||
/// <param name="x">The x coordinate.</param>
|
||||
/// <param name="y">The y coordinate.</param>
|
||||
/// <returns></returns>
|
||||
public ITriangle Query(double x, double y)
|
||||
{
|
||||
var point = new Point(x, y);
|
||||
|
||||
@@ -9,10 +9,18 @@ namespace TriangleNet.Topology.DCEL
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// DCEL mesh.
|
||||
/// </summary>
|
||||
public class DcelMesh
|
||||
{
|
||||
/// <summary>List of vertices.</summary>
|
||||
protected List<Vertex> vertices;
|
||||
|
||||
/// <summary>List of half-edges.</summary>
|
||||
protected List<HalfEdge> edges;
|
||||
|
||||
/// <summary>List of faces.</summary>
|
||||
protected List<Face> faces;
|
||||
|
||||
/// <summary>
|
||||
@@ -24,7 +32,7 @@ namespace TriangleNet.Topology.DCEL
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="" /> class.
|
||||
/// Initializes a new instance of the <see cref="DcelMesh" /> class.
|
||||
/// </summary>
|
||||
/// <param name="initialize">If false, lists will not be initialized.</param>
|
||||
protected DcelMesh(bool initialize)
|
||||
|
||||
@@ -10,12 +10,15 @@ namespace TriangleNet.Topology.DCEL
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// A face of DCEL mesh.
|
||||
/// A face of the DCEL datastructure.
|
||||
/// </summary>
|
||||
public class Face
|
||||
{
|
||||
#region Static initialization of "Outer Space" face
|
||||
|
||||
/// <summary>
|
||||
/// A face representing "outer space".
|
||||
/// </summary>
|
||||
public static readonly Face Empty;
|
||||
|
||||
static Face()
|
||||
@@ -105,6 +108,7 @@ namespace TriangleNet.Topology.DCEL
|
||||
} while (edge.ID != first);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("F-ID {0}", id);
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
namespace TriangleNet.Topology.DCEL
|
||||
{
|
||||
/// <summary>
|
||||
/// A half-edge of the DCEL datastructure.
|
||||
/// </summary>
|
||||
public class HalfEdge
|
||||
{
|
||||
internal int id;
|
||||
@@ -25,6 +28,9 @@ namespace TriangleNet.Topology.DCEL
|
||||
set { id = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boundary marker.
|
||||
/// </summary>
|
||||
public int Boundary
|
||||
{
|
||||
get { return mark; }
|
||||
@@ -93,6 +99,7 @@ namespace TriangleNet.Topology.DCEL
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("HE-ID {0} (Origin = VID-{1})", id, origin.id);
|
||||
|
||||
@@ -8,6 +8,9 @@ namespace TriangleNet.Topology.DCEL
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// A vertex of the DCEL datastructure.
|
||||
/// </summary>
|
||||
public class Vertex : TriangleNet.Geometry.Point
|
||||
{
|
||||
internal HalfEdge leaving;
|
||||
@@ -60,6 +63,7 @@ namespace TriangleNet.Topology.DCEL
|
||||
} while (edge.ID != first);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("V-ID {0}", base.id);
|
||||
|
||||
@@ -23,11 +23,12 @@ namespace TriangleNet.Topology
|
||||
internal SubSegment seg;
|
||||
internal int orient; // Ranges from 0 to 1.
|
||||
|
||||
public SubSegment Segment
|
||||
{
|
||||
get { return seg; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the subsegment.
|
||||
/// </summary>
|
||||
public SubSegment Segment => seg;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
if (seg == null)
|
||||
|
||||
@@ -23,12 +23,16 @@ namespace TriangleNet.Topology
|
||||
internal Triangle tri;
|
||||
internal int orient; // Ranges from 0 to 2.
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the triangle.
|
||||
/// </summary>
|
||||
public Triangle Triangle
|
||||
{
|
||||
get { return tri; }
|
||||
set { tri = value; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
if (tri == null)
|
||||
@@ -77,6 +81,7 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Find the abutting triangle; same edge. [sym(abc) -> ba*]
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that the edge direction is necessarily reversed, because the handle specified
|
||||
/// by an oriented triangle is directed counterclockwise around the triangle.
|
||||
/// </remarks>
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace TriangleNet.Topology
|
||||
internal Otri[] triangles;
|
||||
internal int boundary;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubSegment" /> class.
|
||||
/// </summary>
|
||||
public SubSegment()
|
||||
{
|
||||
// Four NULL vertices.
|
||||
@@ -83,11 +86,13 @@ namespace TriangleNet.Topology
|
||||
return triangles[index].tri.hash == Mesh.DUMMY ? null : triangles[index].tri;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("SID {0}", hash);
|
||||
|
||||
@@ -77,11 +77,18 @@ namespace TriangleNet.Topology
|
||||
/// <summary>
|
||||
/// Gets the specified corners vertex.
|
||||
/// </summary>
|
||||
/// <param name="index">The corner index (0, 1 or 2).</param>
|
||||
/// <returns></returns>
|
||||
public Vertex GetVertex(int index)
|
||||
{
|
||||
return this.vertices[index]; // TODO: Check range?
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified corners vertex id.
|
||||
/// </summary>
|
||||
/// <param name="index">The corner index (0, 1 or 2).</param>
|
||||
/// <returns></returns>
|
||||
public int GetVertexID(int index)
|
||||
{
|
||||
return this.vertices[index].id;
|
||||
@@ -115,11 +122,13 @@ namespace TriangleNet.Topology
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("TID {0}", hash);
|
||||
|
||||
@@ -32,12 +32,21 @@ namespace TriangleNet
|
||||
// Pointer to a recently visited triangle. Improves point location if
|
||||
// proximate vertices are inserted sequentially.
|
||||
internal Otri recenttri;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TriangleLocator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
public TriangleLocator(Mesh mesh)
|
||||
: this(mesh, RobustPredicates.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TriangleLocator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="predicates">The predicates.</param>
|
||||
public TriangleLocator(Mesh mesh, IPredicates predicates)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
@@ -55,7 +64,8 @@ namespace TriangleNet
|
||||
otri.Copy(ref recenttri);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
// TODO: Remove unused method.
|
||||
internal void Reset()
|
||||
{
|
||||
sampler.Reset();
|
||||
recenttri.tri = null; // No triangle has been visited yet.
|
||||
|
||||
@@ -10,6 +10,9 @@ namespace TriangleNet
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Pool datastructure storing triangles of a <see cref="Mesh" />.
|
||||
/// </summary>
|
||||
public class TrianglePool : ICollection<Triangle>
|
||||
{
|
||||
// Determines the size of each block in the pool.
|
||||
@@ -32,6 +35,9 @@ namespace TriangleNet
|
||||
/// </summary>
|
||||
public int Capacity => size;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TrianglePool" /> class.
|
||||
/// </summary>
|
||||
public TrianglePool()
|
||||
{
|
||||
size = 0;
|
||||
@@ -97,6 +103,9 @@ namespace TriangleNet
|
||||
return triangle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release triangle (making it a free triangle).
|
||||
/// </summary>
|
||||
public void Release(Triangle triangle)
|
||||
{
|
||||
stack.Push(triangle);
|
||||
@@ -172,11 +181,17 @@ namespace TriangleNet
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Not supported for this <see cref="ICollection{Triangle}" />.
|
||||
/// </summary>
|
||||
public void Add(Triangle item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear the pool.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
stack.Clear();
|
||||
@@ -199,6 +214,7 @@ namespace TriangleNet
|
||||
size = count = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(Triangle item)
|
||||
{
|
||||
int i = item.hash;
|
||||
@@ -211,6 +227,7 @@ namespace TriangleNet
|
||||
return pool[i / BLOCKSIZE][i % BLOCKSIZE].hash >= 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(Triangle[] array, int index)
|
||||
{
|
||||
var enumerator = GetEnumerator();
|
||||
@@ -222,21 +239,19 @@ namespace TriangleNet
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return count - stack.Count; }
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public int Count => count - stack.Count;
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(Triangle item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<Triangle> GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
|
||||
@@ -12,15 +12,28 @@ namespace TriangleNet.Voronoi
|
||||
|
||||
using TVertex = TriangleNet.Geometry.Vertex;
|
||||
|
||||
/// <summary>
|
||||
/// Computing the bounded Voronoi diagram of a constrained and conforming Delaunay triangulation.
|
||||
/// </summary>
|
||||
public class BoundedVoronoi : VoronoiBase
|
||||
{
|
||||
int offset;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StandardVoronoi" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
public BoundedVoronoi(Mesh mesh)
|
||||
: this(mesh, new DefaultVoronoiFactory(), RobustPredicates.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StandardVoronoi" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="predicates"></param>
|
||||
public BoundedVoronoi(Mesh mesh, IVoronoiFactory factory, IPredicates predicates)
|
||||
: base(mesh, factory, predicates, true)
|
||||
{
|
||||
|
||||
@@ -9,24 +9,29 @@ namespace TriangleNet.Voronoi
|
||||
/// </summary>
|
||||
public class DefaultVoronoiFactory : IVoronoiFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Initialize(int vertexCount, int edgeCount, int faceCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Vertex CreateVertex(double x, double y)
|
||||
{
|
||||
return new Vertex(x, y);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public HalfEdge CreateHalfEdge(Vertex origin, Face face)
|
||||
{
|
||||
return new HalfEdge(origin, face);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Face CreateFace(Geometry.Vertex vertex)
|
||||
{
|
||||
return new Face(vertex);
|
||||
|
||||
@@ -3,16 +3,45 @@ namespace TriangleNet.Voronoi
|
||||
{
|
||||
using TriangleNet.Topology.DCEL;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for Voronoi DCEL datastructure.
|
||||
/// </summary>
|
||||
public interface IVoronoiFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Initialize object pool.
|
||||
/// </summary>
|
||||
/// <param name="vertexCount"></param>
|
||||
/// <param name="edgeCount"></param>
|
||||
/// <param name="faceCount"></param>
|
||||
void Initialize(int vertexCount, int edgeCount, int faceCount);
|
||||
|
||||
/// <summary>
|
||||
/// Reset object pool.
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="Vertex" />.
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
Vertex CreateVertex(double x, double y);
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="HalfEdge" />.
|
||||
/// </summary>
|
||||
/// <param name="origin"></param>
|
||||
/// <param name="face"></param>
|
||||
/// <returns></returns>
|
||||
HalfEdge CreateHalfEdge(Vertex origin, Face face);
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="Face" />.
|
||||
/// </summary>
|
||||
/// <param name="vertex"></param>
|
||||
/// <returns></returns>
|
||||
Face CreateFace(Geometry.Vertex vertex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,18 +11,37 @@ namespace TriangleNet.Voronoi
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology.DCEL;
|
||||
|
||||
/// <summary>
|
||||
/// Computing the standard Voronoi diagram of a Delaunay triangulation.
|
||||
/// </summary>
|
||||
public class StandardVoronoi : VoronoiBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StandardVoronoi" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
public StandardVoronoi(Mesh mesh)
|
||||
: this(mesh, mesh.bounds, new DefaultVoronoiFactory(), RobustPredicates.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StandardVoronoi" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="box">The bounding box used to clip infinite Voronoi edges.</param>
|
||||
public StandardVoronoi(Mesh mesh, Rectangle box)
|
||||
: this(mesh, box, new DefaultVoronoiFactory(), RobustPredicates.Default)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StandardVoronoi" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh.</param>
|
||||
/// <param name="box">The bounding box used for clipping (not implemented.)</param>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="predicates"></param>
|
||||
public StandardVoronoi(Mesh mesh, Rectangle box, IVoronoiFactory factory, IPredicates predicates)
|
||||
: base(mesh, factory, predicates, true)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user