diff --git a/Triangle.NET/TestApp/FormMain.Designer.cs b/Triangle.NET/TestApp/FormMain.Designer.cs
index a6437c1..fa68f8d 100644
--- a/Triangle.NET/TestApp/FormMain.Designer.cs
+++ b/Triangle.NET/TestApp/FormMain.Designer.cs
@@ -55,6 +55,8 @@
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
this.menuToolsRcm = new System.Windows.Forms.ToolStripMenuItem();
this.btnMesh = new MeshExplorer.Controls.DarkButton();
+ this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
+ this.menuToolsTopology = new System.Windows.Forms.ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.SuspendLayout();
@@ -285,6 +287,8 @@
this.menuTools.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.menuToolsGen,
this.menuToolsCheck,
+ this.toolStripSeparator5,
+ this.menuToolsTopology,
this.toolStripSeparator4,
this.menuToolsRcm});
this.menuTools.Name = "menuTools";
@@ -330,6 +334,18 @@
this.btnMesh.UseVisualStyleBackColor = true;
this.btnMesh.Click += new System.EventHandler(this.btnMesh_Click);
//
+ // toolStripSeparator5
+ //
+ this.toolStripSeparator5.Name = "toolStripSeparator5";
+ this.toolStripSeparator5.Size = new System.Drawing.Size(192, 6);
+ //
+ // menuToolsTopology
+ //
+ this.menuToolsTopology.Name = "menuToolsTopology";
+ this.menuToolsTopology.Size = new System.Drawing.Size(195, 22);
+ this.menuToolsTopology.Text = "Topology Explorer";
+ this.menuToolsTopology.Click += new System.EventHandler(this.menuToolsTopology_Click);
+ //
// FormMain
//
this.AllowDrop = true;
@@ -394,6 +410,8 @@
private Views.MeshControlView meshControlView;
private Views.StatisticView statisticView;
private Views.AboutView aboutView;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator5;
+ private System.Windows.Forms.ToolStripMenuItem menuToolsTopology;
}
}
diff --git a/Triangle.NET/TestApp/FormMain.cs b/Triangle.NET/TestApp/FormMain.cs
index ae13757..0ab4a8c 100644
--- a/Triangle.NET/TestApp/FormMain.cs
+++ b/Triangle.NET/TestApp/FormMain.cs
@@ -738,6 +738,11 @@ namespace MeshExplorer
}
}
+ private void menuToolsTopology_Click(object sender, EventArgs e)
+ {
+ (new FormTopology()).ShowDialog(this);
+ }
+
private void menuToolsRcm_Click(object sender, EventArgs e)
{
Renumber();
diff --git a/Triangle.NET/TestApp/FormTopology.Designer.cs b/Triangle.NET/TestApp/FormTopology.Designer.cs
new file mode 100644
index 0000000..5d95f85
--- /dev/null
+++ b/Triangle.NET/TestApp/FormTopology.Designer.cs
@@ -0,0 +1,112 @@
+namespace MeshExplorer
+{
+ partial class FormTopology
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+ this.renderControl = new MeshExplorer.Topology.TopologyRenderControl();
+ this.topoControlView = new MeshExplorer.Topology.TopologyControlView();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+ this.splitContainer1.Panel1.SuspendLayout();
+ this.splitContainer1.Panel2.SuspendLayout();
+ this.splitContainer1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // splitContainer1
+ //
+ this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.splitContainer1.IsSplitterFixed = true;
+ this.splitContainer1.Location = new System.Drawing.Point(0, 0);
+ this.splitContainer1.Name = "splitContainer1";
+ //
+ // splitContainer1.Panel1
+ //
+ this.splitContainer1.Panel1.Controls.Add(this.renderControl);
+ //
+ // splitContainer1.Panel2
+ //
+ this.splitContainer1.Panel2.Controls.Add(this.topoControlView);
+ this.splitContainer1.Size = new System.Drawing.Size(674, 455);
+ this.splitContainer1.SplitterDistance = 475;
+ this.splitContainer1.SplitterWidth = 1;
+ this.splitContainer1.TabIndex = 0;
+ //
+ // renderControl
+ //
+ this.renderControl.BackColor = System.Drawing.Color.Black;
+ this.renderControl.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.renderControl.Location = new System.Drawing.Point(0, 0);
+ this.renderControl.Name = "renderControl";
+ this.renderControl.Size = new System.Drawing.Size(475, 455);
+ this.renderControl.TabIndex = 0;
+ this.renderControl.Text = "topologyRenderControl";
+ this.renderControl.MouseClick += new System.Windows.Forms.MouseEventHandler(this.renderControl_MouseClick);
+ //
+ // topoControlView
+ //
+ this.topoControlView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.topoControlView.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.topoControlView.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.topoControlView.ForeColor = System.Drawing.Color.White;
+ this.topoControlView.Location = new System.Drawing.Point(0, 0);
+ this.topoControlView.Name = "topoControlView";
+ this.topoControlView.Size = new System.Drawing.Size(198, 455);
+ this.topoControlView.TabIndex = 2;
+ //
+ // FormTopology
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.ClientSize = new System.Drawing.Size(674, 455);
+ this.Controls.Add(this.splitContainer1);
+ this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.ForeColor = System.Drawing.Color.White;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "FormTopology";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.Text = "Triangle.NET - Topology Explorer";
+ this.Load += new System.EventHandler(this.FormTopology_Load);
+ this.splitContainer1.Panel1.ResumeLayout(false);
+ this.splitContainer1.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+ this.splitContainer1.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.SplitContainer splitContainer1;
+ private Topology.TopologyRenderControl renderControl;
+ private Topology.TopologyControlView topoControlView;
+ }
+}
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/FormTopology.cs b/Triangle.NET/TestApp/FormTopology.cs
new file mode 100644
index 0000000..045db86
--- /dev/null
+++ b/Triangle.NET/TestApp/FormTopology.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using MeshExplorer.Topology;
+using TriangleNet;
+using TriangleNet.Geometry;
+using TriangleNet.Tools;
+
+namespace MeshExplorer
+{
+ public partial class FormTopology : Form
+ {
+ Mesh mesh;
+ QuadTree tree;
+ OrientedTriangle current;
+
+ public FormTopology()
+ {
+ InitializeComponent();
+ }
+
+ private void FormTopology_Load(object sender, EventArgs e)
+ {
+ var geometry = RectanglePolygon.Generate(4);
+
+ mesh = new Mesh();
+ mesh.Triangulate(geometry);
+
+ renderControl.Initialize(mesh);
+
+ topoControlView.PrimitiveCommandInvoked += PrimitiveCommandHandler;
+
+ current = new OrientedTriangle();
+ }
+
+ void PrimitiveCommandHandler(object sender, GenericEventArgs e)
+ {
+ if (current.Triangle != null)
+ {
+ InvokePrimitive(e.Argument);
+ }
+ }
+
+ private void renderControl_MouseClick(object sender, MouseEventArgs e)
+ {
+ var p = e.Location;
+ var size = renderControl.Size;
+
+ var tri = FindTriangleAt(((float)p.X) / size.Width, ((float)p.Y) / size.Height);
+
+ current.Triangle = tri;
+ current.Orientation = 0;
+
+ renderControl.Update(current);
+
+ topoControlView.SetTriangle(current);
+ }
+
+ private ITriangle FindTriangleAt(float x, float y)
+ {
+ // Get mesh coordinates
+ var p = renderControl.Zoom.ScreenToWorld(x, y);
+
+ topoControlView.SetPosition(p);
+
+ if (tree == null)
+ {
+ tree = new QuadTree(mesh, 5, 2);
+ }
+
+ return tree.Query(p.X, p.Y);
+ }
+
+ private bool TriangleContainsPoint(ITriangle triangle, float x, float y)
+ {
+ bool t1, t2, t3;
+
+ t1 = Sign(x, y, triangle.GetVertex(0), triangle.GetVertex(1)) < 0.0;
+ t2 = Sign(x, y, triangle.GetVertex(1), triangle.GetVertex(2)) < 0.0;
+ t3 = Sign(x, y, triangle.GetVertex(2), triangle.GetVertex(0)) < 0.0;
+
+ return (t1 == t2) && (t2 == t3);
+ }
+
+ private double Sign(double x, double y, Point p, Point q)
+ {
+ return (x - q.X) * (p.Y - q.Y) - (p.X - q.X) * (y - q.Y);
+ }
+
+
+ private void InvokePrimitive(string name)
+ {
+ if (name == "sym")
+ {
+ current.Sym();
+ }
+ else if (name == "lnext")
+ {
+ current.Lnext();
+ }
+ else if (name == "lprev")
+ {
+ current.Lprev();
+ }
+ else if (name == "onext")
+ {
+ current.Onext();
+ }
+ else if (name == "oprev")
+ {
+ current.Oprev();
+ }
+ else if (name == "dnext")
+ {
+ current.Dnext();
+ }
+ else if (name == "dprev")
+ {
+ current.Dprev();
+ }
+ else if (name == "rnext")
+ {
+ current.Rnext();
+ }
+ else if (name == "rprev")
+ {
+ current.Rprev();
+ }
+
+ renderControl.Update(current);
+ topoControlView.SetTriangle(current);
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/FormTopology.resx b/Triangle.NET/TestApp/FormTopology.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/Triangle.NET/TestApp/FormTopology.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/GenericEventArgs.cs b/Triangle.NET/TestApp/GenericEventArgs.cs
new file mode 100644
index 0000000..9a68171
--- /dev/null
+++ b/Triangle.NET/TestApp/GenericEventArgs.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace MeshExplorer
+{
+ public class GenericEventArgs : EventArgs
+ {
+ T argument;
+
+ public T Argument
+ {
+ get { return argument; }
+ }
+
+ public GenericEventArgs(T arg)
+ {
+ argument = arg;
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Mesh Explorer.csproj b/Triangle.NET/TestApp/Mesh Explorer.csproj
index 3788f9e..785e533 100644
--- a/Triangle.NET/TestApp/Mesh Explorer.csproj
+++ b/Triangle.NET/TestApp/Mesh Explorer.csproj
@@ -96,6 +96,12 @@
FormMain.cs
+
+ Form
+
+
+ FormTopology.cs
+
@@ -104,6 +110,7 @@
+
@@ -116,6 +123,18 @@
+
+
+
+ UserControl
+
+
+ TopologyControlView.cs
+
+
+ Component
+
+
UserControl
@@ -148,6 +167,12 @@
FormMain.cs
+
+ FormTopology.cs
+
+
+ TopologyControlView.cs
+
AboutView.cs
diff --git a/Triangle.NET/TestApp/Topology/OrientedTriangle.cs b/Triangle.NET/TestApp/Topology/OrientedTriangle.cs
new file mode 100644
index 0000000..2b32674
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/OrientedTriangle.cs
@@ -0,0 +1,156 @@
+
+namespace MeshExplorer.Topology
+{
+ using TriangleNet.Data;
+ using TriangleNet.Geometry;
+
+ public class OrientedTriangle
+ {
+ ///
+ ///
+ ///
+ public ITriangle Triangle { get; set; }
+
+ ///
+ /// Ranges from 0 to 2.
+ ///
+ public int Orientation { get; set; }
+
+ #region Oriented triangle primitives
+
+ // For fast access
+ static readonly int[] plus1Mod3 = { 1, 2, 0 };
+ static readonly int[] minus1Mod3 = { 2, 0, 1 };
+
+ ///
+ /// Find the abutting triangle; same edge. [sym(abc) -> ba*]
+ ///
+ public void Sym()
+ {
+ //this = tri.triangles[Orientation];
+ // decode(ptr, otri);
+
+ var org = this.Org();
+ Triangle = Triangle.GetNeighbor(Orientation);
+ Orientation = GetOrientation(Triangle, org.ID);
+ }
+
+ ///
+ /// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca]
+ ///
+ public void Lnext()
+ {
+ Orientation = plus1Mod3[Orientation];
+ }
+
+ ///
+ /// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab]
+ ///
+ public void Lprev()
+ {
+ Orientation = minus1Mod3[Orientation];
+ }
+
+ ///
+ /// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*]
+ ///
+ public void Onext()
+ {
+ Lprev();
+ Sym();
+ }
+
+ ///
+ /// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b]
+ ///
+ public void Oprev()
+ {
+ Sym();
+ Lnext();
+ }
+
+ ///
+ /// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba]
+ ///
+ public void Dnext()
+ {
+ Sym();
+ Lprev();
+ }
+
+ ///
+ /// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*]
+ ///
+ public void Dprev()
+ {
+ Lnext();
+ Sym();
+ }
+
+ ///
+ /// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*]
+ ///
+ public void Rnext()
+ {
+ Sym();
+ Lnext();
+ Sym();
+ }
+
+ ///
+ /// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**]
+ ///
+ public void Rprev()
+ {
+ Sym();
+ Lprev();
+ Sym();
+ }
+
+ ///
+ /// Origin [org(abc) -> a]
+ ///
+ public Vertex Org()
+ {
+ return Triangle.GetVertex(plus1Mod3[Orientation]);
+ }
+
+ ///
+ /// Destination [dest(abc) -> b]
+ ///
+ public Vertex Dest()
+ {
+ return Triangle.GetVertex(minus1Mod3[Orientation]);
+ }
+
+ ///
+ /// Apex [apex(abc) -> c]
+ ///
+ public Vertex Apex()
+ {
+ return Triangle.GetVertex(Orientation);
+ }
+
+ #endregion
+
+ private int GetOrientation(ITriangle tri, int org)
+ {
+ if (tri == null)
+ {
+ return 0;
+ }
+
+ if (tri.P0 == org)
+ {
+ return 1;
+ }
+
+ if (tri.P1 == org)
+ {
+ return 2;
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Topology/RectanglePolygon.cs b/Triangle.NET/TestApp/Topology/RectanglePolygon.cs
new file mode 100644
index 0000000..6deb24b
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/RectanglePolygon.cs
@@ -0,0 +1,47 @@
+
+namespace MeshExplorer.Topology
+{
+ using TriangleNet.Geometry;
+
+ internal static class RectanglePolygon
+ {
+ public static InputGeometry Generate(int n, double bounds = 10.0)
+ {
+ var geometry = new InputGeometry((n + 1) * (n + 1));
+
+ double x, y, d = 2 * bounds / n;
+
+ int mark = 0;
+
+ for (int i = 0; i <= n; i++)
+ {
+ y = -bounds + i * d;
+
+ for (int j = 0; j <= n; j++)
+ {
+ x = -bounds + j * d;
+
+ geometry.AddPoint(x, y, mark);
+ }
+ }
+
+ // Add boundary segments
+ for (int i = 0; i < n; i++)
+ {
+ // Bottom
+ geometry.AddSegment(i, i + 1);
+
+ // Right
+ geometry.AddSegment(i * (n + 1) + n, (i + 1) * (n + 1) + n);
+
+ // Top
+ geometry.AddSegment(n * (n + 1) + i, n * (n + 1) + (i + 1));
+
+ // Left
+ geometry.AddSegment(i * (n + 1), (i + 1) * (n + 1));
+ }
+
+ return geometry;
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Topology/TopologyControlView.Designer.cs b/Triangle.NET/TestApp/Topology/TopologyControlView.Designer.cs
new file mode 100644
index 0000000..69e23f3
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/TopologyControlView.Designer.cs
@@ -0,0 +1,359 @@
+namespace MeshExplorer.Topology
+{
+ partial class TopologyControlView
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.lbS2 = new System.Windows.Forms.Label();
+ this.lbS1 = new System.Windows.Forms.Label();
+ this.lbS0 = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ this.lbN2 = new System.Windows.Forms.Label();
+ this.lbN1 = new System.Windows.Forms.Label();
+ this.lbN0 = new System.Windows.Forms.Label();
+ this.label5 = new System.Windows.Forms.Label();
+ this.lbPosition = new System.Windows.Forms.Label();
+ this.lbV2 = new System.Windows.Forms.Label();
+ this.lbV1 = new System.Windows.Forms.Label();
+ this.lbV0 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.lbTriangle = new System.Windows.Forms.Label();
+ this.darkButton9 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton7 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton5 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton3 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton8 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton6 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton4 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton2 = new MeshExplorer.Controls.DarkButton();
+ this.darkButton1 = new MeshExplorer.Controls.DarkButton();
+ this.SuspendLayout();
+ //
+ // lbS2
+ //
+ this.lbS2.Location = new System.Drawing.Point(137, 122);
+ this.lbS2.Name = "lbS2";
+ this.lbS2.Size = new System.Drawing.Size(53, 13);
+ this.lbS2.TabIndex = 16;
+ this.lbS2.Text = "-";
+ this.lbS2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbS1
+ //
+ this.lbS1.Location = new System.Drawing.Point(137, 107);
+ this.lbS1.Name = "lbS1";
+ this.lbS1.Size = new System.Drawing.Size(53, 13);
+ this.lbS1.TabIndex = 15;
+ this.lbS1.Text = "-";
+ this.lbS1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbS0
+ //
+ this.lbS0.Location = new System.Drawing.Point(137, 92);
+ this.lbS0.Name = "lbS0";
+ this.lbS0.Size = new System.Drawing.Size(53, 13);
+ this.lbS0.TabIndex = 17;
+ this.lbS0.Text = "-";
+ this.lbS0.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // label6
+ //
+ this.label6.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.label6.Location = new System.Drawing.Point(134, 71);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(57, 13);
+ this.label6.TabIndex = 19;
+ this.label6.Text = "Segments";
+ //
+ // lbN2
+ //
+ this.lbN2.Location = new System.Drawing.Point(66, 122);
+ this.lbN2.Name = "lbN2";
+ this.lbN2.Size = new System.Drawing.Size(57, 13);
+ this.lbN2.TabIndex = 13;
+ this.lbN2.Text = "-";
+ this.lbN2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbN1
+ //
+ this.lbN1.Location = new System.Drawing.Point(66, 107);
+ this.lbN1.Name = "lbN1";
+ this.lbN1.Size = new System.Drawing.Size(57, 13);
+ this.lbN1.TabIndex = 14;
+ this.lbN1.Text = "-";
+ this.lbN1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbN0
+ //
+ this.lbN0.Location = new System.Drawing.Point(66, 92);
+ this.lbN0.Name = "lbN0";
+ this.lbN0.Size = new System.Drawing.Size(57, 13);
+ this.lbN0.TabIndex = 12;
+ this.lbN0.Text = "-";
+ this.lbN0.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // label5
+ //
+ this.label5.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.label5.Location = new System.Drawing.Point(63, 71);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(61, 13);
+ this.label5.TabIndex = 10;
+ this.label5.Text = "Neighbors";
+ //
+ // lbPosition
+ //
+ this.lbPosition.AutoSize = true;
+ this.lbPosition.Location = new System.Drawing.Point(70, 15);
+ this.lbPosition.Name = "lbPosition";
+ this.lbPosition.Size = new System.Drawing.Size(11, 13);
+ this.lbPosition.TabIndex = 11;
+ this.lbPosition.Text = "-";
+ //
+ // lbV2
+ //
+ this.lbV2.Location = new System.Drawing.Point(16, 122);
+ this.lbV2.Name = "lbV2";
+ this.lbV2.Size = new System.Drawing.Size(38, 13);
+ this.lbV2.TabIndex = 6;
+ this.lbV2.Text = "-";
+ this.lbV2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbV1
+ //
+ this.lbV1.Location = new System.Drawing.Point(16, 107);
+ this.lbV1.Name = "lbV1";
+ this.lbV1.Size = new System.Drawing.Size(38, 13);
+ this.lbV1.TabIndex = 5;
+ this.lbV1.Text = "-";
+ this.lbV1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbV0
+ //
+ this.lbV0.Location = new System.Drawing.Point(16, 92);
+ this.lbV0.Name = "lbV0";
+ this.lbV0.Size = new System.Drawing.Size(38, 13);
+ this.lbV0.TabIndex = 7;
+ this.lbV0.Text = "-";
+ this.lbV0.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // label4
+ //
+ this.label4.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.label4.Location = new System.Drawing.Point(8, 71);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(47, 13);
+ this.label4.TabIndex = 9;
+ this.label4.Text = "Vertices";
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(6, 15);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(52, 13);
+ this.label1.TabIndex = 8;
+ this.label1.Text = "Position:";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(7, 37);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(51, 13);
+ this.label2.TabIndex = 8;
+ this.label2.Text = "Triangle:";
+ //
+ // lbTriangle
+ //
+ this.lbTriangle.AutoSize = true;
+ this.lbTriangle.Location = new System.Drawing.Point(70, 37);
+ this.lbTriangle.Name = "lbTriangle";
+ this.lbTriangle.Size = new System.Drawing.Size(11, 13);
+ this.lbTriangle.TabIndex = 11;
+ this.lbTriangle.Text = "-";
+ //
+ // darkButton9
+ //
+ this.darkButton9.Location = new System.Drawing.Point(99, 367);
+ this.darkButton9.Name = "darkButton9";
+ this.darkButton9.Size = new System.Drawing.Size(78, 23);
+ this.darkButton9.TabIndex = 21;
+ this.darkButton9.Text = "Rprev";
+ this.darkButton9.UseVisualStyleBackColor = true;
+ this.darkButton9.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton7
+ //
+ this.darkButton7.Location = new System.Drawing.Point(99, 338);
+ this.darkButton7.Name = "darkButton7";
+ this.darkButton7.Size = new System.Drawing.Size(78, 23);
+ this.darkButton7.TabIndex = 22;
+ this.darkButton7.Text = "Dprev";
+ this.darkButton7.UseVisualStyleBackColor = true;
+ this.darkButton7.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton5
+ //
+ this.darkButton5.Location = new System.Drawing.Point(99, 309);
+ this.darkButton5.Name = "darkButton5";
+ this.darkButton5.Size = new System.Drawing.Size(78, 23);
+ this.darkButton5.TabIndex = 23;
+ this.darkButton5.Text = "Oprev";
+ this.darkButton5.UseVisualStyleBackColor = true;
+ this.darkButton5.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton3
+ //
+ this.darkButton3.Location = new System.Drawing.Point(99, 280);
+ this.darkButton3.Name = "darkButton3";
+ this.darkButton3.Size = new System.Drawing.Size(78, 23);
+ this.darkButton3.TabIndex = 24;
+ this.darkButton3.Text = "Lprev";
+ this.darkButton3.UseVisualStyleBackColor = true;
+ this.darkButton3.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton8
+ //
+ this.darkButton8.Location = new System.Drawing.Point(11, 367);
+ this.darkButton8.Name = "darkButton8";
+ this.darkButton8.Size = new System.Drawing.Size(78, 23);
+ this.darkButton8.TabIndex = 25;
+ this.darkButton8.Text = "Rnext";
+ this.darkButton8.UseVisualStyleBackColor = true;
+ this.darkButton8.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton6
+ //
+ this.darkButton6.Location = new System.Drawing.Point(11, 338);
+ this.darkButton6.Name = "darkButton6";
+ this.darkButton6.Size = new System.Drawing.Size(78, 23);
+ this.darkButton6.TabIndex = 26;
+ this.darkButton6.Text = "Dnext";
+ this.darkButton6.UseVisualStyleBackColor = true;
+ this.darkButton6.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton4
+ //
+ this.darkButton4.Location = new System.Drawing.Point(11, 309);
+ this.darkButton4.Name = "darkButton4";
+ this.darkButton4.Size = new System.Drawing.Size(78, 23);
+ this.darkButton4.TabIndex = 27;
+ this.darkButton4.Text = "Onext";
+ this.darkButton4.UseVisualStyleBackColor = true;
+ this.darkButton4.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton2
+ //
+ this.darkButton2.Location = new System.Drawing.Point(11, 280);
+ this.darkButton2.Name = "darkButton2";
+ this.darkButton2.Size = new System.Drawing.Size(78, 23);
+ this.darkButton2.TabIndex = 28;
+ this.darkButton2.Text = "Lnext";
+ this.darkButton2.UseVisualStyleBackColor = true;
+ this.darkButton2.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // darkButton1
+ //
+ this.darkButton1.Location = new System.Drawing.Point(11, 251);
+ this.darkButton1.Name = "darkButton1";
+ this.darkButton1.Size = new System.Drawing.Size(166, 23);
+ this.darkButton1.TabIndex = 20;
+ this.darkButton1.Text = "Sym";
+ this.darkButton1.UseVisualStyleBackColor = true;
+ this.darkButton1.Click += new System.EventHandler(this.btnPrimitive_Click);
+ //
+ // TopoControlView
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.Controls.Add(this.darkButton9);
+ this.Controls.Add(this.darkButton7);
+ this.Controls.Add(this.darkButton5);
+ this.Controls.Add(this.darkButton3);
+ this.Controls.Add(this.darkButton8);
+ this.Controls.Add(this.darkButton6);
+ this.Controls.Add(this.darkButton4);
+ this.Controls.Add(this.darkButton2);
+ this.Controls.Add(this.darkButton1);
+ this.Controls.Add(this.lbS2);
+ this.Controls.Add(this.lbS1);
+ this.Controls.Add(this.lbS0);
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.lbN2);
+ this.Controls.Add(this.lbN1);
+ this.Controls.Add(this.lbN0);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.lbTriangle);
+ this.Controls.Add(this.lbPosition);
+ this.Controls.Add(this.lbV2);
+ this.Controls.Add(this.lbV1);
+ this.Controls.Add(this.lbV0);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.ForeColor = System.Drawing.Color.White;
+ this.Name = "TopoControlView";
+ this.Size = new System.Drawing.Size(195, 439);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label lbS2;
+ private System.Windows.Forms.Label lbS1;
+ private System.Windows.Forms.Label lbS0;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label lbN2;
+ private System.Windows.Forms.Label lbN1;
+ private System.Windows.Forms.Label lbN0;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label lbPosition;
+ private System.Windows.Forms.Label lbV2;
+ private System.Windows.Forms.Label lbV1;
+ private System.Windows.Forms.Label lbV0;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label lbTriangle;
+ private Controls.DarkButton darkButton9;
+ private Controls.DarkButton darkButton7;
+ private Controls.DarkButton darkButton5;
+ private Controls.DarkButton darkButton3;
+ private Controls.DarkButton darkButton8;
+ private Controls.DarkButton darkButton6;
+ private Controls.DarkButton darkButton4;
+ private Controls.DarkButton darkButton2;
+ private Controls.DarkButton darkButton1;
+ }
+}
diff --git a/Triangle.NET/TestApp/Topology/TopologyControlView.cs b/Triangle.NET/TestApp/Topology/TopologyControlView.cs
new file mode 100644
index 0000000..377b7e8
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/TopologyControlView.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Drawing;
+using System.Globalization;
+using System.Windows.Forms;
+using TriangleNet.Geometry;
+
+namespace MeshExplorer.Topology
+{
+ public partial class TopologyControlView : UserControl
+ {
+ public event EventHandler> PrimitiveCommandInvoked;
+
+ public TopologyControlView()
+ {
+ InitializeComponent();
+ }
+
+ public void SetPosition(PointF p)
+ {
+ var nfi = NumberFormatInfo.InvariantInfo;
+
+ lbPosition.Text = String.Format(nfi, "X: {0:0.0}, Y: {1:0.0}", p.X, p.Y);
+ }
+
+ public void SetTriangle(OrientedTriangle tri)
+ {
+ var t = tri.Triangle;
+
+ if (t != null)
+ {
+ lbTriangle.Text = t.ID.ToString();
+
+ lbV0.Text = t.P0.ToString();
+ lbV1.Text = t.P1.ToString();
+ lbV2.Text = t.P2.ToString();
+
+ lbN0.Text = t.N0.ToString();
+ lbN1.Text = t.N1.ToString();
+ lbN2.Text = t.N2.ToString();
+
+ lbS0.Text = GetSegmentString(t.GetSegment(0));
+ lbS1.Text = GetSegmentString(t.GetSegment(1));
+ lbS2.Text = GetSegmentString(t.GetSegment(2));
+ }
+ else
+ {
+ lbTriangle.Text = "-";
+
+ lbV0.Text = "-";
+ lbV1.Text = "-";
+ lbV2.Text = "-";
+
+ lbN0.Text = "-";
+ lbN1.Text = "-";
+ lbN2.Text = "-";
+
+ lbS0.Text = "-";
+ lbS1.Text = "-";
+ lbS2.Text = "-";
+ }
+ }
+
+ private string GetSegmentString(ISegment seg)
+ {
+ return seg == null ? "-" : "[" + seg.P0 + " - " + seg.P1 + "]";
+ }
+
+ private void btnPrimitive_Click(object sender, EventArgs e)
+ {
+ var button = sender as Button;
+
+ if (button != null)
+ {
+ var name = button.Text.ToLowerInvariant();
+
+ var handler = PrimitiveCommandInvoked;
+
+ if (handler != null)
+ {
+ handler(this, new GenericEventArgs(name));
+ }
+ }
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Topology/TopologyControlView.resx b/Triangle.NET/TestApp/Topology/TopologyControlView.resx
new file mode 100644
index 0000000..29dcb1b
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/TopologyControlView.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs b/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs
new file mode 100644
index 0000000..78b2bc3
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/TopologyRenderControl.cs
@@ -0,0 +1,141 @@
+
+namespace MeshExplorer.Topology
+{
+ using System.Drawing;
+ using System.Drawing.Drawing2D;
+ using System.Drawing.Text;
+ using System.Windows.Forms;
+ using MeshRenderer.Core;
+ using TriangleNet;
+
+ public class TopologyRenderControl : Control
+ {
+ // Rendering stuff
+ private BufferedGraphics buffer;
+ private BufferedGraphicsContext context;
+
+ Zoom zoom;
+ TopologyRenderer renderer;
+
+ bool initialized = false;
+
+ public Zoom Zoom
+ {
+ get { return zoom; }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TopologyRenderControl()
+ {
+ SetStyle(ControlStyles.ResizeRedraw, true);
+
+ this.BackColor = Color.Black;
+
+ zoom = new Zoom(true);
+ context = new BufferedGraphicsContext();
+ }
+
+ ///
+ /// Initialize the graphics buffer (should be called in the forms load event).
+ ///
+ public void Initialize(Mesh mesh)
+ {
+ renderer = new TopologyRenderer(mesh);
+
+ zoom.Initialize(this.ClientRectangle);
+ //zoom.ClipMargin = 10.0f;
+
+ var b = mesh.Bounds;
+ zoom.Update(new BoundingBox((float)b.Xmin, (float)b.Xmax,
+ (float)b.Ymin, (float)b.Ymax));
+
+ InitializeBuffer();
+
+ initialized = true;
+
+ this.Render();
+ }
+
+ public void Update(OrientedTriangle otri)
+ {
+ renderer.SelectTriangle(otri.Triangle == null ? null : otri);
+ this.Render();
+ }
+
+ private void InitializeBuffer()
+ {
+ if (this.Width > 0 && this.Height > 0)
+ {
+ if (buffer != null)
+ {
+ if (this.ClientRectangle == buffer.Graphics.VisibleClipBounds)
+ {
+ this.Invalidate();
+
+ // Bounds didn't change. Probably we just restored the window
+ // from minimized state.
+ return;
+ }
+
+ buffer.Dispose();
+ }
+
+ buffer = context.Allocate(Graphics.FromHwnd(this.Handle), this.ClientRectangle);
+
+ if (initialized)
+ {
+ this.Render();
+ }
+ }
+ }
+
+ private void Render()
+ {
+ if (buffer == null)
+ {
+ return;
+ }
+
+ Graphics g = buffer.Graphics;
+ g.Clear(this.BackColor);
+
+ if (!initialized || renderer == null)
+ {
+ return;
+ }
+
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+ g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
+
+ renderer.Render(g, zoom);
+
+ this.Invalidate();
+ }
+
+ #region Control overrides
+
+ protected override void OnPaint(PaintEventArgs pe)
+ {
+ if (!initialized)
+ {
+ base.OnPaint(pe);
+ return;
+ }
+
+ buffer.Render();
+ }
+
+ protected override void OnPaintBackground(PaintEventArgs pevent)
+ {
+ // Do nothing
+ if (!initialized)
+ {
+ base.OnPaintBackground(pevent);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Triangle.NET/TestApp/Topology/TopologyRenderer.cs b/Triangle.NET/TestApp/Topology/TopologyRenderer.cs
new file mode 100644
index 0000000..290b3d5
--- /dev/null
+++ b/Triangle.NET/TestApp/Topology/TopologyRenderer.cs
@@ -0,0 +1,281 @@
+
+namespace MeshExplorer.Topology
+{
+ using System;
+ using System.Drawing;
+ using MeshRenderer.Core;
+ using TriangleNet;
+ using TriangleNet.Geometry;
+
+ public class TopologyRenderer
+ {
+ Zoom zoom;
+ Mesh mesh;
+ PointF[] points;
+
+ // Colors
+ Color Background = Color.FromArgb(0, 0, 0);
+ Brush Point = new SolidBrush(Color.FromArgb(0, 80, 0));
+ Brush Triangle = new SolidBrush(Color.FromArgb(50, 50, 50));
+ Pen Line = new Pen(Color.FromArgb(30, 30, 30));
+ Pen Segment = new Pen(Color.DarkBlue);
+
+ Brush SelectedTriangle = new SolidBrush(Color.FromArgb(50, 0, 0));
+ Pen SelectedEdge = new Pen(Color.DarkRed, 2.0f);
+
+ Font font, fontTri;
+
+ OrientedTriangle selection;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TopologyRenderer(Mesh mesh)
+ {
+ this.mesh = mesh;
+
+ points = new PointF[mesh.Vertices.Count];
+
+ int k = 0;
+
+ foreach (var v in mesh.Vertices)
+ {
+ points[k++] = new PointF((float)v.X, (float)v.Y);
+ }
+
+ font = new Font("Arial", 7.5f);
+ fontTri = new Font("Arial", 12f, FontStyle.Bold);
+ }
+
+ ///
+ /// Renders the mesh.
+ ///
+ public void Render(Graphics g, Zoom zoom)
+ {
+ this.zoom = zoom;
+
+ if (mesh.Edges != null)
+ {
+ this.RenderSelectedTriangle(g);
+ this.RenderEdges(g);
+ this.RenderTriangleIds(g);
+ }
+ else if (mesh.Triangles != null)
+ {
+ this.RenderTriangles(g);
+ }
+
+ if (mesh.Segments != null)
+ {
+ this.RenderSegments(g);
+ }
+
+ RenderSelectedEdge(g);
+
+ if (mesh.Vertices != null)
+ {
+ this.RenderPoints(g);
+ }
+ }
+
+ public void SelectTriangle(OrientedTriangle tri)
+ {
+ selection = tri;
+ }
+
+ #region Helpers
+
+ private PointF GetIncenter(PointF p0, PointF p1, PointF p2)
+ {
+ double cx, cy, a, b, c,
+ dax = p1.X - p0.X,
+ dbx = p2.X - p1.X,
+ dcx = p0.X - p2.X,
+ day = p1.Y - p0.Y,
+ dby = p2.Y - p1.Y,
+ dcy = p0.Y - p2.Y;
+
+ a = Math.Sqrt(dax * dax + day * day);
+ b = Math.Sqrt(dbx * dbx + dby * dby);
+ c = Math.Sqrt(dcx * dcx + dcy * dcy);
+
+ cx = (a * p2.X + b * p0.X + c * p1.X) / (a + b + c);
+ cy = (a * p2.Y + b * p0.Y + c * p1.Y) / (a + b + c);
+
+ return new PointF((float)cx, (float)cy);
+ }
+
+ private PointF GetCentroid(PointF p0, PointF p1, PointF p2)
+ {
+ double cx, cy;
+
+ cx = (p0.X + p1.X + p2.X) / 3;
+ cy = (p0.Y + p1.Y + p2.Y) / 3;
+
+ return new PointF((float)cx, (float)cy);
+ }
+
+ private PointF GetPoint(ITriangle tri, int index)
+ {
+ var v = tri.GetVertex(index);
+
+ return new PointF((float)v.X, (float)v.Y);
+ }
+
+ private PointF GetPoint(ISegment seg, int index)
+ {
+ var v = seg.GetVertex(index);
+
+ return new PointF((float)v.X, (float)v.Y);
+ }
+
+ #endregion
+
+ private void RenderPoints(Graphics g)
+ {
+ int n = points.Length;
+ PointF pt;
+
+ int id = selection != null ? selection.Org().ID : -1;
+
+ for (int i = 0; i < n; i++)
+ {
+ var brush = i == id ? Brushes.DarkRed : Point;
+
+ pt = zoom.WorldToScreen(points[i].X, points[i].Y);
+ g.FillEllipse(brush, pt.X - 10f, pt.Y - 10f, 20, 20);
+
+ pt.X -= i > 9 ? 7 : 4;
+ pt.Y -= 6;
+ g.DrawString(i.ToString(), font, Brushes.White, pt);
+ }
+ }
+
+ private void RenderTriangles(Graphics g)
+ {
+ PointF p0, p1, p2, center;
+
+ var triangles = mesh.Triangles;
+
+ // Draw triangles
+ foreach (var tri in triangles)
+ {
+ p0 = points[tri.P0];
+ p1 = points[tri.P1];
+ p2 = points[tri.P2];
+
+ p0 = zoom.WorldToScreen(p0.X, p0.Y);
+ p1 = zoom.WorldToScreen(p1.X, p1.Y);
+ p2 = zoom.WorldToScreen(p2.X, p2.Y);
+
+ g.DrawLine(Line, p0, p1);
+ g.DrawLine(Line, p1, p2);
+ g.DrawLine(Line, p2, p0);
+
+ center = GetIncenter(p0, p1, p2);
+ center.X -= 5;
+ center.Y -= 5;
+
+ g.DrawString(tri.ID.ToString(), fontTri, Triangle, center);
+ }
+ }
+
+ private void RenderTriangleIds(Graphics g)
+ {
+ PointF p0, p1, p2, center;
+
+ var triangles = mesh.Triangles;
+
+ // Draw triangles
+ foreach (var tri in triangles)
+ {
+ p0 = points[tri.P0];
+ p1 = points[tri.P1];
+ p2 = points[tri.P2];
+
+ p0 = zoom.WorldToScreen(p0.X, p0.Y);
+ p1 = zoom.WorldToScreen(p1.X, p1.Y);
+ p2 = zoom.WorldToScreen(p2.X, p2.Y);
+
+ center = GetIncenter(p0, p1, p2);
+ center.X -= 5;
+ center.Y -= 5;
+
+ g.DrawString(tri.ID.ToString(), fontTri, Triangle, center);
+ }
+ }
+
+ private void RenderEdges(Graphics g)
+ {
+ PointF p0, p1;
+
+ var edges = mesh.Edges;
+
+ // Draw edges
+ foreach (var edge in edges)
+ {
+ p0 = points[edge.P0];
+ p1 = points[edge.P1];
+
+ p0 = zoom.WorldToScreen(p0.X, p0.Y);
+ p1 = zoom.WorldToScreen(p1.X, p1.Y);
+
+ g.DrawLine(Line, p0, p1);
+ }
+ }
+
+ private void RenderSegments(Graphics g)
+ {
+ PointF p0, p1;
+
+ var segments = mesh.Segments;
+
+ foreach (var seg in segments)
+ {
+ p0 = points[seg.P0];
+ p1 = points[seg.P1];
+
+ p0 = zoom.WorldToScreen(p0.X, p0.Y);
+ p1 = zoom.WorldToScreen(p1.X, p1.Y);
+
+ g.DrawLine(Segment, p0, p1);
+ }
+ }
+
+ private void RenderSelectedEdge(Graphics g)
+ {
+ if (selection != null)
+ {
+ PointF p0, p1;
+
+ p0 = points[selection.Org().ID];
+ p1 = points[selection.Dest().ID];
+
+ p0 = zoom.WorldToScreen(p0.X, p0.Y);
+ p1 = zoom.WorldToScreen(p1.X, p1.Y);
+
+ g.DrawLine(SelectedEdge, p0, p1);
+ }
+ }
+
+ private void RenderSelectedTriangle(Graphics g)
+ {
+ if (selection != null)
+ {
+ var tri = selection.Triangle;
+
+ var p = new PointF[3];
+
+ p[0] = points[tri.P0];
+ p[1] = points[tri.P1];
+ p[2] = points[tri.P2];
+
+ p[0] = zoom.WorldToScreen(p[0].X, p[0].Y);
+ p[1] = zoom.WorldToScreen(p[1].X, p[1].Y);
+ p[2] = zoom.WorldToScreen(p[2].X, p[2].Y);
+
+ g.FillPolygon(SelectedTriangle, p);
+ }
+ }
+ }
+}
diff --git a/Triangle.NET/Triangle/Tools/QuadTree.cs b/Triangle.NET/Triangle/Tools/QuadTree.cs
index 6b61549..82aa032 100644
--- a/Triangle.NET/Triangle/Tools/QuadTree.cs
+++ b/Triangle.NET/Triangle/Tools/QuadTree.cs
@@ -18,7 +18,7 @@ namespace TriangleNet.Tools
{
QuadNode root;
- internal ITriangle[] triangles;
+ internal Dictionary triangles;
internal int sizeBound;
internal int maxDepth;
@@ -42,7 +42,12 @@ namespace TriangleNet.Tools
this.maxDepth = maxDepth;
this.sizeBound = sizeBound;
- triangles = mesh.Triangles.ToArray();
+ triangles = new Dictionary();
+
+ foreach (var tri in mesh.Triangles)
+ {
+ triangles.Add(tri.id, tri);
+ }
int currentDepth = 0;
@@ -64,6 +69,7 @@ namespace TriangleNet.Tools
if (IsPointInTriangle(point, tri.GetVertex(0), tri.GetVertex(1), tri.GetVertex(2)))
{
result.Add(tri);
+ break;
}
}
@@ -160,11 +166,11 @@ namespace TriangleNet.Tools
if (init)
{
// Allocate memory upfront
- triangles.Capacity = tree.triangles.Length;
+ triangles.Capacity = tree.triangles.Count;
- foreach (var tri in tree.triangles)
+ foreach (var id in tree.triangles.Keys)
{
- triangles.Add(tri.ID);
+ triangles.Add(id);
}
}
}
@@ -208,10 +214,8 @@ namespace TriangleNet.Tools
Point[] triangle = new Point[3];
// Find region for every triangle vertex
- foreach (var index in triangles)
+ foreach (var tri in tree.triangles.Values)
{
- ITriangle tri = tree.triangles[index];
-
triangle[0] = tri.GetVertex(0);
triangle[1] = tri.GetVertex(1);
triangle[2] = tri.GetVertex(2);