Add triangle object pool
git-svn-id: https://triangle.svn.codeplex.com/svn@77753 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -86,18 +86,10 @@ namespace MeshExplorer
|
||||
control.Size = new Size(size.Width, size.Height);
|
||||
control.TabIndex = 0;
|
||||
control.Text = "renderControl1";
|
||||
control.MouseClick += new MouseEventHandler(RenderControl_MouseClick);
|
||||
|
||||
this.splitContainer1.ResumeLayout();
|
||||
}
|
||||
|
||||
private void RenderControl_MouseClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
var pt = e.Location;
|
||||
|
||||
renderManager.Click(((float)pt.X), ((float)pt.Y), e.Button);
|
||||
}
|
||||
|
||||
private void Form1_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
switch (e.KeyCode)
|
||||
@@ -186,17 +178,7 @@ namespace MeshExplorer
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
{
|
||||
var container = this.splitContainer1.Panel2.ClientRectangle;
|
||||
|
||||
System.Drawing.Point pt = e.Location;
|
||||
pt.Offset(-splitContainer1.SplitterDistance, 0);
|
||||
|
||||
if (container.Contains(pt))
|
||||
{
|
||||
renderManager.Zoom(((float)pt.X) / container.Width,
|
||||
((float)pt.Y) / container.Height, e.Delta);
|
||||
}
|
||||
base.OnMouseWheel(e);
|
||||
// TODO: focus render control
|
||||
}
|
||||
|
||||
#region Resize event handler
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace TriangleNet.Rendering.GDI
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
@@ -36,6 +37,7 @@ namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
//this.SetStyle(ControlStyles.UserPaint, true);
|
||||
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
|
||||
//this.SetStyle(ControlStyles.Selectable, true);
|
||||
this.SetStyle(ControlStyles.ResizeRedraw, true);
|
||||
|
||||
//renderColors = ColorManager.Default();
|
||||
@@ -74,60 +76,14 @@ namespace TriangleNet.Rendering.GDI
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void HandleMouseClick(float x, float y, MouseButtons button)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (button == MouseButtons.Middle)
|
||||
{
|
||||
zoom.Reset();
|
||||
this.Render();
|
||||
}
|
||||
else if (button == MouseButtons.Left)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
var nfi = System.Globalization.CultureInfo.InvariantCulture.NumberFormat;
|
||||
|
||||
PointF c = new PointF(x / this.Width, y / this.Height);
|
||||
zoom.ScreenToWorld(ref c);
|
||||
coordinate = String.Format(nfi, "X:{0} Y:{1}", c.X, c.Y);
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom to the given location.
|
||||
/// </summary>
|
||||
/// <param name="location">The zoom focus.</param>
|
||||
/// <param name="delta">Indicates whether to zoom in or out.</param>
|
||||
public void HandleMouseWheel(float x, float y, int delta)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (zoom.Zoom(delta, x, y))
|
||||
{
|
||||
// Redraw
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update graphics buffer and zoom after a resize.
|
||||
/// </summary>
|
||||
public void HandleResize()
|
||||
{
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
var bounds = this.Renderer.Context.Bounds;
|
||||
|
||||
zoom.Initialize(this.ClientRectangle, bounds);
|
||||
zoom.Resize(this.ClientRectangle);
|
||||
InitializeBuffer();
|
||||
}
|
||||
|
||||
@@ -215,6 +171,82 @@ namespace TriangleNet.Rendering.GDI
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(MouseEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (zoom.Zoom(e.Delta, (float)e.X / Width, (float)e.Y / Height))
|
||||
{
|
||||
// Redraw
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e)
|
||||
{
|
||||
// We need to manually set the focus to get proper handling of
|
||||
// the KeyUp and MouseWheel events.
|
||||
this.Focus();
|
||||
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (e.Button == MouseButtons.Middle)
|
||||
{
|
||||
zoom.Reset();
|
||||
this.Render();
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
PointF c = new PointF((float)e.X / Width, (float)e.Y / Height);
|
||||
zoom.ScreenToWorld(ref c);
|
||||
coordinate = String.Format(NumberFormatInfo.InvariantInfo,
|
||||
"X:{0} Y:{1}", c.X, c.Y);
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKeyUp(KeyEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
bool redraw = false;
|
||||
|
||||
if (e.KeyCode == Keys.Up)
|
||||
{
|
||||
redraw = zoom.Translate(0, 1);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Down)
|
||||
{
|
||||
redraw = zoom.Translate(0, -1);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Left)
|
||||
{
|
||||
redraw = zoom.Translate(-1, 0);
|
||||
}
|
||||
else if (e.KeyCode == Keys.Right)
|
||||
{
|
||||
redraw = zoom.Translate(1, 0);
|
||||
}
|
||||
|
||||
if (redraw)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ namespace TriangleNet.Rendering
|
||||
void Initialize();
|
||||
void Refresh();
|
||||
|
||||
void HandleMouseClick(float x, float y, MouseButtons button);
|
||||
void HandleMouseWheel(float x, float y, int delta);
|
||||
void HandleResize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace TriangleNet.Rendering
|
||||
// so inverY must be set to true.
|
||||
bool invertY = false;
|
||||
|
||||
int maxZoomLevel = 50;
|
||||
int maxZoomLevel = 100;
|
||||
|
||||
public Projection(Rectangle screen, bool invertY = true)
|
||||
{
|
||||
@@ -62,15 +62,12 @@ namespace TriangleNet.Rendering
|
||||
this.invertY = invertY;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inititialize the projection.
|
||||
/// </summary>
|
||||
/// <param name="world">The world that should be transformed to screen coordinates.</param>
|
||||
public void Initialize(BoundingBox world)
|
||||
{
|
||||
Initialize(this.screen, world);
|
||||
}
|
||||
|
||||
public void Initialize(Rectangle screen, BoundingBox world)
|
||||
{
|
||||
this.screen = screen;
|
||||
|
||||
this.Level = 1;
|
||||
|
||||
// Add a margin so there's some space around the border
|
||||
@@ -101,6 +98,66 @@ namespace TriangleNet.Rendering
|
||||
this.world = this.Viewport;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle resize of the screen.
|
||||
/// </summary>
|
||||
/// <param name="newScreen">The new screen dimensions.</param>
|
||||
public void Resize(Rectangle newScreen)
|
||||
{
|
||||
// The viewport has to be updated, but we want to keep
|
||||
// the scaling and the center.
|
||||
|
||||
// Get the screen scaling.
|
||||
float scaleX = newScreen.Width / (float)screen.Width;
|
||||
float scaleY = newScreen.Height / (float)screen.Height;
|
||||
|
||||
this.screen = newScreen;
|
||||
|
||||
var view = this.Viewport;
|
||||
|
||||
// Center of the viewport
|
||||
float centerX = (view.Left + view.Right) / 2;
|
||||
float centerY = (view.Bottom + view.Top) / 2;
|
||||
|
||||
// The new viewport dimensions.
|
||||
float width = view.Width * scaleX;
|
||||
float height = view.Height * scaleY;
|
||||
|
||||
this.Viewport = new RectangleF(
|
||||
centerX - width / 2,
|
||||
centerY - height / 2,
|
||||
width, height);
|
||||
|
||||
// Do the same for the world:
|
||||
centerX = (world.Left + world.Right) / 2;
|
||||
centerY = (world.Bottom + world.Top) / 2;
|
||||
|
||||
width = world.Width * scaleX;
|
||||
height = world.Height * scaleY;
|
||||
|
||||
this.world = new RectangleF(
|
||||
centerX - width / 2,
|
||||
centerY - height / 2,
|
||||
width, height);
|
||||
}
|
||||
|
||||
public bool Translate(int dx, int dy)
|
||||
{
|
||||
if (Level == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var view = this.Viewport;
|
||||
|
||||
float x = view.X + dx * view.Width / 4;
|
||||
float y = view.Y + dy * view.Height / 4;
|
||||
|
||||
this.Viewport = new RectangleF(x, y, view.Width, view.Height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom in or out of the viewport.
|
||||
/// </summary>
|
||||
|
||||
@@ -77,16 +77,6 @@ namespace TriangleNet.Rendering
|
||||
control.HandleResize();
|
||||
}
|
||||
|
||||
public void Click(float x, float y, MouseButtons button)
|
||||
{
|
||||
control.HandleMouseClick(x, y, button);
|
||||
}
|
||||
|
||||
public void Zoom(float x, float y, int delta)
|
||||
{
|
||||
control.HandleMouseWheel(x, y, delta);
|
||||
}
|
||||
|
||||
public void Enable(int layer, bool enabled)
|
||||
{
|
||||
context.Enable(layer, enabled);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Configuration.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Meshing.Algorithm;
|
||||
|
||||
/// <summary>
|
||||
/// Configure advanced aspects of the library.
|
||||
/// </summary>
|
||||
public class Configuration
|
||||
{
|
||||
public Configuration()
|
||||
: this(() => RobustPredicates.Default, () => new TrianglePool())
|
||||
{
|
||||
}
|
||||
|
||||
public Configuration(Func<IPredicates> predicates)
|
||||
: this(predicates, () => new TrianglePool())
|
||||
{
|
||||
}
|
||||
|
||||
public Configuration(Func<IPredicates> predicates, Func<TrianglePool> trianglePool)
|
||||
{
|
||||
Predicates = predicates;
|
||||
TrianglePool = trianglePool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the factory method for the <see cref="IPredicates"/> implementation.
|
||||
/// </summary>
|
||||
public Func<IPredicates> Predicates { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the factory method for the <see cref="TrianglePool"/>.
|
||||
/// </summary>
|
||||
public Func<TrianglePool> TrianglePool { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace TriangleNet.Geometry
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
public class Contour
|
||||
{
|
||||
int marker;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Meshing;
|
||||
|
||||
public static class ExtensionMethods
|
||||
@@ -56,5 +57,87 @@ namespace TriangleNet.Geometry
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Rectangle extensions
|
||||
|
||||
#endregion
|
||||
|
||||
#region ITriangle extensions
|
||||
|
||||
/// <summary>
|
||||
/// Test whether a given point lies inside a triangle or not.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
{
|
||||
return Contains(triangle, p.X, p.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test whether a given point lies inside a triangle or not.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public static bool Contains(this ITriangle triangle, double x, double y)
|
||||
{
|
||||
var t0 = triangle.GetVertex(0);
|
||||
var t1 = triangle.GetVertex(1);
|
||||
var t2 = triangle.GetVertex(2);
|
||||
|
||||
// TODO: no need to create new Point instances here
|
||||
Point d0 = new Point(t1.X - t0.X, t1.Y - t0.Y);
|
||||
Point d1 = new Point(t2.X - t0.X, t2.Y - t0.Y);
|
||||
Point d2 = new Point(x - t0.X, y - t0.Y);
|
||||
|
||||
// crossproduct of (0, 0, 1) and d0
|
||||
Point c0 = new Point(-d0.Y, d0.X);
|
||||
|
||||
// crossproduct of (0, 0, 1) and d1
|
||||
Point c1 = new Point(-d1.Y, d1.X);
|
||||
|
||||
// Linear combination d2 = s * d0 + v * d1.
|
||||
//
|
||||
// Multiply both sides of the equation with c0 and c1
|
||||
// and solve for s and v respectively
|
||||
//
|
||||
// s = d2 * c1 / d0 * c1
|
||||
// v = d2 * c0 / d1 * c0
|
||||
|
||||
double s = DotProduct(d2, c1) / DotProduct(d0, c1);
|
||||
double v = DotProduct(d2, c0) / DotProduct(d1, c0);
|
||||
|
||||
if (s >= 0 && v >= 0 && ((s + v) <= 1))
|
||||
{
|
||||
// Point is inside or on the edge of this triangle.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Rectangle Bounds(this ITriangle triangle)
|
||||
{
|
||||
var bounds = new Rectangle();
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
bounds.Expand(triangle.GetVertex(i));
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper methods
|
||||
|
||||
internal static double DotProduct(Point p, Point q)
|
||||
{
|
||||
return p.X * q.X + p.Y * q.Y;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,21 +121,12 @@ namespace TriangleNet.Geometry
|
||||
this.points.Add(vertex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a segment to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="segment">The segment to insert.</param>
|
||||
public void Add(ISegment segment)
|
||||
{
|
||||
this.segments.Add(segment);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a segment to the polygon.
|
||||
/// </summary>
|
||||
/// <param name="segment">The segment to insert.</param>
|
||||
/// <param name="insert">If true, both endpoints will be added to the points list.</param>
|
||||
public void Add(ISegment segment, bool insert)
|
||||
public void Add(ISegment segment, bool insert = false)
|
||||
{
|
||||
this.segments.Add(segment);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace TriangleNet.Geometry
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// A simple bounding box class.
|
||||
/// A simple rectangle class.
|
||||
/// </summary>
|
||||
public class Rectangle
|
||||
{
|
||||
@@ -79,7 +79,7 @@ namespace TriangleNet.Geometry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width of the bounding box.
|
||||
/// Gets the width of the rectangle.
|
||||
/// </summary>
|
||||
public double Width
|
||||
{
|
||||
@@ -87,7 +87,7 @@ namespace TriangleNet.Geometry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the bounding box.
|
||||
/// Gets the height of the rectangle.
|
||||
/// </summary>
|
||||
public double Height
|
||||
{
|
||||
@@ -144,20 +144,31 @@ namespace TriangleNet.Geometry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if given point is inside bounding box.
|
||||
/// Check if given point is inside rectangle.
|
||||
/// </summary>
|
||||
/// <param name="pt">Point to check.</param>
|
||||
/// <returns>Return true, if bounding box contains given point.</returns>
|
||||
public bool Contains(Point pt)
|
||||
/// <param name="x">Point to check.</param>
|
||||
/// <param name="y">Point to check.</param>
|
||||
/// <returns>Return true, if rectangle contains given point.</returns>
|
||||
public bool Contains(double x, double y)
|
||||
{
|
||||
return ((pt.x >= xmin) && (pt.x <= xmax) && (pt.y >= ymin) && (pt.y <= ymax));
|
||||
return ((x >= xmin) && (x <= xmax) && (y >= ymin) && (y <= ymax));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if given rectangle is inside bounding box.
|
||||
/// Check if given point is inside rectangle.
|
||||
/// </summary>
|
||||
/// <param name="pt">Point to check.</param>
|
||||
/// <returns>Return true, if rectangle contains given point.</returns>
|
||||
public bool Contains(Point pt)
|
||||
{
|
||||
return Contains(pt.x, pt.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if this rectangle contains other rectangle.
|
||||
/// </summary>
|
||||
/// <param name="other">Rectangle to check.</param>
|
||||
/// <returns>Return true, if bounding box contains given rectangle.</returns>
|
||||
/// <returns>Return true, if this rectangle contains given rectangle.</returns>
|
||||
public bool Contains(Rectangle other)
|
||||
{
|
||||
return (xmin <= other.Left && other.Right <= xmax
|
||||
@@ -165,10 +176,10 @@ namespace TriangleNet.Geometry
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if given rectangle intersects bounding box.
|
||||
/// Check if this rectangle intersects other rectangle.
|
||||
/// </summary>
|
||||
/// <param name="other">Rectangle to check.</param>
|
||||
/// <returns>Return true, if given rectangle intersects bounding box.</returns>
|
||||
/// <returns>Return true, if given rectangle intersects this rectangle.</returns>
|
||||
public bool Intersects(Rectangle other)
|
||||
{
|
||||
return (other.Left < xmax && xmin < other.Right
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace TriangleNet.Geometry
|
||||
internal double[] attributes;
|
||||
#endif
|
||||
internal VertexType type;
|
||||
internal Otri tri;
|
||||
internal Otri tri; // TODO: change from Otri to Triangle
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Vertex" /> class.
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace TriangleNet.IO
|
||||
foreach (var v in mesh.vertices.Values)
|
||||
{
|
||||
// Vertex number, x and y coordinates and marker.
|
||||
stream.WriteLine("{0} {1} {2} {3}", v.hash, v.x.ToString(nfi), v.y.ToString(nfi), v.label);
|
||||
stream.WriteLine("{0} {1} {2} {3}", v.id, v.x.ToString(nfi), v.y.ToString(nfi), v.label);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -184,7 +184,7 @@ namespace TriangleNet.IO
|
||||
p2 = subseg.Dest();
|
||||
|
||||
// Segment number, indices of its two endpoints, and marker.
|
||||
stream.WriteLine("{0} {1} {2} {3}", subseg.seg.hash, p1.hash, p2.hash, subseg.seg.boundary);
|
||||
stream.WriteLine("{0} {1} {2} {3}", subseg.seg.hash, p1.id, p2.id, subseg.seg.boundary);
|
||||
}
|
||||
|
||||
Otri tri = default(Otri), trisym = default(Otri);
|
||||
@@ -195,7 +195,7 @@ namespace TriangleNet.IO
|
||||
// Number of triangles.
|
||||
stream.WriteLine("{0}", mesh.triangles.Count);
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
@@ -203,9 +203,9 @@ namespace TriangleNet.IO
|
||||
p2 = tri.Dest();
|
||||
p3 = tri.Apex();
|
||||
|
||||
h1 = (p1 == null) ? -1 : p1.hash;
|
||||
h2 = (p2 == null) ? -1 : p2.hash;
|
||||
h3 = (p3 == null) ? -1 : p3.hash;
|
||||
h1 = (p1 == null) ? -1 : p1.id;
|
||||
h2 = (p2 == null) ? -1 : p2.id;
|
||||
h3 = (p3 == null) ? -1 : p3.id;
|
||||
|
||||
// Triangle number, indices for three vertices.
|
||||
stream.Write("{0} {1} {2} {3}", tri.tri.hash, h1, h2, h3);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace TriangleNet.IO
|
||||
List<ITriangle> triangles;
|
||||
Polygon geometry;
|
||||
|
||||
TriangleReader.Read(filename, out geometry, out triangles);
|
||||
(new TriangleReader()).Read(filename, out geometry, out triangles);
|
||||
|
||||
if (geometry != null && triangles != null)
|
||||
{
|
||||
@@ -51,8 +51,10 @@ namespace TriangleNet.IO
|
||||
|
||||
public void Write(IMesh mesh, string filename)
|
||||
{
|
||||
TriangleWriter.WritePoly((Mesh)mesh, Path.ChangeExtension(filename, ".poly"));
|
||||
TriangleWriter.WriteElements((Mesh)mesh, Path.ChangeExtension(filename, ".ele"));
|
||||
var writer = new TriangleWriter();
|
||||
|
||||
writer.WritePoly((Mesh)mesh, Path.ChangeExtension(filename, ".poly"));
|
||||
writer.WriteElements((Mesh)mesh, Path.ChangeExtension(filename, ".ele"));
|
||||
}
|
||||
|
||||
public void Write(IMesh mesh, Stream stream)
|
||||
@@ -66,12 +68,11 @@ namespace TriangleNet.IO
|
||||
|
||||
if (ext == ".node")
|
||||
{
|
||||
return TriangleReader.ReadNodeFile(filename);
|
||||
return (new TriangleReader()).ReadNodeFile(filename);
|
||||
}
|
||||
|
||||
if (ext == ".poly")
|
||||
else if (ext == ".poly")
|
||||
{
|
||||
return TriangleReader.ReadPolyFile(filename);
|
||||
return (new TriangleReader()).ReadPolyFile(filename);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("File format '" + ext + "' not supported.");
|
||||
@@ -80,7 +81,7 @@ namespace TriangleNet.IO
|
||||
|
||||
public void Write(IPolygon polygon, string filename)
|
||||
{
|
||||
TriangleWriter.WritePoly(polygon, filename);
|
||||
(new TriangleWriter()).WritePoly(polygon, filename);
|
||||
}
|
||||
|
||||
public void Write(IPolygon polygon, Stream stream)
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Helper methods for reading Triangle file formats.
|
||||
/// </summary>
|
||||
public static class TriangleReader
|
||||
public class TriangleReader
|
||||
{
|
||||
static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
|
||||
static int startIndex = 0;
|
||||
static NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo;
|
||||
int startIndex = 0;
|
||||
|
||||
#region Helper methods
|
||||
|
||||
static bool TryReadLine(StreamReader reader, out string[] token)
|
||||
private bool TryReadLine(StreamReader reader, out string[] token)
|
||||
{
|
||||
token = null;
|
||||
|
||||
@@ -57,7 +57,7 @@ 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(List<Vertex> data, int index, string[] line, int attributes, int marks)
|
||||
private 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);
|
||||
@@ -98,7 +98,7 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Reads geometry information from .node or .poly files.
|
||||
/// </summary>
|
||||
public static void Read(string filename, out Polygon geometry)
|
||||
public void Read(string filename, out Polygon geometry)
|
||||
{
|
||||
geometry = null;
|
||||
|
||||
@@ -106,40 +106,40 @@ namespace TriangleNet.IO
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
geometry = TriangleReader.ReadPolyFile(path);
|
||||
geometry = ReadPolyFile(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = Path.ChangeExtension(filename, ".node");
|
||||
geometry = TriangleReader.ReadNodeFile(path);
|
||||
geometry = ReadNodeFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a mesh from .node, .poly or .ele files.
|
||||
/// </summary>
|
||||
public static void Read(string filename, out Polygon geometry, out List<ITriangle> triangles)
|
||||
public void Read(string filename, out Polygon geometry, out List<ITriangle> triangles)
|
||||
{
|
||||
triangles = null;
|
||||
|
||||
TriangleReader.Read(filename, out geometry);
|
||||
Read(filename, out geometry);
|
||||
|
||||
string path = Path.ChangeExtension(filename, ".ele");
|
||||
|
||||
if (File.Exists(path) && geometry != null)
|
||||
{
|
||||
triangles = TriangleReader.ReadEleFile(path);
|
||||
triangles = ReadEleFile(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads geometry information from .node or .poly files.
|
||||
/// </summary>
|
||||
public static IPolygon Read(string filename)
|
||||
public IPolygon Read(string filename)
|
||||
{
|
||||
Polygon geometry = null;
|
||||
|
||||
TriangleReader.Read(filename, out geometry);
|
||||
Read(filename, out geometry);
|
||||
|
||||
return geometry;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodefilename"></param>
|
||||
/// <remarks>Will NOT read associated .ele by default.</remarks>
|
||||
public static Polygon ReadNodeFile(string nodefilename)
|
||||
public Polygon ReadNodeFile(string nodefilename)
|
||||
{
|
||||
return ReadNodeFile(nodefilename, false);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodefilename"></param>
|
||||
/// <param name="readElements"></param>
|
||||
public static Polygon ReadNodeFile(string nodefilename, bool readElements)
|
||||
public Polygon ReadNodeFile(string nodefilename, bool readElements)
|
||||
{
|
||||
Polygon data;
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace TriangleNet.IO
|
||||
string[] line;
|
||||
int invertices = 0, attributes = 0, nodemarkers = 0;
|
||||
|
||||
using (StreamReader reader = new StreamReader(nodefilename))
|
||||
using (var reader = new StreamReader(nodefilename))
|
||||
{
|
||||
if (!TryReadLine(reader, out line))
|
||||
{
|
||||
@@ -249,7 +249,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <remarks>Will NOT read associated .ele by default.</remarks>
|
||||
public static Polygon ReadPolyFile(string polyfilename)
|
||||
public Polygon ReadPolyFile(string polyfilename)
|
||||
{
|
||||
return ReadPolyFile(polyfilename, false, false);
|
||||
}
|
||||
@@ -260,7 +260,7 @@ namespace TriangleNet.IO
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <param name="readElements">If true, look for an associated .ele file.</param>
|
||||
/// <remarks>Will NOT read associated .area by default.</remarks>
|
||||
public static Polygon ReadPolyFile(string polyfilename, bool readElements)
|
||||
public Polygon ReadPolyFile(string polyfilename, bool readElements)
|
||||
{
|
||||
return ReadPolyFile(polyfilename, readElements, false);
|
||||
}
|
||||
@@ -271,7 +271,7 @@ namespace TriangleNet.IO
|
||||
/// <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>
|
||||
public static Polygon ReadPolyFile(string polyfilename, bool readElements, bool readArea)
|
||||
public Polygon ReadPolyFile(string polyfilename, bool readElements, bool readArea)
|
||||
{
|
||||
// Read poly file
|
||||
Polygon data;
|
||||
@@ -281,7 +281,7 @@ namespace TriangleNet.IO
|
||||
string[] line;
|
||||
int invertices = 0, attributes = 0, nodemarkers = 0;
|
||||
|
||||
using (StreamReader reader = new StreamReader(polyfilename))
|
||||
using (var reader = new StreamReader(polyfilename))
|
||||
{
|
||||
if (!TryReadLine(reader, out line))
|
||||
{
|
||||
@@ -488,7 +488,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="elefilename">The file name.</param>
|
||||
/// <returns>A list of triangles.</returns>
|
||||
public static List<ITriangle> ReadEleFile(string elefilename)
|
||||
public List<ITriangle> ReadEleFile(string elefilename)
|
||||
{
|
||||
return ReadEleFile(elefilename, false);
|
||||
}
|
||||
@@ -499,13 +499,13 @@ namespace TriangleNet.IO
|
||||
/// <param name="elefilename"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="readArea"></param>
|
||||
private static List<ITriangle> ReadEleFile(string elefilename, bool readArea)
|
||||
private List<ITriangle> ReadEleFile(string elefilename, bool readArea)
|
||||
{
|
||||
int intriangles = 0, attributes = 0;
|
||||
|
||||
List<ITriangle> triangles;
|
||||
|
||||
using (StreamReader reader = new StreamReader(elefilename))
|
||||
using (var reader = new StreamReader(elefilename))
|
||||
{
|
||||
// Read number of elements and number of attributes.
|
||||
string[] line;
|
||||
@@ -585,11 +585,11 @@ namespace TriangleNet.IO
|
||||
/// <param name="areafilename"></param>
|
||||
/// <param name="intriangles"></param>
|
||||
/// <param name="data"></param>
|
||||
private static double[] ReadAreaFile(string areafilename, int intriangles)
|
||||
private double[] ReadAreaFile(string areafilename, int intriangles)
|
||||
{
|
||||
double[] data = null;
|
||||
|
||||
using (StreamReader reader = new StreamReader(areafilename))
|
||||
using (var reader = new StreamReader(areafilename))
|
||||
{
|
||||
string[] line;
|
||||
|
||||
@@ -633,7 +633,7 @@ namespace TriangleNet.IO
|
||||
/// <param name="edgeFile">The file name.</param>
|
||||
/// <param name="invertices">The number of input vertices (read from a .node or .poly file).</param>
|
||||
/// <returns>A List of edges.</returns>
|
||||
public static List<Edge> ReadEdgeFile(string edgeFile, int invertices)
|
||||
public List<Edge> ReadEdgeFile(string edgeFile, int invertices)
|
||||
{
|
||||
// Read poly file
|
||||
List<Edge> data = null;
|
||||
@@ -642,7 +642,7 @@ namespace TriangleNet.IO
|
||||
|
||||
string[] line;
|
||||
|
||||
using (StreamReader reader = new StreamReader(edgeFile))
|
||||
using (var reader = new StreamReader(edgeFile))
|
||||
{
|
||||
// Read the edges from a .edge file.
|
||||
|
||||
|
||||
@@ -16,19 +16,19 @@ namespace TriangleNet.IO
|
||||
/// <summary>
|
||||
/// Helper methods for writing Triangle file formats.
|
||||
/// </summary>
|
||||
public static class TriangleWriter
|
||||
public class TriangleWriter
|
||||
{
|
||||
static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
|
||||
static NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Number the vertices and write them to a .node file.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="filename"></param>
|
||||
public static void Write(Mesh mesh, string filename)
|
||||
public void Write(Mesh mesh, string filename)
|
||||
{
|
||||
TriangleWriter.WritePoly(mesh, Path.ChangeExtension(filename, ".poly"));
|
||||
TriangleWriter.WriteElements(mesh, Path.ChangeExtension(filename, ".ele"));
|
||||
WritePoly(mesh, Path.ChangeExtension(filename, ".poly"));
|
||||
WriteElements(mesh, Path.ChangeExtension(filename, ".ele"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,18 +36,18 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="filename"></param>
|
||||
public static void WriteNodes(Mesh mesh, string filename)
|
||||
public void WriteNodes(Mesh mesh, string filename)
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
using (var writer = new StreamWriter(filename))
|
||||
{
|
||||
TriangleWriter.WriteNodes(writer, mesh);
|
||||
WriteNodes(writer, mesh);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number the vertices and write them to a .node file.
|
||||
/// </summary>
|
||||
private static void WriteNodes(StreamWriter writer, Mesh mesh)
|
||||
private void WriteNodes(StreamWriter writer, Mesh mesh)
|
||||
{
|
||||
int outvertices = mesh.vertices.Count;
|
||||
int nextras = mesh.nextras;
|
||||
@@ -102,7 +102,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodes"></param>
|
||||
/// <param name="writer"></param>
|
||||
private static void WriteNodes(StreamWriter writer, IEnumerable<Vertex> nodes, bool markers,
|
||||
private void WriteNodes(StreamWriter writer, IEnumerable<Vertex> nodes, bool markers,
|
||||
int attribs, bool jettison)
|
||||
{
|
||||
int index = 0;
|
||||
@@ -140,7 +140,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="filename"></param>
|
||||
public static void WriteElements(Mesh mesh, string filename)
|
||||
public void WriteElements(Mesh mesh, string filename)
|
||||
{
|
||||
Otri tri = default(Otri);
|
||||
Vertex p1, p2, p3;
|
||||
@@ -150,12 +150,12 @@ namespace TriangleNet.IO
|
||||
|
||||
tri.orient = 0;
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
using (var writer = new StreamWriter(filename))
|
||||
{
|
||||
// Number of triangles, vertices per triangle, attributes per triangle.
|
||||
writer.WriteLine("{0} 3 {1}", mesh.triangles.Count, regions ? 1 : 0);
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
@@ -188,18 +188,18 @@ namespace TriangleNet.IO
|
||||
/// <remarks>If the nodes should not be written into this file,
|
||||
/// make sure a .node file was written before, so that the nodes
|
||||
/// are numbered right.</remarks>
|
||||
public static void WritePoly(IPolygon polygon, string filename)
|
||||
public void WritePoly(IPolygon polygon, string filename)
|
||||
{
|
||||
bool hasMarkers = polygon.HasSegmentMarkers;
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
using (var writer = new StreamWriter(filename))
|
||||
{
|
||||
// TODO: write vertex attributes
|
||||
|
||||
writer.WriteLine("{0} 2 0 {1}", polygon.Points.Count, polygon.HasPointMarkers ? "1" : "0");
|
||||
|
||||
// Write nodes to this file.
|
||||
TriangleWriter.WriteNodes(writer, polygon.Points, polygon.HasPointMarkers, 0, false);
|
||||
WriteNodes(writer, polygon.Points, polygon.HasPointMarkers, 0, false);
|
||||
|
||||
// Number of segments, number of boundary markers (zero or one).
|
||||
writer.WriteLine("{0} {1}", polygon.Segments.Count, hasMarkers ? "1" : "0");
|
||||
@@ -254,9 +254,9 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="filename"></param>
|
||||
public static void WritePoly(Mesh mesh, string filename)
|
||||
public void WritePoly(Mesh mesh, string filename)
|
||||
{
|
||||
TriangleWriter.WritePoly(mesh, filename, true);
|
||||
WritePoly(mesh, filename, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -268,19 +268,19 @@ namespace TriangleNet.IO
|
||||
/// <remarks>If the nodes should not be written into this file,
|
||||
/// make sure a .node file was written before, so that the nodes
|
||||
/// are numbered right.</remarks>
|
||||
public static void WritePoly(Mesh mesh, string filename, bool writeNodes)
|
||||
public void WritePoly(Mesh mesh, string filename, bool writeNodes)
|
||||
{
|
||||
Osub subseg = default(Osub);
|
||||
Vertex pt1, pt2;
|
||||
|
||||
bool useBoundaryMarkers = mesh.behavior.UseBoundaryMarkers;
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
using (var writer = new StreamWriter(filename))
|
||||
{
|
||||
if (writeNodes)
|
||||
{
|
||||
// Write nodes to this file.
|
||||
TriangleWriter.WriteNodes(writer, mesh);
|
||||
WriteNodes(writer, mesh);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -347,7 +347,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="filename"></param>
|
||||
public static void WriteEdges(Mesh mesh, string filename)
|
||||
public void WriteEdges(Mesh mesh, string filename)
|
||||
{
|
||||
Otri tri = default(Otri), trisym = default(Otri);
|
||||
Osub checkmark = default(Osub);
|
||||
@@ -355,7 +355,7 @@ namespace TriangleNet.IO
|
||||
|
||||
Behavior behavior = mesh.behavior;
|
||||
|
||||
using (StreamWriter writer = new StreamWriter(filename))
|
||||
using (var writer = new StreamWriter(filename))
|
||||
{
|
||||
// Number of edges, number of boundary markers (zero or one).
|
||||
writer.WriteLine("{0} {1}", mesh.NumberOfEdges, behavior.UseBoundaryMarkers ? "1" : "0");
|
||||
@@ -367,7 +367,7 @@ namespace TriangleNet.IO
|
||||
// adjacent triangle, operate on the edge only if the current triangle
|
||||
// has a smaller pointer than its neighbor. This way, each edge is
|
||||
// considered only once.
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
@@ -423,7 +423,7 @@ namespace TriangleNet.IO
|
||||
/// <param name="filename"></param>
|
||||
/// <remarks>WARNING: Be sure WriteElements has been called before,
|
||||
/// so the elements are numbered right!</remarks>
|
||||
public static void WriteNeighbors(Mesh mesh, string filename)
|
||||
public void WriteNeighbors(Mesh mesh, string filename)
|
||||
{
|
||||
Otri tri = default(Otri), trisym = default(Otri);
|
||||
int n1, n2, n3;
|
||||
@@ -434,7 +434,7 @@ namespace TriangleNet.IO
|
||||
// Number of triangles, three neighbors per triangle.
|
||||
writer.WriteLine("{0} 3", mesh.triangles.Count);
|
||||
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace TriangleNet
|
||||
// TODO: Check if custom hashmap implementation could be faster.
|
||||
|
||||
// Using hashsets for memory management should quite fast.
|
||||
internal Dictionary<int, Triangle> triangles;
|
||||
internal TrianglePool triangles;
|
||||
internal Dictionary<int, SubSegment> subsegs;
|
||||
internal Dictionary<int, Vertex> vertices;
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace TriangleNet
|
||||
/// </summary>
|
||||
public ICollection<Triangle> Triangles
|
||||
{
|
||||
get { return this.triangles.Values; }
|
||||
get { return this.triangles; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -232,7 +232,7 @@ namespace TriangleNet
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mesh" /> class.
|
||||
/// </summary>
|
||||
public Mesh(IPredicates predicates)
|
||||
public Mesh(Configuration config)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
@@ -241,9 +241,10 @@ namespace TriangleNet
|
||||
behavior = new Behavior();
|
||||
|
||||
vertices = new Dictionary<int, Vertex>();
|
||||
triangles = new Dictionary<int, Triangle>();
|
||||
subsegs = new Dictionary<int, SubSegment>();
|
||||
|
||||
triangles = config.TrianglePool();
|
||||
|
||||
flipstack = new Stack<Otri>();
|
||||
|
||||
holes = new List<Point>();
|
||||
@@ -251,7 +252,7 @@ namespace TriangleNet
|
||||
|
||||
steinerleft = -1;
|
||||
|
||||
this.predicates = predicates;
|
||||
this.predicates = config.Predicates();
|
||||
|
||||
this.locator = new TriangleLocator(this, predicates);
|
||||
}
|
||||
@@ -317,7 +318,7 @@ namespace TriangleNet
|
||||
|
||||
// Triangles will always be numbered from 0 to n-1
|
||||
id = 0;
|
||||
foreach (var item in this.triangles.Values)
|
||||
foreach (var item in this.triangles)
|
||||
{
|
||||
item.id = id++;
|
||||
}
|
||||
@@ -358,7 +359,7 @@ namespace TriangleNet
|
||||
private void ResetData()
|
||||
{
|
||||
vertices.Clear();
|
||||
triangles.Clear();
|
||||
triangles.Restart();
|
||||
subsegs.Clear();
|
||||
|
||||
holes.Clear();
|
||||
@@ -410,7 +411,7 @@ namespace TriangleNet
|
||||
|
||||
if (this.invertices < 3)
|
||||
{
|
||||
logger.Error("Input must have at least three input vertices.", "MeshReader.TransferNodes()");
|
||||
logger.Error("Input must have at least three input vertices.", "Mesh.TransferNodes()");
|
||||
throw new Exception("Input must have at least three input vertices.");
|
||||
}
|
||||
|
||||
@@ -461,7 +462,7 @@ namespace TriangleNet
|
||||
Otri tri = default(Otri);
|
||||
Vertex triorg;
|
||||
|
||||
foreach (var t in this.triangles.Values)
|
||||
foreach (var t in this.triangles)
|
||||
{
|
||||
tri.tri = t;
|
||||
// Check all three vertices of the triangle.
|
||||
@@ -483,9 +484,9 @@ namespace TriangleNet
|
||||
/// <param name="newotri">Reference to the new triangle.</param>
|
||||
internal void MakeTriangle(ref Otri newotri)
|
||||
{
|
||||
Triangle tri = new Triangle();
|
||||
Triangle tri = triangles.Get();
|
||||
|
||||
tri.hash = tri.id = this.hash_tri++;
|
||||
//tri.id = tri.hash;
|
||||
|
||||
tri.subsegs[0].seg = dummysub;
|
||||
tri.subsegs[1].seg = dummysub;
|
||||
@@ -497,8 +498,6 @@ namespace TriangleNet
|
||||
|
||||
newotri.tri = tri;
|
||||
newotri.orient = 0;
|
||||
|
||||
triangles.Add(tri.hash, tri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1732,7 +1731,7 @@ namespace TriangleNet
|
||||
// Mark the triangle as dead. This makes it possible to detect dead
|
||||
// triangles when traversing the list of all triangles.
|
||||
Otri.Kill(dyingtriangle);
|
||||
triangles.Remove(dyingtriangle.hash);
|
||||
triangles.Release(dyingtriangle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace TriangleNet
|
||||
int horrors = 0;
|
||||
|
||||
// Run through the list of triangles, checking each one.
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
tri.tri = t;
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace TriangleNet
|
||||
var inf3 = mesh.infvertex3;
|
||||
|
||||
// Run through the list of triangles, checking each one.
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
loop.tri = tri;
|
||||
|
||||
|
||||
@@ -55,16 +55,6 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
Vertex[] sortarray;
|
||||
Mesh mesh;
|
||||
|
||||
public Dwyer()
|
||||
: this(RobustPredicates.Default)
|
||||
{
|
||||
}
|
||||
|
||||
public Dwyer(IPredicates predicates)
|
||||
{
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// </summary>
|
||||
@@ -73,9 +63,11 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
/// Sorts the vertices, calls a recursive procedure to triangulate them, and
|
||||
/// removes the bounding box, setting boundary markers as appropriate.
|
||||
/// </remarks>
|
||||
public IMesh Triangulate(IList<Vertex> points)
|
||||
public IMesh Triangulate(IList<Vertex> points, Configuration config)
|
||||
{
|
||||
this.mesh = new Mesh(predicates);
|
||||
this.predicates = config.Predicates();
|
||||
|
||||
this.mesh = new Mesh(config);
|
||||
this.mesh.TransferNodes(points);
|
||||
|
||||
Otri hullleft = default(Otri), hullright = default(Otri);
|
||||
@@ -104,7 +96,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning(
|
||||
String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].hash),
|
||||
String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].id),
|
||||
"Dwyer.Triangulate()");
|
||||
}
|
||||
sortarray[j].type = VertexType.UndeadVertex;
|
||||
|
||||
@@ -16,28 +16,16 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
/// </summary>
|
||||
public class Incremental : ITriangulator
|
||||
{
|
||||
IPredicates predicates;
|
||||
|
||||
Mesh mesh;
|
||||
|
||||
public Incremental()
|
||||
: this(RobustPredicates.Default)
|
||||
{
|
||||
}
|
||||
|
||||
public Incremental(IPredicates predicates)
|
||||
{
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by incrementally inserting vertices.
|
||||
/// </summary>
|
||||
/// <returns>Returns the number of edges on the convex hull of the
|
||||
/// triangulation.</returns>
|
||||
public IMesh Triangulate(IList<Vertex> points)
|
||||
public IMesh Triangulate(IList<Vertex> points, Configuration config)
|
||||
{
|
||||
this.mesh = new Mesh(predicates);
|
||||
this.mesh = new Mesh(config);
|
||||
this.mesh.TransferNodes(points);
|
||||
|
||||
Otri starttri = new Otri();
|
||||
|
||||
@@ -33,19 +33,11 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
double xminextreme; // Nonexistent x value used as a flag in sweepline.
|
||||
List<SplayNode> splaynodes;
|
||||
|
||||
public SweepLine()
|
||||
: this(RobustPredicates.Default)
|
||||
public IMesh Triangulate(IList<Vertex> points, Configuration config)
|
||||
{
|
||||
}
|
||||
this.predicates = config.Predicates();
|
||||
|
||||
public SweepLine(IPredicates predicates)
|
||||
{
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
public IMesh Triangulate(IList<Vertex> points)
|
||||
{
|
||||
this.mesh = new Mesh(predicates);
|
||||
this.mesh = new Mesh(config);
|
||||
this.mesh.TransferNodes(points);
|
||||
|
||||
// Nonexistent x value used as a flag to mark circle events in sweepline
|
||||
|
||||
@@ -26,10 +26,10 @@ namespace TriangleNet.Meshing
|
||||
|
||||
ILog<LogItem> logger;
|
||||
|
||||
public ConstraintMesher(Mesh mesh, IPredicates predicates)
|
||||
public ConstraintMesher(Mesh mesh, Configuration config)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
this.predicates = predicates;
|
||||
this.predicates = config.Predicates();
|
||||
|
||||
this.behavior = mesh.behavior;
|
||||
this.locator = mesh.locator;
|
||||
@@ -41,9 +41,10 @@ namespace TriangleNet.Meshing
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate given input data.
|
||||
/// Insert segments into the mesh.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="input">The polygon.</param>
|
||||
/// <param name="options">Constraint options.</param>
|
||||
public void Apply(IPolygon input, ConstraintOptions options)
|
||||
{
|
||||
behavior.Poly = input.Segments.Count > 0;
|
||||
@@ -231,8 +232,6 @@ namespace TriangleNet.Meshing
|
||||
// The segment endpoints.
|
||||
Vertex p, q;
|
||||
|
||||
int label;
|
||||
|
||||
mesh.insegments = 0;
|
||||
|
||||
if (behavior.Poly)
|
||||
@@ -251,17 +250,11 @@ namespace TriangleNet.Meshing
|
||||
mesh.MakeVertexMap();
|
||||
}
|
||||
|
||||
label = 0;
|
||||
|
||||
// Read and insert the segments.
|
||||
foreach (var seg in input.Segments)
|
||||
{
|
||||
mesh.insegments++;
|
||||
|
||||
label = seg.Label;
|
||||
|
||||
// TODO: wrap segment dictionary access in try / catch?
|
||||
|
||||
p = seg.GetVertex(0);
|
||||
q = seg.GetVertex(1);
|
||||
|
||||
@@ -275,7 +268,7 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
else
|
||||
{
|
||||
InsertSegment(p, q, label);
|
||||
InsertSegment(p, q, seg.Label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace TriangleNet.Meshing
|
||||
int elements = triangles == null ? 0 : triangles.Length;
|
||||
int segments = polygon.Segments.Count;
|
||||
|
||||
var mesh = new Mesh(RobustPredicates.Default);
|
||||
// TODO: Configuration should be a function argument.
|
||||
var mesh = new Mesh(new Configuration());
|
||||
|
||||
mesh.TransferNodes(polygon.Points);
|
||||
|
||||
@@ -114,7 +115,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
// Read the triangles from the .ele file, and link
|
||||
// together those that share an edge.
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
@@ -371,7 +372,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
Face face;
|
||||
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
face = new Face(null);
|
||||
face.id = t.id;
|
||||
@@ -396,7 +397,7 @@ namespace TriangleNet.Meshing
|
||||
// Maps a vertex to its leaving boundary edge.
|
||||
var boundary = new Dictionary<int, HalfEdge>();
|
||||
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
id = t.id;
|
||||
|
||||
|
||||
@@ -15,33 +15,36 @@ namespace TriangleNet.Meshing
|
||||
/// <summary>
|
||||
/// Create meshes of point sets or polygons.
|
||||
/// </summary>
|
||||
public class GenericMesher : ITriangulator, IConstraintMesher, IQualityMesher
|
||||
public class GenericMesher
|
||||
{
|
||||
IPredicates predicates;
|
||||
|
||||
Configuration config;
|
||||
ITriangulator triangulator;
|
||||
|
||||
public GenericMesher()
|
||||
: this(new Dwyer(), new Configuration())
|
||||
{
|
||||
this.predicates = new RobustPredicates();
|
||||
this.triangulator = new Dwyer(this.predicates);
|
||||
}
|
||||
|
||||
public GenericMesher(ITriangulator triangulator)
|
||||
: this(triangulator, RobustPredicates.Default)
|
||||
: this(triangulator, new Configuration())
|
||||
{
|
||||
}
|
||||
|
||||
public GenericMesher(ITriangulator triangulator, IPredicates predicates)
|
||||
public GenericMesher(Configuration config)
|
||||
: this(new Dwyer(), config)
|
||||
{
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
public GenericMesher(ITriangulator triangulator, Configuration config)
|
||||
{
|
||||
this.config = config;
|
||||
this.triangulator = triangulator;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMesh Triangulate(IList<Vertex> points)
|
||||
{
|
||||
return triangulator.Triangulate(points);
|
||||
return triangulator.Triangulate(points, config);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -65,10 +68,10 @@ namespace TriangleNet.Meshing
|
||||
/// <inheritdoc />
|
||||
public IMesh Triangulate(IPolygon polygon, ConstraintOptions options, QualityOptions quality)
|
||||
{
|
||||
var mesh = (Mesh)triangulator.Triangulate(polygon.Points);
|
||||
var mesh = (Mesh)triangulator.Triangulate(polygon.Points, config);
|
||||
|
||||
var cmesher = new ConstraintMesher(mesh, predicates);
|
||||
var qmesher = new QualityMesher(mesh, predicates);
|
||||
var cmesher = new ConstraintMesher(mesh, config);
|
||||
var qmesher = new QualityMesher(mesh, config);
|
||||
|
||||
mesh.SetQualityMesher(qmesher);
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ namespace TriangleNet.Meshing
|
||||
/// Triangulates a point set.
|
||||
/// </summary>
|
||||
/// <param name="points">Collection of points.</param>
|
||||
/// <param name="config"></param>
|
||||
/// <returns>Mesh</returns>
|
||||
IMesh Triangulate(IList<Vertex> points);
|
||||
IMesh Triangulate(IList<Vertex> points, Configuration config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace TriangleNet.Meshing.Iterators
|
||||
/// </summary>
|
||||
public EdgeIterator(Mesh mesh)
|
||||
{
|
||||
triangles = mesh.triangles.Values.GetEnumerator();
|
||||
triangles = mesh.triangles.GetEnumerator();
|
||||
triangles.MoveNext();
|
||||
|
||||
tri.tri = triangles.Current;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TriangleNet.Meshing
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Logging;
|
||||
using TriangleNet.Meshing.Data;
|
||||
using Tools;
|
||||
using TriangleNet.Tools;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
/// <summary>
|
||||
@@ -35,7 +35,7 @@ namespace TriangleNet.Meshing
|
||||
// in SplitTriangle method.
|
||||
Triangle newvertex_tri;
|
||||
|
||||
public QualityMesher(Mesh mesh, IPredicates predicates)
|
||||
public QualityMesher(Mesh mesh, Configuration config)
|
||||
{
|
||||
logger = Log.Instance;
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace TriangleNet.Meshing
|
||||
queue = new BadTriQueue();
|
||||
|
||||
this.mesh = mesh;
|
||||
this.predicates = predicates;
|
||||
this.predicates = config.Predicates();
|
||||
|
||||
this.behavior = mesh.behavior;
|
||||
|
||||
@@ -53,9 +53,9 @@ namespace TriangleNet.Meshing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triangulate given input data.
|
||||
/// Apply quality constraints to a mesh.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="quality">The quality constraints.</param>
|
||||
public void Apply(QualityOptions quality)
|
||||
{
|
||||
// Copy quality options
|
||||
@@ -684,7 +684,7 @@ namespace TriangleNet.Meshing
|
||||
Otri triangleloop = default(Otri);
|
||||
triangleloop.orient = 0;
|
||||
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
triangleloop.tri = tri;
|
||||
|
||||
|
||||
@@ -2524,11 +2524,6 @@ namespace TriangleNet
|
||||
petaly = new double[2 * numpoints];
|
||||
petalr = new double[2 * numpoints];
|
||||
wedges = new double[2 * numpoints * 16 + 36];
|
||||
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Info("NewLocation: resized work arrays (" + 2 * numpoints + ")");
|
||||
}
|
||||
}
|
||||
|
||||
double xmid, ymid, dist, x3, y3;
|
||||
@@ -2791,11 +2786,6 @@ namespace TriangleNet
|
||||
petaly = new double[2 * numpoints];
|
||||
petalr = new double[2 * numpoints];
|
||||
wedges = new double[2 * numpoints * 20 + 40];
|
||||
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Info("NewLocation: resized work arrays (" + 2 * numpoints + ")");
|
||||
}
|
||||
}
|
||||
|
||||
double xmid, ymid, dist, x3, y3;
|
||||
|
||||
@@ -9,17 +9,18 @@ namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
/// <summary>
|
||||
/// Used for triangle sampling in the <see cref="TriangleLocator"/> class.
|
||||
/// </summary>
|
||||
class Sampler
|
||||
class Sampler : IEnumerable<Triangle>
|
||||
{
|
||||
// Empirically chosen factor.
|
||||
private const int samplefactor = 11;
|
||||
|
||||
private Random rand;
|
||||
private Mesh mesh;
|
||||
|
||||
// Number of random samples for point location (at least 1).
|
||||
private int samples = 1;
|
||||
@@ -27,11 +28,9 @@ namespace TriangleNet
|
||||
// Number of triangles in mesh.
|
||||
private int triangleCount = 0;
|
||||
|
||||
// Keys of the triangle dictionary.
|
||||
private int[] keys;
|
||||
|
||||
public Sampler()
|
||||
public Sampler(Mesh mesh)
|
||||
{
|
||||
this.mesh = mesh;
|
||||
this.rand = new Random(110503);
|
||||
}
|
||||
|
||||
@@ -48,16 +47,7 @@ namespace TriangleNet
|
||||
/// Update sampling parameters if mesh changed.
|
||||
/// </summary>
|
||||
/// <param name="mesh">Current mesh.</param>
|
||||
public void Update(Mesh mesh)
|
||||
{
|
||||
this.Update(mesh, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update sampling parameters if mesh changed.
|
||||
/// </summary>
|
||||
/// <param name="mesh">Current mesh.</param>
|
||||
public void Update(Mesh mesh, bool forceUpdate)
|
||||
public void Update(bool forceUpdate = false)
|
||||
{
|
||||
int count = mesh.triangles.Count;
|
||||
|
||||
@@ -74,43 +64,17 @@ namespace TriangleNet
|
||||
{
|
||||
samples++;
|
||||
}
|
||||
|
||||
// TODO: Is there a way not calling ToArray()?
|
||||
keys = mesh.triangles.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a random sample set of triangle keys.
|
||||
/// </summary>
|
||||
/// <returns>Array of triangle keys.</returns>
|
||||
public int[] GetSamples(Mesh mesh)
|
||||
public IEnumerator<Triangle> GetEnumerator()
|
||||
{
|
||||
// TODO: Using currKeys to check key availability?
|
||||
List<int> randSamples = new List<int>(samples);
|
||||
return mesh.triangles.Sample(samples, rand).GetEnumerator();
|
||||
}
|
||||
|
||||
int range = triangleCount / samples;
|
||||
int key;
|
||||
|
||||
for (int i = 0; i < samples; i++)
|
||||
{
|
||||
// Yeah, rand should be equally distributed, but just to make
|
||||
// sure, use a range variable...
|
||||
key = rand.Next(i * range, (i + 1) * range - 1);
|
||||
|
||||
if (!mesh.triangles.ContainsKey(keys[key]))
|
||||
{
|
||||
// Keys collection isn't up to date anymore!
|
||||
this.Update(mesh, true);
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
randSamples.Add(keys[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return randSamples.ToArray();
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace TriangleNet.Tools
|
||||
}
|
||||
|
||||
// Examine each triangle.
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
tid = tri.id;
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace TriangleNet.Tools
|
||||
int tid, nid; // Triangle and neighbor id.
|
||||
|
||||
// Examine each triangle.
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
tid = tri.id;
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ namespace TriangleNet.Tools
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
using Vertex = TriangleNet.Topology.DCEL.Vertex;
|
||||
|
||||
public static class IntersectionHelper
|
||||
{
|
||||
/// <summary>
|
||||
@@ -47,8 +45,8 @@ namespace TriangleNet.Tools
|
||||
/// <param name="rect">The clip rectangle.</param>
|
||||
/// <param name="p0">Segment endpoint.</param>
|
||||
/// <param name="p1">Segment endpoint.</param>
|
||||
/// <param name="c0">The new location of p0 (DCEL vertex).</param>
|
||||
/// <param name="c1">The new location of p1 (DCEL vertex).</param>
|
||||
/// <param name="c0">The new location of p0.</param>
|
||||
/// <param name="c1">The new location of p1.</param>
|
||||
/// <returns>Returns true, if segment is clipped.</returns>
|
||||
/// <remarks>
|
||||
/// Based on Liang-Barsky function by Daniel White:
|
||||
@@ -111,7 +109,7 @@ namespace TriangleNet.Tools
|
||||
/// <param name="rect">The clip rectangle.</param>
|
||||
/// <param name="p0">The ray startpoint (inside the box).</param>
|
||||
/// <param name="p1">Any point in ray direction (NOT the direction vector).</param>
|
||||
/// <param name="c1">The intersection point (DCEL vertex).</param>
|
||||
/// <param name="c1">The intersection point.</param>
|
||||
/// <returns>Returns false, if startpoint is outside the box.</returns>
|
||||
public static bool BoxRayIntersection(Rectangle rect, Point p0, Point p1, ref Point c1)
|
||||
{
|
||||
|
||||
@@ -182,7 +182,7 @@ namespace TriangleNet.Tools
|
||||
|
||||
int n = 0;
|
||||
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
n++;
|
||||
|
||||
@@ -247,7 +247,7 @@ namespace TriangleNet.Tools
|
||||
|
||||
int gi, gj;
|
||||
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace TriangleNet.Tools
|
||||
int i, j, k;
|
||||
|
||||
tri.orient = 0;
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
tri.tri = t;
|
||||
p[0] = tri.Org();
|
||||
@@ -256,7 +256,7 @@ namespace TriangleNet.Tools
|
||||
|
||||
double triMinAngle, triMaxAngle = 1;
|
||||
|
||||
foreach (var tri in mesh.triangles.Values)
|
||||
foreach (var tri in mesh.triangles)
|
||||
{
|
||||
triMinAngle = 0; // Min angle: 0 < a < 60 degress
|
||||
triMaxAngle = 1; // Max angle: 60 < a < 180 degress
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration.cs" />
|
||||
<Compile Include="Geometry\Contour.cs" />
|
||||
<Compile Include="Geometry\Edge.cs" />
|
||||
<Compile Include="Geometry\ExtensionMethods.cs" />
|
||||
@@ -101,6 +102,7 @@
|
||||
<Compile Include="Topology\DCEL\Vertex.cs" />
|
||||
<Compile Include="Smoothing\ISmoother.cs" />
|
||||
<Compile Include="Smoothing\SimpleSmoother.cs" />
|
||||
<Compile Include="TrianglePool.cs" />
|
||||
<Compile Include="Voronoi\BoundedVoronoi.cs" />
|
||||
<Compile Include="Voronoi\DefaultVoronoiFactory.cs" />
|
||||
<Compile Include="Voronoi\IVoronoiFactory.cs" />
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace TriangleNet
|
||||
this.mesh = mesh;
|
||||
this.predicates = predicates;
|
||||
|
||||
sampler = new Sampler();
|
||||
sampler = new Sampler(mesh);
|
||||
}
|
||||
|
||||
public void Update(ref Otri otri)
|
||||
@@ -292,12 +292,11 @@ namespace TriangleNet
|
||||
}
|
||||
|
||||
// TODO: Improve sampling.
|
||||
sampler.Update(mesh);
|
||||
int[] samples = sampler.GetSamples(mesh);
|
||||
sampler.Update();
|
||||
|
||||
foreach (var key in samples)
|
||||
foreach (var t in sampler)
|
||||
{
|
||||
sampletri.tri = mesh.triangles[key];
|
||||
sampletri.tri = t;
|
||||
if (!Otri.IsDead(sampletri.tri))
|
||||
{
|
||||
torg = sampletri.Org();
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="TrianglePool.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Topology;
|
||||
|
||||
public class TrianglePool : ICollection<Triangle>
|
||||
{
|
||||
// Determines the size of each block in the pool.
|
||||
private const int BLOCKSIZE = 1024;
|
||||
|
||||
// The total number of currently allocated triangles.
|
||||
int size;
|
||||
|
||||
// The number of triangles currently used.
|
||||
int count;
|
||||
|
||||
// The pool.
|
||||
Triangle[][] pool;
|
||||
|
||||
// A stack of free triangles.
|
||||
Stack<Triangle> stack;
|
||||
|
||||
public TrianglePool()
|
||||
{
|
||||
size = 0;
|
||||
|
||||
// On startup, the pool should be able to hold 2^16 triangles.
|
||||
int n = Math.Max(1, 65536 / BLOCKSIZE);
|
||||
|
||||
pool = new Triangle[n][];
|
||||
pool[0] = new Triangle[BLOCKSIZE];
|
||||
|
||||
stack = new Stack<Triangle>(BLOCKSIZE);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a triangle from the pool.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Triangle Get()
|
||||
{
|
||||
Triangle triangle;
|
||||
|
||||
if (stack.Count > 0)
|
||||
{
|
||||
triangle = stack.Pop();
|
||||
triangle.hash = -triangle.hash - 1;
|
||||
|
||||
Cleanup(triangle);
|
||||
}
|
||||
else if (count < size)
|
||||
{
|
||||
triangle = pool[count / BLOCKSIZE][count % BLOCKSIZE];
|
||||
triangle.id = triangle.hash;
|
||||
|
||||
Cleanup(triangle);
|
||||
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
triangle = new Triangle();
|
||||
triangle.hash = size;
|
||||
triangle.id = triangle.hash;
|
||||
|
||||
int block = size / BLOCKSIZE;
|
||||
|
||||
if (pool[block] == null)
|
||||
{
|
||||
pool[block] = new Triangle[BLOCKSIZE];
|
||||
|
||||
// Check if the pool has to be resized.
|
||||
if (block + 1 == pool.Length)
|
||||
{
|
||||
Array.Resize(ref pool, 2 * pool.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// Add triangle to pool.
|
||||
pool[block][size % BLOCKSIZE] = triangle;
|
||||
|
||||
count = ++size;
|
||||
}
|
||||
|
||||
return triangle;
|
||||
}
|
||||
|
||||
public void Release(Triangle triangle)
|
||||
{
|
||||
stack.Push(triangle);
|
||||
|
||||
// Mark the triangle as free (used by enumerator).
|
||||
triangle.hash = -triangle.hash - 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart the triangle pool.
|
||||
/// </summary>
|
||||
public TrianglePool Restart()
|
||||
{
|
||||
foreach (var triangle in stack)
|
||||
{
|
||||
// Reset hash to original value.
|
||||
triangle.hash = -triangle.hash - 1;
|
||||
}
|
||||
|
||||
stack.Clear();
|
||||
|
||||
count = 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Samples a number of triangles from the pool.
|
||||
/// </summary>
|
||||
/// <param name="k">The number of triangles to sample.</param>
|
||||
/// <param name="random"></param>
|
||||
/// <returns></returns>
|
||||
internal IEnumerable<Triangle> Sample(int k, Random random)
|
||||
{
|
||||
int i, count = this.Count;
|
||||
|
||||
if (k > count)
|
||||
{
|
||||
// TODO: handle Sample special case.
|
||||
k = count;
|
||||
}
|
||||
|
||||
Triangle t;
|
||||
|
||||
// TODO: improve sampling code (to ensure no duplicates).
|
||||
|
||||
while (k > 0)
|
||||
{
|
||||
i = random.Next(0, count);
|
||||
|
||||
t = pool[i / BLOCKSIZE][i % BLOCKSIZE];
|
||||
|
||||
if (t.hash >= 0)
|
||||
{
|
||||
k--;
|
||||
yield return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Cleanup(Triangle triangle)
|
||||
{
|
||||
triangle.label = 0;
|
||||
triangle.area = 0.0;
|
||||
triangle.infected = false;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
triangle.vertices[i] = null;
|
||||
|
||||
triangle.subsegs[i] = default(Osub);
|
||||
triangle.neighbors[i] = default(Otri);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(Triangle item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
stack.Clear();
|
||||
|
||||
int blocks = (size / BLOCKSIZE) + 1;
|
||||
|
||||
for (int i = 0; i < blocks; i++)
|
||||
{
|
||||
var block = pool[i];
|
||||
|
||||
// Number of triangles in current block:
|
||||
int length = (size - i * BLOCKSIZE) % BLOCKSIZE;
|
||||
|
||||
for (int j = 0; j < length; j++)
|
||||
{
|
||||
block[j] = null;
|
||||
}
|
||||
}
|
||||
|
||||
size = count = 0;
|
||||
}
|
||||
|
||||
public bool Contains(Triangle item)
|
||||
{
|
||||
int i = item.hash;
|
||||
|
||||
if (i < 0 || i > size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return pool[i / BLOCKSIZE][i % BLOCKSIZE].hash >= 0;
|
||||
}
|
||||
|
||||
public void CopyTo(Triangle[] array, int index)
|
||||
{
|
||||
var enumerator = GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
array[index] = enumerator.Current;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return count - stack.Count; }
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public bool Remove(Triangle item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<Triangle> GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
class Enumerator : IEnumerator<Triangle>
|
||||
{
|
||||
// TODO: enumerator should be able to tell if collection changed.
|
||||
|
||||
int count;
|
||||
|
||||
Triangle[][] pool;
|
||||
|
||||
Triangle current;
|
||||
|
||||
int index, offset;
|
||||
|
||||
public Enumerator(TrianglePool pool)
|
||||
{
|
||||
this.count = pool.Count;
|
||||
this.pool = pool.pool;
|
||||
|
||||
index = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
public Triangle Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
object System.Collections.IEnumerator.Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
while (index < count)
|
||||
{
|
||||
current = pool[offset / BLOCKSIZE][offset % BLOCKSIZE];
|
||||
|
||||
offset++;
|
||||
|
||||
if (current.hash >= 0)
|
||||
{
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
Point pt;
|
||||
|
||||
// Compue triangle circumcenters
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
Osub sub1 = default(Osub);
|
||||
|
||||
// Tag all triangles non-blind
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
// Use the infected flag for 'blinded' attribute.
|
||||
t.infected = false;
|
||||
@@ -442,7 +442,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// Add midpoint of start triangles' edge.
|
||||
torg = f.Org();
|
||||
tdest = f.Dest();
|
||||
p = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2);
|
||||
p = new Point((torg.x + tdest.x) / 2, (torg.y + tdest.y) / 2);
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
@@ -466,7 +466,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// been added, so post process cell to remove duplicates???)
|
||||
torg = f.Org();
|
||||
tapex = f.Apex();
|
||||
p = new Point((torg.X + tapex.X) / 2, (torg.Y + tapex.Y) / 2);
|
||||
p = new Point((torg.x + tapex.x) / 2, (torg.y + tapex.y) / 2);
|
||||
|
||||
p.id = n + segIndex++;
|
||||
segPoints.Add(p);
|
||||
@@ -515,7 +515,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// have to add the intersection with the segment.
|
||||
|
||||
// Center of f edge dest->apex
|
||||
Point bisec = new Point((tdest.X + tapex.X) / 2, (tdest.Y + tapex.Y) / 2);
|
||||
Point bisec = new Point((tdest.x + tapex.x) / 2, (tdest.y + tapex.y) / 2);
|
||||
|
||||
// Find intersection of seg with line through f's bisector and circumcenter
|
||||
if (SegmentsIntersect(sorg, sdest, bisec, cc_f, out p, false))
|
||||
@@ -562,7 +562,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
// have to add the intersection with the segment.
|
||||
|
||||
// Center of f_next edge org->dest
|
||||
Point bisec = new Point((torg.X + tdest.X) / 2, (torg.Y + tdest.Y) / 2);
|
||||
Point bisec = new Point((torg.x + tdest.x) / 2, (torg.y + tdest.y) / 2);
|
||||
|
||||
// Find intersection of seg with line through f_next's bisector and circumcenter
|
||||
if (SegmentsIntersect(sorg, sdest, bisec, cc_f_next, out p, false))
|
||||
@@ -602,12 +602,12 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
/// </returns>
|
||||
private bool SegmentsIntersect(Point p1, Point p2, Point p3, Point p4, out Point p, bool strictIntersect)
|
||||
{
|
||||
p = null;
|
||||
p = null; // TODO: Voronoi SegmentsIntersect
|
||||
|
||||
double Ax = p1.X, Ay = p1.Y;
|
||||
double Bx = p2.X, By = p2.Y;
|
||||
double Cx = p3.X, Cy = p3.Y;
|
||||
double Dx = p4.X, Dy = p4.Y;
|
||||
double Ax = p1.x, Ay = p1.y;
|
||||
double Bx = p2.x, By = p2.y;
|
||||
double Cx = p3.x, Cy = p3.y;
|
||||
double Dx = p4.x, Dy = p4.y;
|
||||
|
||||
double distAB, theCos, theSin, newX, ABpos;
|
||||
|
||||
@@ -674,7 +674,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
}
|
||||
else
|
||||
{
|
||||
edges.Add(new Edge(last.ID, pt.ID));
|
||||
edges.Add(new Edge(last.id, pt.id));
|
||||
|
||||
last = pt;
|
||||
}
|
||||
@@ -682,7 +682,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
|
||||
if (region.Bounded && first != null)
|
||||
{
|
||||
edges.Add(new Edge(last.ID, first.ID));
|
||||
edges.Add(new Edge(last.id, first.id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace TriangleNet.Voronoi.Legacy
|
||||
Point pt;
|
||||
|
||||
// Compue triangle circumcenters
|
||||
foreach (var item in mesh.triangles.Values)
|
||||
foreach (var item in mesh.triangles)
|
||||
{
|
||||
tri.tri = item;
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace TriangleNet.Voronoi
|
||||
/// <param name="generate">If set to true, the constuctor will call the Generate
|
||||
/// method, which builds the Voronoi diagram.</param>
|
||||
protected VoronoiBase(Mesh mesh, IVoronoiFactory factory, IPredicates predicates,
|
||||
bool generate) : base(false)
|
||||
bool generate)
|
||||
: base(false)
|
||||
{
|
||||
this.factory = factory;
|
||||
this.predicates = predicates;
|
||||
@@ -105,7 +106,7 @@ namespace TriangleNet.Voronoi
|
||||
var map = new List<HalfEdge>[mesh.triangles.Count];
|
||||
|
||||
// Compue triangle circumcenters
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
id = t.id;
|
||||
tri.tri = t;
|
||||
@@ -152,7 +153,7 @@ namespace TriangleNet.Voronoi
|
||||
// to the edge, operate on the edge. If there is another adjacent triangle,
|
||||
// operate on the edge only if the current triangle has a smaller id than
|
||||
// its neighbor. This way, each edge is considered only once.
|
||||
foreach (var t in mesh.triangles.Values)
|
||||
foreach (var t in mesh.triangles)
|
||||
{
|
||||
id = t.id;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user