diff --git a/Triangle.NET/TestApp/FormMain.cs b/Triangle.NET/TestApp/FormMain.cs index d466434..08bde6f 100644 --- a/Triangle.NET/TestApp/FormMain.cs +++ b/Triangle.NET/TestApp/FormMain.cs @@ -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 diff --git a/Triangle.NET/Triangle.Rendering/GDI/RenderControl.cs b/Triangle.NET/Triangle.Rendering/GDI/RenderControl.cs index d707e50..2dfda4a 100644 --- a/Triangle.NET/Triangle.Rendering/GDI/RenderControl.cs +++ b/Triangle.NET/Triangle.Rendering/GDI/RenderControl.cs @@ -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; /// @@ -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(); - } - } - - /// - /// Zoom to the given location. - /// - /// The zoom focus. - /// Indicates whether to zoom in or out. - 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(); - } - } - /// /// Update graphics buffer and zoom after a resize. /// 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 } } diff --git a/Triangle.NET/Triangle.Rendering/IRenderControl.cs b/Triangle.NET/Triangle.Rendering/IRenderControl.cs index 95a3b37..da85e8e 100644 --- a/Triangle.NET/Triangle.Rendering/IRenderControl.cs +++ b/Triangle.NET/Triangle.Rendering/IRenderControl.cs @@ -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(); } } diff --git a/Triangle.NET/Triangle.Rendering/Projection.cs b/Triangle.NET/Triangle.Rendering/Projection.cs index 43e37a9..6dd8118 100644 --- a/Triangle.NET/Triangle.Rendering/Projection.cs +++ b/Triangle.NET/Triangle.Rendering/Projection.cs @@ -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; } + /// + /// Inititialize the projection. + /// + /// The world that should be transformed to screen coordinates. 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; } + /// + /// Handle resize of the screen. + /// + /// The new screen dimensions. + 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; + } + /// /// Zoom in or out of the viewport. /// diff --git a/Triangle.NET/Triangle.Rendering/RenderManager.cs b/Triangle.NET/Triangle.Rendering/RenderManager.cs index c0352d5..1337185 100644 --- a/Triangle.NET/Triangle.Rendering/RenderManager.cs +++ b/Triangle.NET/Triangle.Rendering/RenderManager.cs @@ -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); diff --git a/Triangle.NET/Triangle/Configuration.cs b/Triangle.NET/Triangle/Configuration.cs new file mode 100644 index 0000000..6dcb8e4 --- /dev/null +++ b/Triangle.NET/Triangle/Configuration.cs @@ -0,0 +1,44 @@ +// ----------------------------------------------------------------------- +// +// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/ +// +// ----------------------------------------------------------------------- + +namespace TriangleNet +{ + using System; + using TriangleNet.Meshing; + using TriangleNet.Meshing.Algorithm; + + /// + /// Configure advanced aspects of the library. + /// + public class Configuration + { + public Configuration() + : this(() => RobustPredicates.Default, () => new TrianglePool()) + { + } + + public Configuration(Func predicates) + : this(predicates, () => new TrianglePool()) + { + } + + public Configuration(Func predicates, Func trianglePool) + { + Predicates = predicates; + TrianglePool = trianglePool; + } + + /// + /// Gets or sets the factory method for the implementation. + /// + public Func Predicates { get; set; } + + /// + /// Gets or sets the factory method for the . + /// + public Func TrianglePool { get; set; } + } +} diff --git a/Triangle.NET/Triangle/Geometry/Contour.cs b/Triangle.NET/Triangle/Geometry/Contour.cs index fe7e35c..f3d0ac8 100644 --- a/Triangle.NET/Triangle/Geometry/Contour.cs +++ b/Triangle.NET/Triangle/Geometry/Contour.cs @@ -8,7 +8,7 @@ namespace TriangleNet.Geometry { using System; using System.Collections.Generic; - + public class Contour { int marker; diff --git a/Triangle.NET/Triangle/Geometry/ExtensionMethods.cs b/Triangle.NET/Triangle/Geometry/ExtensionMethods.cs index 12736ac..9087adb 100644 --- a/Triangle.NET/Triangle/Geometry/ExtensionMethods.cs +++ b/Triangle.NET/Triangle/Geometry/ExtensionMethods.cs @@ -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 + + /// + /// Test whether a given point lies inside a triangle or not. + /// + /// Point to locate. + /// True, if point is inside or on the edge of this triangle. + public static bool Contains(this ITriangle triangle, Point p) + { + return Contains(triangle, p.X, p.Y); + } + + /// + /// Test whether a given point lies inside a triangle or not. + /// + /// Point to locate. + /// Point to locate. + /// True, if point is inside or on the edge of this triangle. + 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 } } diff --git a/Triangle.NET/Triangle/Geometry/Polygon.cs b/Triangle.NET/Triangle/Geometry/Polygon.cs index 82447ab..96d7106 100644 --- a/Triangle.NET/Triangle/Geometry/Polygon.cs +++ b/Triangle.NET/Triangle/Geometry/Polygon.cs @@ -121,21 +121,12 @@ namespace TriangleNet.Geometry this.points.Add(vertex); } - /// - /// Add a segment to the polygon. - /// - /// The segment to insert. - public void Add(ISegment segment) - { - this.segments.Add(segment); - } - /// /// Add a segment to the polygon. /// /// The segment to insert. /// If true, both endpoints will be added to the points list. - public void Add(ISegment segment, bool insert) + public void Add(ISegment segment, bool insert = false) { this.segments.Add(segment); diff --git a/Triangle.NET/Triangle/Geometry/Rectangle.cs b/Triangle.NET/Triangle/Geometry/Rectangle.cs index fe309c3..37df152 100644 --- a/Triangle.NET/Triangle/Geometry/Rectangle.cs +++ b/Triangle.NET/Triangle/Geometry/Rectangle.cs @@ -10,7 +10,7 @@ namespace TriangleNet.Geometry using System.Collections.Generic; /// - /// A simple bounding box class. + /// A simple rectangle class. /// public class Rectangle { @@ -79,7 +79,7 @@ namespace TriangleNet.Geometry } /// - /// Gets the width of the bounding box. + /// Gets the width of the rectangle. /// public double Width { @@ -87,7 +87,7 @@ namespace TriangleNet.Geometry } /// - /// Gets the height of the bounding box. + /// Gets the height of the rectangle. /// public double Height { @@ -144,20 +144,31 @@ namespace TriangleNet.Geometry } /// - /// Check if given point is inside bounding box. + /// Check if given point is inside rectangle. /// - /// Point to check. - /// Return true, if bounding box contains given point. - public bool Contains(Point pt) + /// Point to check. + /// Point to check. + /// Return true, if rectangle contains given point. + 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)); } /// - /// Check if given rectangle is inside bounding box. + /// Check if given point is inside rectangle. + /// + /// Point to check. + /// Return true, if rectangle contains given point. + public bool Contains(Point pt) + { + return Contains(pt.x, pt.y); + } + + /// + /// Check if this rectangle contains other rectangle. /// /// Rectangle to check. - /// Return true, if bounding box contains given rectangle. + /// Return true, if this rectangle contains given rectangle. public bool Contains(Rectangle other) { return (xmin <= other.Left && other.Right <= xmax @@ -165,10 +176,10 @@ namespace TriangleNet.Geometry } /// - /// Check if given rectangle intersects bounding box. + /// Check if this rectangle intersects other rectangle. /// /// Rectangle to check. - /// Return true, if given rectangle intersects bounding box. + /// Return true, if given rectangle intersects this rectangle. public bool Intersects(Rectangle other) { return (other.Left < xmax && xmin < other.Right diff --git a/Triangle.NET/Triangle/Geometry/Vertex.cs b/Triangle.NET/Triangle/Geometry/Vertex.cs index 49f1b58..bb817f9 100644 --- a/Triangle.NET/Triangle/Geometry/Vertex.cs +++ b/Triangle.NET/Triangle/Geometry/Vertex.cs @@ -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 /// /// Initializes a new instance of the class. diff --git a/Triangle.NET/Triangle/IO/DebugWriter.cs b/Triangle.NET/Triangle/IO/DebugWriter.cs index 0c7a215..717c5ad 100644 --- a/Triangle.NET/Triangle/IO/DebugWriter.cs +++ b/Triangle.NET/Triangle/IO/DebugWriter.cs @@ -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); diff --git a/Triangle.NET/Triangle/IO/TriangleFormat.cs b/Triangle.NET/Triangle/IO/TriangleFormat.cs index 58f18d3..0c50d27 100644 --- a/Triangle.NET/Triangle/IO/TriangleFormat.cs +++ b/Triangle.NET/Triangle/IO/TriangleFormat.cs @@ -38,7 +38,7 @@ namespace TriangleNet.IO List 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) diff --git a/Triangle.NET/Triangle/IO/TriangleReader.cs b/Triangle.NET/Triangle/IO/TriangleReader.cs index 43a1dec..d769196 100644 --- a/Triangle.NET/Triangle/IO/TriangleReader.cs +++ b/Triangle.NET/Triangle/IO/TriangleReader.cs @@ -16,14 +16,14 @@ namespace TriangleNet.IO /// /// Helper methods for reading Triangle file formats. /// - 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 /// The current line. /// Number of point attributes /// Number of point markers (0 or 1) - static void ReadVertex(List data, int index, string[] line, int attributes, int marks) + private void ReadVertex(List 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 /// /// Reads geometry information from .node or .poly files. /// - 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); } } /// /// Reads a mesh from .node, .poly or .ele files. /// - public static void Read(string filename, out Polygon geometry, out List triangles) + public void Read(string filename, out Polygon geometry, out List 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); } } /// /// Reads geometry information from .node or .poly files. /// - 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 /// /// /// Will NOT read associated .ele by default. - public static Polygon ReadNodeFile(string nodefilename) + public Polygon ReadNodeFile(string nodefilename) { return ReadNodeFile(nodefilename, false); } @@ -161,7 +161,7 @@ namespace TriangleNet.IO /// /// /// - 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 /// /// /// Will NOT read associated .ele by default. - public static Polygon ReadPolyFile(string polyfilename) + public Polygon ReadPolyFile(string polyfilename) { return ReadPolyFile(polyfilename, false, false); } @@ -260,7 +260,7 @@ namespace TriangleNet.IO /// /// If true, look for an associated .ele file. /// Will NOT read associated .area by default. - 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 /// /// If true, look for an associated .ele file. /// If true, look for an associated .area file. - 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 /// /// The file name. /// A list of triangles. - public static List ReadEleFile(string elefilename) + public List ReadEleFile(string elefilename) { return ReadEleFile(elefilename, false); } @@ -499,13 +499,13 @@ namespace TriangleNet.IO /// /// /// - private static List ReadEleFile(string elefilename, bool readArea) + private List ReadEleFile(string elefilename, bool readArea) { int intriangles = 0, attributes = 0; List 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 /// /// /// - 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 /// The file name. /// The number of input vertices (read from a .node or .poly file). /// A List of edges. - public static List ReadEdgeFile(string edgeFile, int invertices) + public List ReadEdgeFile(string edgeFile, int invertices) { // Read poly file List 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. diff --git a/Triangle.NET/Triangle/IO/TriangleWriter.cs b/Triangle.NET/Triangle/IO/TriangleWriter.cs index 976ab9c..c0a0d3a 100644 --- a/Triangle.NET/Triangle/IO/TriangleWriter.cs +++ b/Triangle.NET/Triangle/IO/TriangleWriter.cs @@ -16,19 +16,19 @@ namespace TriangleNet.IO /// /// Helper methods for writing Triangle file formats. /// - public static class TriangleWriter + public class TriangleWriter { - static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat; + static NumberFormatInfo nfi = NumberFormatInfo.InvariantInfo; /// /// Number the vertices and write them to a .node file. /// /// /// - 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")); } /// @@ -36,18 +36,18 @@ namespace TriangleNet.IO /// /// /// - 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); } } /// /// Number the vertices and write them to a .node file. /// - 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 /// /// /// - private static void WriteNodes(StreamWriter writer, IEnumerable nodes, bool markers, + private void WriteNodes(StreamWriter writer, IEnumerable nodes, bool markers, int attribs, bool jettison) { int index = 0; @@ -140,7 +140,7 @@ namespace TriangleNet.IO /// /// /// - 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 /// 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. - 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 /// /// /// - public static void WritePoly(Mesh mesh, string filename) + public void WritePoly(Mesh mesh, string filename) { - TriangleWriter.WritePoly(mesh, filename, true); + WritePoly(mesh, filename, true); } /// @@ -268,19 +268,19 @@ namespace TriangleNet.IO /// 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. - 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 /// /// /// - 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 /// /// WARNING: Be sure WriteElements has been called before, /// so the elements are numbered right! - 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; diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs index f4b0808..24d24ea 100644 --- a/Triangle.NET/Triangle/Mesh.cs +++ b/Triangle.NET/Triangle/Mesh.cs @@ -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 triangles; + internal TrianglePool triangles; internal Dictionary subsegs; internal Dictionary vertices; @@ -107,7 +107,7 @@ namespace TriangleNet /// public ICollection Triangles { - get { return this.triangles.Values; } + get { return this.triangles; } } /// @@ -232,7 +232,7 @@ namespace TriangleNet /// /// Initializes a new instance of the class. /// - public Mesh(IPredicates predicates) + public Mesh(Configuration config) { Initialize(); @@ -241,9 +241,10 @@ namespace TriangleNet behavior = new Behavior(); vertices = new Dictionary(); - triangles = new Dictionary(); subsegs = new Dictionary(); + triangles = config.TrianglePool(); + flipstack = new Stack(); holes = new List(); @@ -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 /// Reference to the new triangle. 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); } /// @@ -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); } /// diff --git a/Triangle.NET/Triangle/MeshValidator.cs b/Triangle.NET/Triangle/MeshValidator.cs index 64bad8b..d6e4982 100644 --- a/Triangle.NET/Triangle/MeshValidator.cs +++ b/Triangle.NET/Triangle/MeshValidator.cs @@ -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; diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs index ab79c62..a3e7cbb 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/Dwyer.cs @@ -55,16 +55,6 @@ namespace TriangleNet.Meshing.Algorithm Vertex[] sortarray; Mesh mesh; - public Dwyer() - : this(RobustPredicates.Default) - { - } - - public Dwyer(IPredicates predicates) - { - this.predicates = predicates; - } - /// /// Form a Delaunay triangulation by the divide-and-conquer method. /// @@ -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. /// - public IMesh Triangulate(IList points) + public IMesh Triangulate(IList 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; diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs b/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs index 9a7fc7d..3686fa4 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/Incremental.cs @@ -16,28 +16,16 @@ namespace TriangleNet.Meshing.Algorithm /// public class Incremental : ITriangulator { - IPredicates predicates; - Mesh mesh; - public Incremental() - : this(RobustPredicates.Default) - { - } - - public Incremental(IPredicates predicates) - { - this.predicates = predicates; - } - /// /// Form a Delaunay triangulation by incrementally inserting vertices. /// /// Returns the number of edges on the convex hull of the /// triangulation. - public IMesh Triangulate(IList points) + public IMesh Triangulate(IList points, Configuration config) { - this.mesh = new Mesh(predicates); + this.mesh = new Mesh(config); this.mesh.TransferNodes(points); Otri starttri = new Otri(); diff --git a/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs b/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs index 31c1ba3..bce274d 100644 --- a/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs +++ b/Triangle.NET/Triangle/Meshing/Algorithm/SweepLine.cs @@ -33,19 +33,11 @@ namespace TriangleNet.Meshing.Algorithm double xminextreme; // Nonexistent x value used as a flag in sweepline. List splaynodes; - public SweepLine() - : this(RobustPredicates.Default) + public IMesh Triangulate(IList points, Configuration config) { - } + this.predicates = config.Predicates(); - public SweepLine(IPredicates predicates) - { - this.predicates = predicates; - } - - public IMesh Triangulate(IList 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 diff --git a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs index c13d98d..548b4be 100644 --- a/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs +++ b/Triangle.NET/Triangle/Meshing/ConstraintMesher.cs @@ -26,10 +26,10 @@ namespace TriangleNet.Meshing ILog 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 /// - /// Triangulate given input data. + /// Insert segments into the mesh. /// - /// + /// The polygon. + /// Constraint options. 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); } } } diff --git a/Triangle.NET/Triangle/Meshing/Converter.cs b/Triangle.NET/Triangle/Meshing/Converter.cs index af7b024..e8cba91 100644 --- a/Triangle.NET/Triangle/Meshing/Converter.cs +++ b/Triangle.NET/Triangle/Meshing/Converter.cs @@ -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(); - foreach (var t in mesh.triangles.Values) + foreach (var t in mesh.triangles) { id = t.id; diff --git a/Triangle.NET/Triangle/Meshing/GenericMesher.cs b/Triangle.NET/Triangle/Meshing/GenericMesher.cs index 9a19358..74f1019 100644 --- a/Triangle.NET/Triangle/Meshing/GenericMesher.cs +++ b/Triangle.NET/Triangle/Meshing/GenericMesher.cs @@ -15,33 +15,36 @@ namespace TriangleNet.Meshing /// /// Create meshes of point sets or polygons. /// - 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; } /// public IMesh Triangulate(IList points) { - return triangulator.Triangulate(points); + return triangulator.Triangulate(points, config); } /// @@ -65,10 +68,10 @@ namespace TriangleNet.Meshing /// 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); diff --git a/Triangle.NET/Triangle/Meshing/ITriangulator.cs b/Triangle.NET/Triangle/Meshing/ITriangulator.cs index a8139bd..5bc1541 100644 --- a/Triangle.NET/Triangle/Meshing/ITriangulator.cs +++ b/Triangle.NET/Triangle/Meshing/ITriangulator.cs @@ -18,7 +18,8 @@ namespace TriangleNet.Meshing /// Triangulates a point set. /// /// Collection of points. + /// /// Mesh - IMesh Triangulate(IList points); + IMesh Triangulate(IList points, Configuration config); } } diff --git a/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs b/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs index ebacb1a..1b247f4 100644 --- a/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs +++ b/Triangle.NET/Triangle/Meshing/Iterators/EdgeIterator.cs @@ -27,7 +27,7 @@ namespace TriangleNet.Meshing.Iterators /// public EdgeIterator(Mesh mesh) { - triangles = mesh.triangles.Values.GetEnumerator(); + triangles = mesh.triangles.GetEnumerator(); triangles.MoveNext(); tri.tri = triangles.Current; diff --git a/Triangle.NET/Triangle/Meshing/QualityMesher.cs b/Triangle.NET/Triangle/Meshing/QualityMesher.cs index 3d39216..f7f76c0 100644 --- a/Triangle.NET/Triangle/Meshing/QualityMesher.cs +++ b/Triangle.NET/Triangle/Meshing/QualityMesher.cs @@ -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; /// @@ -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 } /// - /// Triangulate given input data. + /// Apply quality constraints to a mesh. /// - /// + /// The quality constraints. 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; diff --git a/Triangle.NET/Triangle/NewLocation.cs b/Triangle.NET/Triangle/NewLocation.cs index 204248a..e45264d 100644 --- a/Triangle.NET/Triangle/NewLocation.cs +++ b/Triangle.NET/Triangle/NewLocation.cs @@ -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; diff --git a/Triangle.NET/Triangle/Sampler.cs b/Triangle.NET/Triangle/Sampler.cs index bc94aca..b590224 100644 --- a/Triangle.NET/Triangle/Sampler.cs +++ b/Triangle.NET/Triangle/Sampler.cs @@ -9,17 +9,18 @@ namespace TriangleNet { using System; using System.Collections.Generic; - using System.Linq; + using TriangleNet.Topology; /// /// Used for triangle sampling in the class. /// - class Sampler + class Sampler : IEnumerable { // 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. /// /// Current mesh. - public void Update(Mesh mesh) - { - this.Update(mesh, false); - } - - /// - /// Update sampling parameters if mesh changed. - /// - /// Current mesh. - 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(); } } - /// - /// Get a random sample set of triangle keys. - /// - /// Array of triangle keys. - public int[] GetSamples(Mesh mesh) + public IEnumerator GetEnumerator() { - // TODO: Using currKeys to check key availability? - List randSamples = new List(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(); } } } diff --git a/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs b/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs index 3031b1a..7c4d7c8 100644 --- a/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs +++ b/Triangle.NET/Triangle/Tools/AdjacencyMatrix.cs @@ -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; diff --git a/Triangle.NET/Triangle/Tools/IntersectionHelper.cs b/Triangle.NET/Triangle/Tools/IntersectionHelper.cs index 42e6ffd..afb4aeb 100644 --- a/Triangle.NET/Triangle/Tools/IntersectionHelper.cs +++ b/Triangle.NET/Triangle/Tools/IntersectionHelper.cs @@ -8,8 +8,6 @@ namespace TriangleNet.Tools { using TriangleNet.Geometry; - using Vertex = TriangleNet.Topology.DCEL.Vertex; - public static class IntersectionHelper { /// @@ -47,8 +45,8 @@ namespace TriangleNet.Tools /// The clip rectangle. /// Segment endpoint. /// Segment endpoint. - /// The new location of p0 (DCEL vertex). - /// The new location of p1 (DCEL vertex). + /// The new location of p0. + /// The new location of p1. /// Returns true, if segment is clipped. /// /// Based on Liang-Barsky function by Daniel White: @@ -111,7 +109,7 @@ namespace TriangleNet.Tools /// The clip rectangle. /// The ray startpoint (inside the box). /// Any point in ray direction (NOT the direction vector). - /// The intersection point (DCEL vertex). + /// The intersection point. /// Returns false, if startpoint is outside the box. public static bool BoxRayIntersection(Rectangle rect, Point p0, Point p1, ref Point c1) { diff --git a/Triangle.NET/Triangle/Tools/QualityMeasure.cs b/Triangle.NET/Triangle/Tools/QualityMeasure.cs index 9c8acfc..50abfe8 100644 --- a/Triangle.NET/Triangle/Tools/QualityMeasure.cs +++ b/Triangle.NET/Triangle/Tools/QualityMeasure.cs @@ -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++) { diff --git a/Triangle.NET/Triangle/Tools/Statistic.cs b/Triangle.NET/Triangle/Tools/Statistic.cs index f1515ae..1f8c8a3 100644 --- a/Triangle.NET/Triangle/Tools/Statistic.cs +++ b/Triangle.NET/Triangle/Tools/Statistic.cs @@ -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 diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj index d451d4b..d3a23f5 100644 --- a/Triangle.NET/Triangle/Triangle.csproj +++ b/Triangle.NET/Triangle/Triangle.csproj @@ -40,6 +40,7 @@ + @@ -101,6 +102,7 @@ + diff --git a/Triangle.NET/Triangle/TriangleLocator.cs b/Triangle.NET/Triangle/TriangleLocator.cs index 275c8c5..cc9f2f7 100644 --- a/Triangle.NET/Triangle/TriangleLocator.cs +++ b/Triangle.NET/Triangle/TriangleLocator.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(); diff --git a/Triangle.NET/Triangle/TrianglePool.cs b/Triangle.NET/Triangle/TrianglePool.cs new file mode 100644 index 0000000..331d70b --- /dev/null +++ b/Triangle.NET/Triangle/TrianglePool.cs @@ -0,0 +1,305 @@ +// ----------------------------------------------------------------------- +// +// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/ +// +// ----------------------------------------------------------------------- + +namespace TriangleNet +{ + using System; + using System.Collections.Generic; + using TriangleNet.Geometry; + using TriangleNet.Topology; + + public class TrianglePool : ICollection + { + // 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 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(BLOCKSIZE); + } + + /// + /// Gets a triangle from the pool. + /// + /// + 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; + } + + /// + /// Restart the triangle pool. + /// + public TrianglePool Restart() + { + foreach (var triangle in stack) + { + // Reset hash to original value. + triangle.hash = -triangle.hash - 1; + } + + stack.Clear(); + + count = 0; + + return this; + } + + /// + /// Samples a number of triangles from the pool. + /// + /// The number of triangles to sample. + /// + /// + internal IEnumerable 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 GetEnumerator() + { + return new Enumerator(this); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + class Enumerator : IEnumerator + { + // 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; + } + } + } +} diff --git a/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs b/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs index 6622e54..643fa0b 100644 --- a/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs +++ b/Triangle.NET/Triangle/Voronoi/Legacy/BoundedVoronoiLegacy.cs @@ -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 /// 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)); } } diff --git a/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs b/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs index 5f67d43..c65ffa0 100644 --- a/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs +++ b/Triangle.NET/Triangle/Voronoi/Legacy/SimpleVoronoi.cs @@ -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; diff --git a/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs b/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs index 7226905..0122d71 100644 --- a/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs +++ b/Triangle.NET/Triangle/Voronoi/VoronoiBase.cs @@ -37,7 +37,8 @@ namespace TriangleNet.Voronoi /// If set to true, the constuctor will call the Generate /// method, which builds the Voronoi diagram. 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[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;