using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Numerics; namespace NaturalNeighbor { using Internal; /// /// Performs planar subdivision /// public class SubDivision2d { /// /// Constructs a new subdivision including the specified points /// /// XY coordinates /// Margin for the bounding box public SubDivision2d(Vector2[] points, double margin) { Bounds bounds = Utils.CalculateBounds(points, (float)margin, null, null); _impl = new SubDiv2D_Mutable(bounds); _searchContext = new SearchContext(); InsertRange(points); } internal int NumberOfSamples { get; private set; } private SearchContext _searchContext; /// /// Constructs a new subdivision including the specified points /// /// XY coordinates public SubDivision2d(Vector2[] points):this(points, 0.0) { } /// /// Constructs an empty subdivision with the specified boundaries /// /// the bottom left corner /// the top right corner public SubDivision2d(Vector2 min, Vector2 max) { _impl = new SubDiv2D_Mutable(new Bounds(min, max)); _searchContext = new SearchContext(); } internal SubDiv2D_Mutable _impl; /// /// The bottom left corner of the bounding box /// public Vector2 MinValue => _impl.Bounds.MinValue; /// /// The top right corner of the bounding box /// public Vector2 MaxValue => _impl.Bounds.MaxValue; /// /// Inserts a node into Delaunay graph /// /// xy coordinate /// node Id public NodeId Insert(Vector2 point) { return _impl.Insert(point, _searchContext); } /// /// Inserts a node into Delaunay graph /// /// x coordinate /// y coordinate /// node Id public NodeId Insert(float x, float y) { var result = _impl.Insert(new Vector2(x, y), _searchContext); if (_searchContext.Vertex == 0) { NumberOfSamples++; } return result; } /// /// Inserts a sequence of nodes into Delaunay graph /// /// xy coordinates public void InsertRange(IEnumerable points) { foreach (var p in points) { _impl.Insert(p, _searchContext); if (_searchContext.Vertex == 0) { NumberOfSamples++; } } } /// /// Clears the graph retaining the bounding box /// public void Clear() { var bounds = _impl.Bounds; _impl = new SubDiv2D_Mutable(bounds); _searchContext.Clear(); NumberOfSamples = 0; } /// /// Reads delaunay triangles in the current node set /// /// list of triangles public IEnumerable GetDelaunayTriangles() { return _impl.GetTriangles(); } /// /// Reads all edges of graph /// /// A list of endpoints forming an edge public IEnumerable<(Vector2, Vector2)> GetEdges() { return _impl.GetEdges(); } /// /// Finds a node closest to the specified location /// /// Location xy coordinate /// Closest node location /// Found node Id, null if point is out of bounds public NodeId? FindNearest(Vector2 point, out Vector2 result) { return _impl.FindNearest(point, _searchContext, out result); } /// /// Finds a node closest to the specified location /// /// Location X coordinate /// Location Y coordinate /// Closest node location /// Id of the found node or null if point is out of bounds public NodeId? FindNearest(float x, float y, out Vector2 result) { return _impl.FindNearest(new Vector2(x, y), _searchContext, out result); } /// /// Reads all voronoi facets /// /// A list of facets public IEnumerable GetVoronoiFacets() { return _impl.GetVoronoiFacets(); } /// /// Reads specific voronoi facets /// /// node ids /// A list of requested facets public IEnumerable GetVoronoiFacets(IReadOnlyList vertices) { return _impl.GetVoronoiFacets(vertices); } } }