Fix Quadtree;

Added topology explorer to test app;

git-svn-id: https://triangle.svn.codeplex.com/svn@74355 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2014-01-14 21:16:08 +00:00
parent 7fd0fe2341
commit d76842d2f6
15 changed files with 1638 additions and 8 deletions
+18
View File
@@ -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;
}
}
+5
View File
@@ -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();
+112
View File
@@ -0,0 +1,112 @@
namespace MeshExplorer
{
partial class FormTopology
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}
+138
View File
@@ -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<string> 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);
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+19
View File
@@ -0,0 +1,19 @@
using System;
namespace MeshExplorer
{
public class GenericEventArgs<T> : EventArgs
{
T argument;
public T Argument
{
get { return argument; }
}
public GenericEventArgs(T arg)
{
argument = arg;
}
}
}
+25
View File
@@ -96,6 +96,12 @@
<Compile Include="FormMain.Designer.cs">
<DependentUpon>FormMain.cs</DependentUpon>
</Compile>
<Compile Include="FormTopology.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormTopology.Designer.cs">
<DependentUpon>FormTopology.cs</DependentUpon>
</Compile>
<Compile Include="Generators\BaseGenerator.cs" />
<Compile Include="Generators\BoxWithHole.cs" />
<Compile Include="Generators\CircleWithHole.cs" />
@@ -104,6 +110,7 @@
<Compile Include="Generators\RandomPointsCircle.cs" />
<Compile Include="Generators\RingPolygon.cs" />
<Compile Include="Generators\StarInBox.cs" />
<Compile Include="GenericEventArgs.cs" />
<Compile Include="IO\EpsImage.cs" />
<Compile Include="IO\FileProcessor.cs" />
<Compile Include="IO\Formats\JsonFile.cs" />
@@ -116,6 +123,18 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Topology\OrientedTriangle.cs" />
<Compile Include="Topology\RectanglePolygon.cs" />
<Compile Include="Topology\TopologyControlView.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Topology\TopologyControlView.Designer.cs">
<DependentUpon>TopologyControlView.cs</DependentUpon>
</Compile>
<Compile Include="Topology\TopologyRenderControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Topology\TopologyRenderer.cs" />
<Compile Include="Util.cs" />
<Compile Include="Views\AboutView.cs">
<SubType>UserControl</SubType>
@@ -148,6 +167,12 @@
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="FormTopology.resx">
<DependentUpon>FormTopology.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Topology\TopologyControlView.resx">
<DependentUpon>TopologyControlView.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Views\AboutView.resx">
<DependentUpon>AboutView.cs</DependentUpon>
</EmbeddedResource>
@@ -0,0 +1,156 @@
namespace MeshExplorer.Topology
{
using TriangleNet.Data;
using TriangleNet.Geometry;
public class OrientedTriangle
{
/// <summary>
///
/// </summary>
public ITriangle Triangle { get; set; }
/// <summary>
/// Ranges from 0 to 2.
/// </summary>
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 };
/// <summary>
/// Find the abutting triangle; same edge. [sym(abc) -> ba*]
/// </summary>
public void Sym()
{
//this = tri.triangles[Orientation];
// decode(ptr, otri);
var org = this.Org();
Triangle = Triangle.GetNeighbor(Orientation);
Orientation = GetOrientation(Triangle, org.ID);
}
/// <summary>
/// Find the next edge (counterclockwise) of a triangle. [lnext(abc) -> bca]
/// </summary>
public void Lnext()
{
Orientation = plus1Mod3[Orientation];
}
/// <summary>
/// Find the previous edge (clockwise) of a triangle. [lprev(abc) -> cab]
/// </summary>
public void Lprev()
{
Orientation = minus1Mod3[Orientation];
}
/// <summary>
/// Find the next edge counterclockwise with the same origin. [onext(abc) -> ac*]
/// </summary>
public void Onext()
{
Lprev();
Sym();
}
/// <summary>
/// Find the next edge clockwise with the same origin. [oprev(abc) -> a*b]
/// </summary>
public void Oprev()
{
Sym();
Lnext();
}
/// <summary>
/// Find the next edge counterclockwise with the same destination. [dnext(abc) -> *ba]
/// </summary>
public void Dnext()
{
Sym();
Lprev();
}
/// <summary>
/// Find the next edge clockwise with the same destination. [dprev(abc) -> cb*]
/// </summary>
public void Dprev()
{
Lnext();
Sym();
}
/// <summary>
/// Find the next edge (counterclockwise) of the adjacent triangle. [rnext(abc) -> *a*]
/// </summary>
public void Rnext()
{
Sym();
Lnext();
Sym();
}
/// <summary>
/// Find the previous edge (clockwise) of the adjacent triangle. [rprev(abc) -> b**]
/// </summary>
public void Rprev()
{
Sym();
Lprev();
Sym();
}
/// <summary>
/// Origin [org(abc) -> a]
/// </summary>
public Vertex Org()
{
return Triangle.GetVertex(plus1Mod3[Orientation]);
}
/// <summary>
/// Destination [dest(abc) -> b]
/// </summary>
public Vertex Dest()
{
return Triangle.GetVertex(minus1Mod3[Orientation]);
}
/// <summary>
/// Apex [apex(abc) -> c]
/// </summary>
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;
}
}
}
@@ -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;
}
}
}
@@ -0,0 +1,359 @@
namespace MeshExplorer.Topology
{
partial class TopologyControlView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}
@@ -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<GenericEventArgs<string>> 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<string>(name));
}
}
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -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; }
}
/// <summary>
/// Initializes a new instance of the <see cref="RenderControl" /> class.
/// </summary>
public TopologyRenderControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
this.BackColor = Color.Black;
zoom = new Zoom(true);
context = new BufferedGraphicsContext();
}
/// <summary>
/// Initialize the graphics buffer (should be called in the forms load event).
/// </summary>
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
}
}
@@ -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;
/// <summary>
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
/// </summary>
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);
}
/// <summary>
/// Renders the mesh.
/// </summary>
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);
}
}
}
}
+12 -8
View File
@@ -18,7 +18,7 @@ namespace TriangleNet.Tools
{
QuadNode root;
internal ITriangle[] triangles;
internal Dictionary<int, ITriangle> 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<int, ITriangle>();
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);