diff --git a/Triangle.NET/TestApp/Controls/AngleHistogram.cs b/Triangle.NET/TestApp/Controls/AngleHistogram.cs
index 465be1e..1dac085 100644
--- a/Triangle.NET/TestApp/Controls/AngleHistogram.cs
+++ b/Triangle.NET/TestApp/Controls/AngleHistogram.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp.Controls
+namespace MeshExplorer.Controls
{
using System;
using System.Collections.Generic;
@@ -12,10 +12,16 @@ namespace TestApp.Controls
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
+ using System.Drawing.Text;
///
- /// TODO: Update summary.
+ /// Displays an angle histogram.
///
+ ///
+ /// The angle histogram is divided into two parts:
+ /// the minimum angles on the left side (0 to 60 degrees) and
+ /// the maximum angles on the right (60 to 180 degrees)
+ ///
public class AngleHistogram : Control
{
#region Designer
@@ -53,102 +59,141 @@ namespace TestApp.Controls
#endregion
- int[] data;
- int max = 0;
+ int[] maxAngles;
+ int[] minAngles;
+
+ Brush fillBlue1 = new SolidBrush(Color.FromArgb(60, 100, 140));
+ Brush fillBlue2 = new SolidBrush(Color.FromArgb(110, 150, 200));
+
+ Brush textBack = new SolidBrush(Color.FromArgb(72, 0, 0, 0));
+
+ // The maximum number of angles
+ int maxAngleCount = 0;
public AngleHistogram()
{
- this.BackColor = Color.FromArgb(76, 76, 76);
+ this.BackColor = ColorScheme.ColorGray78;
InitializeComponent();
}
- public void SetData(int[] data)
+ public void SetData(int[] dataMin, int[] dataMax)
+ {
+ maxAngleCount = 0;
+
+ this.minAngles = dataMin;
+ this.maxAngles = dataMax;
+
+ ParseData(dataMin);
+ ParseData(dataMax);
+
+ if (maxAngleCount == 0)
+ {
+ this.maxAngles = null;
+ return;
+ }
+
+ this.Invalidate();
+ }
+
+ private void ParseData(int[] data)
{
if (data != null)
{
- this.data = data;
- this.max = 0;
-
for (int i = 0; i < data.Length; i++)
{
- if (data[i] > max)
+ if (data[i] > maxAngleCount)
{
- max = data[i];
+ maxAngleCount = data[i];
}
}
-
- if (max == 0)
- {
- this.data = null;
- return;
- }
-
- double lg10 = Math.Ceiling(Math.Log10(max)) - 1;
- int norm = (int)Math.Pow(10, lg10);
- int mod = -max % norm;
- max = max + mod + norm;
-
- this.Invalidate();
}
}
+ int padding = 1;
+ int paddingBottom = 0;
+ int paddingTop = 15;
+
+ private void DrawHistogram(Graphics g, int offset, int left, int size, int[] data, Brush brush, Brush brushTop)
+ {
+ int count = maxAngleCount;
+ int totalHeight = this.Height - paddingBottom - paddingTop;
+
+ int n = offset == 0 ? data.Length / 3 : data.Length;
+ float value = 0;
+
+ for (int i = offset; i < n; i++)
+ {
+ if (data[i] > 0)
+ {
+ // Scale to control height
+ value = totalHeight * data[i] / count;
+
+ // Fill bar
+ g.FillRectangle(brush,
+ left + i * size, this.Height - paddingBottom - value,
+ size - 1, value);
+
+ // Draw top of bar (just a little effect ...)
+ if (value > 2)
+ {
+ g.FillRectangle(brushTop,
+ left + i * size, this.Height - paddingBottom - value,
+ size - 1, 2);
+ }
+ }
+ }
+ }
+
+
+ private void DrawStrings(Graphics g, SizeF fSize, int size, int middle)
+ {
+ int fHeight = (int)(fSize.Height + 2);
+ g.FillRectangle(textBack, 0, this.Height - fHeight, this.Width, fHeight);
+
+ g.DrawString("0", this.Font, Brushes.White, padding, this.Height - fSize.Height - 1);
+ g.DrawString("60", this.Font, Brushes.White,
+ this.minAngles.Length * size / 3.0f - 2 * fSize.Width,
+ this.Height - fSize.Height - 1);
+
+ g.DrawString("60", this.Font, Brushes.White, middle, this.Height - fSize.Height - 1);
+ g.DrawString("180", this.Font, Brushes.White,
+ this.Width - 3 * fSize.Width,
+ this.Height - fSize.Height - 1);
+ }
+
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
- SizeF s1 = g.MeasureString("180", base.Font, this.Width);
- SizeF s2 = g.MeasureString(max.ToString(), base.Font, this.Width);
-
- // Draw bottom rect
- g.FillRectangle(Brushes.DimGray, s2.Width, this.Height - s1.Height - 4, this.Width, s1.Height + 4);
-
- // Draw Histogram
- if (data != null)
+ if (this.minAngles == null || this.maxAngles == null)
{
- int n = data.Length;
- float width = (this.Width - s2.Width) / n;
- float value = 0;
-
- for (int i = 0; i < data.Length; i++)
- {
- if (data[i] > 0)
- {
- // Scale to control height
- value = (this.Height - s1.Height - 4) * data[i] / max;
-
- g.FillRectangle(Brushes.DarkGreen,
- s2.Width + i * width + width / 8,
- this.Height - s1.Height - 4 - value,
- 3 * width / 4,
- value);
-
- if (value > 2)
- {
- g.FillRectangle(Brushes.Green,
- s2.Width + i * width + width / 8,
- this.Height - s1.Height - 4 - value,
- 3 * width / 4,
- 2);
- }
- }
- }
+ return;
}
- e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
+ SizeF fSize = g.MeasureString("0", this.Font, this.Width);
- // Draw data keys
- g.DrawString("0", this.Font, Brushes.White, s2.Width + 2, this.Height - s1.Height - 2);
- g.DrawString("90", this.Font, Brushes.White, this.Width / 2 - s1.Width / 3, this.Height - s1.Height - 2);
- g.DrawString("180", this.Font, Brushes.White, this.Width - s1.Width - 2, this.Height - s1.Height - 2);
+ int n = this.minAngles.Length;
- // Draw data values
- if (max > 0)
+ // Hack --- TODO: Change stats class
+ if (n != this.maxAngles.Length)
{
- g.DrawString(max.ToString(), this.Font, Brushes.White, 2, 10);
- g.DrawString((max / 2).ToString(), this.Font, Brushes.White, 2, (this.Height - s1.Height) / 2);
+ n = this.minAngles.Length + this.maxAngles.Length;
}
+
+ // Each bar takes up this space
+ int size = (this.Width - 2 * padding) / (n + 1);
+
+ // Make pixel align
+ int middle = this.Width - padding - n * size;
+
+ DrawHistogram(g, 0, padding, size, this.minAngles, Brushes.DarkGreen, Brushes.Green);
+ DrawHistogram(g, n / 3, middle, size, this.maxAngles, fillBlue1, fillBlue2);
+
+ g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
+
+ DrawStrings(g, fSize, size, middle + n / 3 * size);
}
}
}
diff --git a/Triangle.NET/TestApp/Controls/ColorScheme.cs b/Triangle.NET/TestApp/Controls/ColorScheme.cs
new file mode 100644
index 0000000..f00428d
--- /dev/null
+++ b/Triangle.NET/TestApp/Controls/ColorScheme.cs
@@ -0,0 +1,40 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.Controls
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Drawing;
+using System.Drawing.Drawing2D;
+
+ ///
+ /// TODO: Update summary.
+ ///
+ public static class ColorScheme
+ {
+
+ public static Color ColorGray13 = Color.FromArgb(13, 13, 13);
+ public static Color ColorGray46 = Color.FromArgb(46, 46, 46);
+ public static Color ColorGray64 = Color.FromArgb(64, 64, 64);
+ public static Color ColorGray68 = Color.FromArgb(68, 68, 68);
+ public static Color ColorGray78 = Color.FromArgb(78, 78, 78);
+ public static Color ColorGray89 = Color.FromArgb(89, 89, 89);
+ public static Color ColorGray98 = Color.FromArgb(98, 98, 98);
+ public static Color ColorGray107 = Color.FromArgb(107, 107, 107);
+ public static Color ColorGray110 = Color.FromArgb(110, 110, 110);
+ public static Color ColorGray122 = Color.FromArgb(122, 122, 122);
+
+ public static Brush BrushGray68 = new SolidBrush(ColorGray68);
+ public static Brush BrushGray78 = new SolidBrush(ColorGray78);
+
+ // Linear gradient horizontal
+ public static Brush SliderBorderBrush = new SolidBrush(ColorGray46);
+ public static Brush SliderFillBrush = new SolidBrush(ColorGray89);
+ }
+}
diff --git a/Triangle.NET/TestApp/Controls/DarkButton.cs b/Triangle.NET/TestApp/Controls/DarkButton.cs
index 153fb79..ac8c5e6 100644
--- a/Triangle.NET/TestApp/Controls/DarkButton.cs
+++ b/Triangle.NET/TestApp/Controls/DarkButton.cs
@@ -1,6 +1,6 @@
-namespace TestApp.Controls
+namespace MeshExplorer.Controls
{
using System;
using System.Collections.Generic;
diff --git a/Triangle.NET/TestApp/Controls/DarkCheckBox.cs b/Triangle.NET/TestApp/Controls/DarkCheckBox.cs
index f177297..00942b2 100644
--- a/Triangle.NET/TestApp/Controls/DarkCheckBox.cs
+++ b/Triangle.NET/TestApp/Controls/DarkCheckBox.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp.Controls
+namespace MeshExplorer.Controls
{
using System;
using System.Collections.Generic;
@@ -107,7 +107,7 @@ namespace TestApp.Controls
else
brushBorder = new Pen(Color.FromArgb(38, 38, 38), 1f);
- brushOuter = new LinearGradientBrush(newRect, Color.FromArgb(82, 82, 82), Color.FromArgb(96, 96, 96), mode);
+ brushOuter = new LinearGradientBrush(newRect, ColorScheme.ColorGray107, ColorScheme.ColorGray110, mode);
e.Graphics.FillRectangle(brushOuter, newRect);
newRect = new Rectangle(2, y + 1, boxSize - 3, boxSize - 3);
diff --git a/Triangle.NET/TestApp/Controls/DarkListBox.cs b/Triangle.NET/TestApp/Controls/DarkListBox.cs
new file mode 100644
index 0000000..5bc1918
--- /dev/null
+++ b/Triangle.NET/TestApp/Controls/DarkListBox.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+using System.Drawing;
+
+namespace MeshExplorer.Controls
+{
+ public class DarkListBox : ListBox
+ {
+ Font _boldFont;
+
+ public DarkListBox()
+ {
+ _boldFont = new Font(base.Font.FontFamily, base.Font.Size, FontStyle.Bold);
+
+ this.DrawMode = DrawMode.OwnerDrawVariable;
+ this.ItemHeight = 22;
+ this.FontChanged += new EventHandler(ListBoxFontChanged);
+ this.BackColor = Color.FromArgb(96, 96, 96);
+ }
+
+ void ListBoxFontChanged(object sender, EventArgs e)
+ {
+ _boldFont = new Font(base.Font.FontFamily, base.Font.Size, FontStyle.Bold);
+ }
+
+ protected override void OnMeasureItem(MeasureItemEventArgs e)
+ {
+ e.ItemHeight = 22;
+ }
+
+ protected override void OnDrawItem(DrawItemEventArgs e)
+ {
+ if (this.Items.Count == 0)
+ {
+ return;
+ }
+
+ e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
+
+ int index = e.Index;
+
+ string content = "[Error]";
+
+ if (index < this.Items.Count && index >= 0)
+ {
+ content = this.Items[index].ToString();
+ }
+
+ Color color = (e.Index % 2) == 0 ? Color.FromArgb(85, 85, 85) : Color.FromArgb(90, 90, 90);
+
+ if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
+ {
+ color = Color.FromArgb(100, 105, 110);
+ }
+
+ using (SolidBrush background = new SolidBrush(color))
+ {
+ e.Graphics.FillRectangle(background, e.Bounds);
+ }
+
+ using (SolidBrush pen = new SolidBrush(Color.White))
+ {
+ e.Graphics.DrawString(content, this.Font, pen,
+ new PointF(10, e.Bounds.Y + 3), StringFormat.GenericDefault);
+ }
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Controls/DarkSlider.cs b/Triangle.NET/TestApp/Controls/DarkSlider.cs
new file mode 100644
index 0000000..46af015
--- /dev/null
+++ b/Triangle.NET/TestApp/Controls/DarkSlider.cs
@@ -0,0 +1,430 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.Controls
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Windows.Forms;
+ using System.Drawing;
+ using System.Drawing.Drawing2D;
+
+ // CodeProject: Owner-drawn trackbar (slider), Michal Brylka
+
+ ///
+ /// Encapsulates control that visualy displays certain integer value and allows user to change
+ /// it within desired range. It imitates as far as
+ /// mouse usage is concerned.
+ ///
+ public class DarkSlider : Control
+ {
+ #region Designer
+
+ ///
+ /// 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()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Events
+
+ ///
+ /// Fires when Slider position has changed
+ ///
+ public event EventHandler ValueChanging;
+
+ private void OnValueChanging()
+ {
+ var evt = ValueChanging;
+
+ if (evt != null)
+ {
+ evt(this, EventArgs.Empty);
+ }
+ }
+
+ ///
+ /// Fires when Slider position has changed
+ ///
+ public event EventHandler ValueChanged;
+
+ private void OnValueChanged()
+ {
+ var evt = ValueChanged;
+
+ if (evt != null)
+ {
+ evt(this, EventArgs.Empty);
+ }
+ }
+
+ #endregion
+
+ #region Properties
+
+ int thumbSize = 7;
+ private Rectangle thumbRect; //bounding rectangle of thumb area
+ private Rectangle barRect; //bounding rectangle of bar area
+ private bool mouseInThumbRegion = false;
+
+ private int trackerValue = 50;
+ ///
+ /// Gets or sets the value of Slider.
+ ///
+ /// The value.
+ public int Value
+ {
+ get { return trackerValue; }
+ set
+ {
+ if (value >= barMinimum & value <= barMaximum)
+ {
+ trackerValue = value;
+ if (ValueChanged != null) ValueChanged(this, new EventArgs());
+ Invalidate();
+ }
+ // ArgumentOutOfRangeException("Value is outside appropriate range (min, max)");
+ }
+ }
+
+
+ private int barMinimum = 0;
+ ///
+ /// Gets or sets the minimum value.
+ ///
+ /// The minimum value.
+ public int Minimum
+ {
+ get { return barMinimum; }
+ set
+ {
+ if (value < barMaximum)
+ {
+ barMinimum = value;
+ if (trackerValue < barMinimum)
+ {
+ trackerValue = barMinimum;
+ if (ValueChanged != null) ValueChanged(this, new EventArgs());
+ }
+ Invalidate();
+ }
+ // ArgumentOutOfRangeException("Minimal value is greather than maximal one");
+ }
+ }
+
+
+ private int barMaximum = 100;
+ ///
+ /// Gets or sets the maximum value.
+ ///
+ /// The maximum value.
+ public int Maximum
+ {
+ get { return barMaximum; }
+ set
+ {
+ if (value > barMinimum)
+ {
+ barMaximum = value;
+ if (trackerValue > barMaximum)
+ {
+ trackerValue = barMaximum;
+ if (ValueChanged != null) ValueChanged(this, new EventArgs());
+ }
+ Invalidate();
+ }
+ // ArgumentOutOfRangeException("Maximal value is lower than minimal one");
+ }
+ }
+
+ private uint criticalPercent = 0;
+ ///
+ /// Gets or sets trackbar's small change. It affects how to behave when directional keys are pressed
+ ///
+ /// The small change value.
+ public uint CriticalPercent
+ {
+ get { return criticalPercent; }
+ set { criticalPercent = value; }
+ }
+
+ private Color thumbOuterColor = Color.White;
+ private Color thumbInnerColor = Color.Gainsboro;
+ private Color thumbPenColor = Color.Silver;
+ private Color barOuterColor = Color.SkyBlue;
+ private Color barInnerColor = Color.DarkSlateBlue;
+ private Color barPenColor = Color.Gainsboro;
+ private Color elapsedOuterColor = Color.DarkGreen;
+ private Color elapsedInnerColor = Color.Chartreuse;
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public DarkSlider()
+ {
+ InitializeComponent();
+ SetStyle(ControlStyles.AllPaintingInWmPaint
+ | ControlStyles.OptimizedDoubleBuffer
+ | ControlStyles.ResizeRedraw
+ | ControlStyles.Selectable
+ | ControlStyles.SupportsTransparentBackColor
+ | ControlStyles.UserMouse
+ | ControlStyles.UserPaint, true);
+
+ BackColor = Color.Transparent;
+
+ Minimum = 0;
+ Maximum = 100;
+ Value = 50;
+ }
+
+ #endregion
+
+ #region Paint
+
+ ///
+ /// Raises the event.
+ ///
+ /// A that contains the event data.
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ if (!Enabled)
+ {
+ DrawColorSlider(e.Graphics);
+ }
+ else
+ {
+ //if (mouseEffects && mouseInRegion)
+ //{
+ // Color[] lightenedColors = LightenColors(thumbOuterColor, thumbInnerColor, thumbPenColor,
+ // barOuterColor, barInnerColor, barPenColor,
+ // elapsedOuterColor, elapsedInnerColor);
+ // DrawColorSlider(e, lightenedColors[0], lightenedColors[1], lightenedColors[2], lightenedColors[3],
+ // lightenedColors[4], lightenedColors[5], lightenedColors[6], lightenedColors[7]);
+ //}
+ //else
+ {
+ DrawColorSlider(e.Graphics);
+ }
+ }
+ }
+
+ ///
+ /// Draws the colorslider control using passed colors.
+ ///
+ /// The instance containing the event data.
+ /// The thumb outer color paint.
+ /// The thumb inner color paint.
+ /// The thumb pen color paint.
+ /// The bar outer color paint.
+ /// The bar inner color paint.
+ /// The bar pen color paint.
+ /// The elapsed outer color paint.
+ /// The elapsed inner color paint.
+ private void DrawColorSlider(Graphics g)
+ {
+ try
+ {
+ //set up thumbRect aproprietly
+ int track = (((trackerValue - barMinimum) * (ClientRectangle.Width - thumbSize)) / (barMaximum - barMinimum));
+ thumbRect = new Rectangle(track, this.Height / 2 - 3, thumbSize - 1, 10);
+
+ //adjust drawing rects
+ barRect = new Rectangle(1, this.Height / 2, this.Width - 2, 5);
+
+ //get thumb shape path
+ GraphicsPath thumbPath = new GraphicsPath();
+ thumbPath.AddPolygon(new Point[] {
+ new Point(thumbRect.Left, thumbRect.Top),
+ new Point(thumbRect.Right, thumbRect.Top),
+ new Point(thumbRect.Right, thumbRect.Bottom - 4),
+ new Point(thumbRect.Left + thumbRect.Width / 2, thumbRect.Bottom),
+ new Point(thumbRect.Left, thumbRect.Bottom - 4)
+ });
+
+ Brush sliderLGBrushH = new LinearGradientBrush(barRect, ColorScheme.ColorGray122,
+ ColorScheme.ColorGray107, LinearGradientMode.Horizontal);
+
+ Brush barFill = (criticalPercent > 0 && trackerValue > criticalPercent) ? Brushes.Peru : Brushes.Green;
+
+ //draw bar
+ {
+ // Background gradient
+ g.FillRectangle(sliderLGBrushH, barRect);
+ // Background fill
+ g.FillRectangle(ColorScheme.SliderBorderBrush,
+ barRect.Left + 1, barRect.Top, barRect.Width - 2, barRect.Height - 1);
+ // Bar fill
+ g.FillRectangle(ColorScheme.SliderFillBrush,
+ barRect.Left + 2, barRect.Top + 1, barRect.Width - 4, barRect.Height - 3);
+ // Elapsed bar fill
+
+ g.FillRectangle(barFill,
+ barRect.Left + 2, barRect.Top + 1, thumbRect.Left + thumbSize / 2 - 2, barRect.Height - 3);
+
+ //draw bar band
+ //g.DrawRectangle(barPen, barRect);
+ }
+
+ sliderLGBrushH.Dispose();
+
+ //draw thumb
+ Brush brushInner = new LinearGradientBrush(thumbRect,
+ Color.FromArgb(111, 111, 111), Color.FromArgb(80, 80, 80),
+ LinearGradientMode.Vertical);
+
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+ g.FillPath(brushInner, thumbPath);
+ g.DrawPath(Pens.Black, thumbPath);
+
+ brushInner.Dispose();
+ //draw thumb band
+ //Color newThumbPenColor = thumbPenColorPaint;
+ //if (mouseEffects && (Capture || mouseInThumbRegion))
+ // newThumbPenColor = ControlPaint.Dark(newThumbPenColor);
+ //g.DrawPath(thumbPen, thumbPath);
+ }
+ catch (Exception)
+ { }
+ finally
+ { }
+ }
+
+ #endregion
+
+ #region Overided events
+
+ ///
+ /// Raises the event.
+ ///
+ /// An that contains the event data.
+ protected override void OnEnabledChanged(EventArgs e)
+ {
+ base.OnEnabledChanged(e);
+ Invalidate();
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// An that contains the event data.
+ protected override void OnMouseLeave(EventArgs e)
+ {
+ base.OnMouseLeave(e);
+ mouseInThumbRegion = false;
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// A that contains the event data.
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ base.OnMouseDown(e);
+ if (e.Button == MouseButtons.Left)
+ {
+ this.Capture = true;
+ OnValueChanging();
+ OnMouseMove(e);
+ }
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// A that contains the event data.
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ base.OnMouseMove(e);
+ mouseInThumbRegion = thumbRect.Contains(e.Location);
+ if (Capture & e.Button == MouseButtons.Left)
+ {
+ Point pt = e.Location;
+ int p = pt.X;
+ int margin = thumbSize >> 1;
+ p -= margin;
+ float coef = (float)(barMaximum - barMinimum) /
+ (float)(ClientSize.Width - 2 * margin);
+ trackerValue = (int)(p * coef + barMinimum);
+
+ if (trackerValue <= barMinimum)
+ {
+ trackerValue = barMinimum;
+ }
+ else if (trackerValue >= barMaximum)
+ {
+ trackerValue = barMaximum;
+ }
+
+ OnValueChanging();
+ }
+ Invalidate();
+ }
+
+ ///
+ /// Raises the event.
+ ///
+ /// A that contains the event data.
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ base.OnMouseUp(e);
+ this.Capture = false;
+ mouseInThumbRegion = thumbRect.Contains(e.Location);
+ OnValueChanged();
+ Invalidate();
+ }
+
+ #endregion
+
+ #region Help routines
+
+ ///
+ /// Sets the trackbar value so that it wont exceed allowed range.
+ ///
+ /// The value.
+ private void SetProperValue(int val)
+ {
+ if (val < barMinimum) Value = barMinimum;
+ else if (val > barMaximum) Value = barMaximum;
+ else Value = val;
+ }
+
+ #endregion
+ }
+}
diff --git a/Triangle.NET/TestApp/Controls/DarkTabControl.cs b/Triangle.NET/TestApp/Controls/DarkTabControl.cs
new file mode 100644
index 0000000..b191563
--- /dev/null
+++ b/Triangle.NET/TestApp/Controls/DarkTabControl.cs
@@ -0,0 +1,182 @@
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Drawing.Text;
+
+// CodeProject: A .NET Flat TabControl (CustomDraw), Oscar Londono
+
+namespace MeshExplorer.Controls
+{
+ ///
+ /// Summary description for FlatTabControl.
+ ///
+ public class DarkTabControl : System.Windows.Forms.TabControl
+ {
+ #region Designer
+
+ ///
+ /// 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()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+
+ #endregion
+
+ private const int margin = 5;
+ private Color backColor = ColorScheme.ColorGray68;
+
+ public DarkTabControl()
+ {
+ // This call is required by the Windows.Forms Form Designer.
+ InitializeComponent();
+
+ base.Multiline = false;
+
+ // double buffering
+ this.SetStyle(ControlStyles.UserPaint, true);
+ this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+ this.SetStyle(ControlStyles.DoubleBuffer, true);
+ this.SetStyle(ControlStyles.ResizeRedraw, true);
+ this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+
+ this.SelectedIndexChanged += (obj, evt) => { Invalidate(); };
+ }
+
+ #region Properties
+
+ new public TabAlignment Alignment
+ {
+ get { return base.Alignment; }
+ set
+ {
+ TabAlignment ta = value;
+ if ((ta != TabAlignment.Top) && (ta != TabAlignment.Bottom))
+ {
+ ta = TabAlignment.Top;
+ }
+
+ base.Alignment = ta;
+ }
+ }
+
+ public override Color BackColor
+ {
+ get
+ {
+ return backColor;
+ }
+ set
+ {
+ base.BackColor = backColor;
+ }
+ }
+
+ #endregion
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ base.OnPaint(e);
+
+ DrawControl(e.Graphics);
+ }
+
+ private void DrawControl(Graphics g)
+ {
+ if (!Visible)
+ {
+ return;
+ }
+
+ Rectangle controlBounds = this.ClientRectangle;
+ Rectangle tabBounds = this.DisplayRectangle;
+
+ // Fill client area
+ Brush br = new SolidBrush(this.BackColor);
+ g.FillRectangle(br, controlBounds);
+ br.Dispose();
+
+ int width = tabBounds.Width + margin;
+
+ // Clip region for drawing tabs
+ Region clip = g.Clip;
+ Rectangle region = new Rectangle(tabBounds.Left, controlBounds.Top, width - margin, controlBounds.Height);
+
+ g.SetClip(region);
+
+ // Draw tabs
+ for (int i = 0; i < this.TabCount; i++)
+ {
+ DrawTab(g, this.TabPages[i], i);
+ }
+
+ g.Clip = clip;
+ }
+
+ private void DrawTab(Graphics g, TabPage tabPage, int index)
+ {
+ Rectangle tabBounds = this.GetTabRect(index);
+
+ bool selected = (this.SelectedIndex == index);
+
+ // Fill this tab with background color
+ g.FillRectangle(selected ? Brushes.DimGray : ColorScheme.BrushGray68, tabBounds);
+
+ if (selected)
+ {
+ // Clear bottom lines
+ Pen pen = new Pen(tabPage.BackColor);
+
+ switch (this.Alignment)
+ {
+ case TabAlignment.Top:
+ g.DrawLine(pen, tabBounds.Left, tabBounds.Bottom, tabBounds.Right - 1, tabBounds.Bottom);
+ g.DrawLine(pen, tabBounds.Left, tabBounds.Bottom + 1, tabBounds.Right - 1, tabBounds.Bottom + 1);
+ break;
+
+ case TabAlignment.Bottom:
+ g.DrawLine(pen, tabBounds.Left, tabBounds.Top, tabBounds.Right - 1, tabBounds.Top);
+ g.DrawLine(pen, tabBounds.Left, tabBounds.Top - 1, tabBounds.Right - 1, tabBounds.Top - 1);
+ g.DrawLine(pen, tabBounds.Left, tabBounds.Top - 2, tabBounds.Right - 1, tabBounds.Top - 2);
+ break;
+ }
+
+ pen.Dispose();
+ }
+
+ // Draw string
+ StringFormat stringFormat = new StringFormat();
+ stringFormat.Alignment = StringAlignment.Center;
+ stringFormat.LineAlignment = StringAlignment.Center;
+
+ g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
+
+ g.DrawString(tabPage.Text, Font, Brushes.White, tabBounds, stringFormat);
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Controls/DarkTextBox.cs b/Triangle.NET/TestApp/Controls/DarkTextBox.cs
index b0f7ff5..f92cc78 100644
--- a/Triangle.NET/TestApp/Controls/DarkTextBox.cs
+++ b/Triangle.NET/TestApp/Controls/DarkTextBox.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp.Controls
+namespace MeshExplorer.Controls
{
using System;
using System.Collections.Generic;
diff --git a/Triangle.NET/TestApp/Controls/DarkToolStripRenderer.cs b/Triangle.NET/TestApp/Controls/DarkToolStripRenderer.cs
new file mode 100644
index 0000000..d55cae6
--- /dev/null
+++ b/Triangle.NET/TestApp/Controls/DarkToolStripRenderer.cs
@@ -0,0 +1,66 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.Controls
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Windows.Forms;
+ using System.Drawing;
+
+ ///
+ /// TODO: Update summary.
+ ///
+ public class DarkToolStripRenderer : ToolStripRenderer
+ {
+ protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
+ {
+ e.TextColor = e.Item.Enabled ? Color.White : Color.Gray;
+
+ base.OnRenderItemText(e);
+ }
+
+ protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
+ {
+ if (!e.Item.Selected && !e.Item.Pressed)
+ {
+ e.ArrowColor = ColorScheme.ColorGray89;
+ }
+
+ base.OnRenderArrow(e);
+ }
+
+ protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
+ {
+ e.Graphics.FillRectangle(ColorScheme.BrushGray78, 0, 2, e.Item.Width, 1);
+ }
+
+ protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
+ {
+ if (e.Item.Enabled)
+ {
+ if (e.Item.Selected || e.Item.Pressed)
+ {
+ e.Graphics.FillRectangle(Brushes.DimGray, 0, 0, e.Item.Width, e.Item.Height);
+ }
+ else
+ {
+ e.Graphics.FillRectangle(ColorScheme.BrushGray68, 0, 0, e.Item.Width, e.Item.Height);
+ }
+ }
+
+ //base.OnRenderMenuItemBackground(e);
+ }
+
+ protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
+ {
+ e.Graphics.FillRectangle(ColorScheme.BrushGray68, e.AffectedBounds);
+ //base.OnRenderToolStripBackground(e);
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Controls/MeshRenderer.cs b/Triangle.NET/TestApp/Controls/MeshRenderer.cs
index 632f318..98b72b8 100644
--- a/Triangle.NET/TestApp/Controls/MeshRenderer.cs
+++ b/Triangle.NET/TestApp/Controls/MeshRenderer.cs
@@ -4,24 +4,24 @@
//
// -----------------------------------------------------------------------
-namespace TestApp
+namespace MeshExplorer.Controls
{
using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Windows.Forms;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Drawing.Drawing2D;
- using TriangleNet;
using System.Diagnostics;
+ using System.Drawing;
+ using System.Drawing.Drawing2D;
+ using System.Drawing.Text;
+ using System.Windows.Forms;
+ using MeshExplorer.Rendering;
+ using TriangleNet;
using TriangleNet.IO;
- using TestApp.Rendering;
+ using TriangleNet.Data;
+ using TriangleNet.Geometry;
///
/// Renders a mesh using GDI.
///
- public class MeshRenderer : System.Windows.Forms.Control
+ public class MeshRenderer : Control
{
// Rendering stuff
private BufferedGraphics buffer;
@@ -33,7 +33,12 @@ namespace TestApp
RenderData data;
bool initialized = false;
+ string coordinate = String.Empty;
+
+ Timer timer;
+
public long RenderTime { get; private set; }
+ public RenderData Data { get { return data; } }
public MeshRenderer()
{
@@ -44,39 +49,48 @@ namespace TestApp
zoom = new Zoom();
context = new BufferedGraphicsContext();
data = new RenderData();
+
+ timer = new Timer();
+ timer.Interval = 3000;
+ timer.Tick += (sender, e) => {
+ timer.Stop();
+ coordinate = String.Empty;
+ this.Invalidate();
+ };
}
- public void SetData(MeshData meshdata, bool input)
+ public void Initialize()
{
- data.SetData(meshdata);
-
- if (input)
- {
- // Reset the zoom on new data
- zoom.Initialize(this.ClientRectangle, data.Bounds);
- }
+ zoom.Initialize(this.ClientRectangle, this.ClientRectangle);
+ InitializeBuffer();
initialized = true;
- this.Render();
+ this.Invalidate();
}
- public void SetData(Mesh mesh, bool input)
+ public void SetData(InputGeometry mesh)
{
data.SetData(mesh);
- if (input)
- {
- // Reset the zoom on new data
- zoom.Initialize(this.ClientRectangle, data.Bounds);
- }
-
+ // Reset the zoom on new data
+ zoom.Initialize(this.ClientRectangle, data.Bounds);
+
initialized = true;
this.Render();
}
- public void Zoom(Point location, int delta)
+ public void SetData(Mesh mesh)
+ {
+ data.SetData(mesh);
+
+ initialized = true;
+
+ this.Render();
+ }
+
+ public void Zoom(PointF location, int delta)
{
if (!initialized) return;
@@ -87,7 +101,13 @@ namespace TestApp
}
}
- private void IntializeBuffer()
+ public void HandleResize()
+ {
+ zoom.Resize(this.ClientRectangle, data.Bounds);
+ InitializeBuffer();
+ }
+
+ private void InitializeBuffer()
{
if (this.Width > 0 && this.Height > 0)
{
@@ -95,6 +115,8 @@ namespace TestApp
{
if (this.ClientRectangle == buffer.Graphics.VisibleClipBounds)
{
+ this.Invalidate();
+
// Bounds didn't change. Probably we just restored the window
// from minimized state.
return;
@@ -150,21 +172,18 @@ namespace TestApp
PointF p0, p1, p2;
PointF[] pts = data.Points;
- int[] tri;
+ var triangles = data.Triangles;
// Draw triangles
- int n = data.Triangles.Length;
- for (int i = 0; i < n; i++)
+ foreach (var tri in triangles)
{
- tri = data.Triangles[i];
-
- if (zoom.ViewportContains(pts[tri[0]]) ||
- zoom.ViewportContains(pts[tri[1]]) ||
- zoom.ViewportContains(pts[tri[2]]))
+ if (zoom.ViewportContains(pts[tri.P0]) ||
+ zoom.ViewportContains(pts[tri.P1]) ||
+ zoom.ViewportContains(pts[tri.P2]))
{
- p0 = zoom.WorldToScreen(pts[tri[0]]);
- p1 = zoom.WorldToScreen(pts[tri[1]]);
- p2 = zoom.WorldToScreen(pts[tri[2]]);
+ p0 = zoom.WorldToScreen(pts[tri.P0]);
+ p1 = zoom.WorldToScreen(pts[tri.P1]);
+ p2 = zoom.WorldToScreen(pts[tri.P2]);
g.DrawLine(lines, p0, p1);
g.DrawLine(lines, p1, p2);
@@ -178,19 +197,16 @@ namespace TestApp
PointF p0, p1;
PointF[] pts = data.Points;
- int[] tri;
+ var edges = data.Edges;
- // Draw triangles
- int n = data.Edges.Length;
- for (int i = 0; i < n; i++)
+ // Draw edges
+ foreach (var edge in edges)
{
- tri = data.Edges[i];
-
- if (zoom.ViewportContains(pts[tri[0]]) ||
- zoom.ViewportContains(pts[tri[1]]))
+ if (zoom.ViewportContains(pts[edge.P0]) ||
+ zoom.ViewportContains(pts[edge.P1]))
{
- p0 = zoom.WorldToScreen(pts[tri[0]]);
- p1 = zoom.WorldToScreen(pts[tri[1]]);
+ p0 = zoom.WorldToScreen(pts[edge.P0]);
+ p1 = zoom.WorldToScreen(pts[edge.P1]);
g.DrawLine(lines, p0, p1);
}
@@ -202,19 +218,15 @@ namespace TestApp
PointF p0, p1;
PointF[] pts = data.Points;
- int[] tri;
+ var segments = data.Segments;
- // Draw triangles
- int n = data.Segments.Length;
- for (int i = 0; i < n; i++)
+ foreach (var seg in segments)
{
- tri = data.Segments[i];
-
- if (zoom.ViewportContains(pts[tri[0]]) ||
- zoom.ViewportContains(pts[tri[1]]))
+ if (zoom.ViewportContains(pts[seg.P0]) ||
+ zoom.ViewportContains(pts[seg.P1]))
{
- p0 = zoom.WorldToScreen(pts[tri[0]]);
- p1 = zoom.WorldToScreen(pts[tri[1]]);
+ p0 = zoom.WorldToScreen(pts[seg.P0]);
+ p1 = zoom.WorldToScreen(pts[seg.P1]);
g.DrawLine(Pens.DarkBlue, p0, p1);
}
@@ -223,10 +235,12 @@ namespace TestApp
private void Render()
{
+ coordinate = String.Empty;
+
Graphics g = buffer.Graphics;
g.Clear(this.BackColor);
- if (!initialized)
+ if (!initialized || data == null)
{
return;
}
@@ -250,7 +264,10 @@ namespace TestApp
this.RenderSegments(g);
}
- this.RenderPoints(g);
+ if (data.Points != null)
+ {
+ this.RenderPoints(g);
+ }
stopwatch.Stop();
@@ -263,28 +280,20 @@ namespace TestApp
protected override void OnPaint(PaintEventArgs pe)
{
- Graphics g = buffer.Graphics;
- g.SmoothingMode = SmoothingMode.Default;
-
- Pen pen1 = new Pen(Color.FromArgb(82, 82, 82));
- Pen pen2 = new Pen(Color.FromArgb(40, 40, 40));
-
- g.DrawLine(pen1, 0, 0, this.Width, 0);
- g.DrawLine(pen2, 0, 1, this.Width, 1);
-
- pen1.Dispose();
- pen2.Dispose();
+ if (!initialized)
+ {
+ base.OnPaint(pe);
+ return;
+ }
buffer.Render();
- }
- protected override void OnClientSizeChanged(EventArgs e)
- {
- if (buffer == null) return;
-
- // Redraw
-
- base.OnClientSizeChanged(e);
+ if (!String.IsNullOrEmpty(coordinate) && data.Points != null)
+ {
+ Graphics g = pe.Graphics;
+ g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
+ g.DrawString(coordinate, this.Font, Brushes.White, 10, 10);
+ }
}
protected override void OnMouseClick(MouseEventArgs e)
@@ -296,6 +305,20 @@ namespace TestApp
zoom.Reset();
this.Render();
}
+ else if (e.Button == MouseButtons.Left)
+ {
+ // Just in case ...
+ timer.Stop();
+
+ PointF c = zoom.ScreenToWorld((float)e.X / this.Width, (float)e.Y / this.Height);
+ coordinate = String.Format("X:{0} Y:{1}",
+ c.X.ToString(Util.Nfi),
+ c.Y.ToString(Util.Nfi));
+
+ this.Invalidate();
+
+ timer.Start();
+ }
base.OnMouseClick(e);
}
@@ -303,15 +326,10 @@ namespace TestApp
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// Do nothing
- }
-
- protected override void OnResize(EventArgs e)
- {
- base.OnResize(e);
-
- IntializeBuffer();
-
- //zoom.Initialize(this.ClientRectangle, data.Bounds);
+ if (!initialized)
+ {
+ base.OnPaintBackground(pevent);
+ }
}
#endregion
diff --git a/Triangle.NET/TestApp/DarkMessageBox.cs b/Triangle.NET/TestApp/DarkMessageBox.cs
new file mode 100644
index 0000000..4fc2a22
--- /dev/null
+++ b/Triangle.NET/TestApp/DarkMessageBox.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+
+namespace MeshExplorer
+{
+ class DarkMessageBox : Form
+ {
+ #region Designer
+
+ ///
+ /// 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.btnClose = new MeshExplorer.Controls.DarkButton();
+ this.btnShowLog = new MeshExplorer.Controls.DarkButton();
+ this.lbMessage = new System.Windows.Forms.Label();
+ this.lbInfo = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // btnClose
+ //
+ this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.btnClose.Location = new System.Drawing.Point(336, 87);
+ this.btnClose.Name = "btnClose";
+ this.btnClose.Size = new System.Drawing.Size(92, 23);
+ this.btnClose.TabIndex = 0;
+ this.btnClose.Text = "Close";
+ this.btnClose.UseVisualStyleBackColor = true;
+ //
+ // btnShowLog
+ //
+ this.btnShowLog.DialogResult = System.Windows.Forms.DialogResult.OK;
+ this.btnShowLog.Location = new System.Drawing.Point(234, 87);
+ this.btnShowLog.Name = "btnShowLog";
+ this.btnShowLog.Size = new System.Drawing.Size(92, 23);
+ this.btnShowLog.TabIndex = 1;
+ this.btnShowLog.Text = "Show Log";
+ this.btnShowLog.UseVisualStyleBackColor = true;
+ //
+ // lbMessage
+ //
+ this.lbMessage.BackColor = System.Drawing.Color.Transparent;
+ this.lbMessage.ForeColor = System.Drawing.Color.White;
+ this.lbMessage.Location = new System.Drawing.Point(12, 9);
+ this.lbMessage.Name = "lbMessage";
+ this.lbMessage.Size = new System.Drawing.Size(412, 30);
+ this.lbMessage.TabIndex = 2;
+ this.lbMessage.Text = "Message";
+ //
+ // lbInfo
+ //
+ this.lbInfo.AutoSize = true;
+ this.lbInfo.BackColor = System.Drawing.Color.Transparent;
+ this.lbInfo.ForeColor = System.Drawing.Color.White;
+ this.lbInfo.Location = new System.Drawing.Point(12, 47);
+ this.lbInfo.Name = "lbInfo";
+ this.lbInfo.Size = new System.Drawing.Size(28, 13);
+ this.lbInfo.TabIndex = 3;
+ this.lbInfo.Text = "Info";
+ //
+ // DarkMessageBox
+ //
+ 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(436, 118);
+ this.Controls.Add(this.lbInfo);
+ this.Controls.Add(this.lbMessage);
+ this.Controls.Add(this.btnShowLog);
+ this.Controls.Add(this.btnClose);
+ this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "DarkMessageBox";
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+ this.Text = "Message Box";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private Controls.DarkButton btnClose;
+ private Label lbMessage;
+ private Label lbInfo;
+ private Controls.DarkButton btnShowLog;
+
+ #endregion
+
+ public DarkMessageBox()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ base.OnPaint(e);
+
+ var rect = this.ClientRectangle;
+ rect.Height -= 40;
+
+ e.Graphics.FillRectangle(Brushes.DimGray, rect);
+ }
+
+ public static DialogResult Show(string title, string message, string info, bool log)
+ {
+ DarkMessageBox m = new DarkMessageBox();
+
+ if (!log)
+ {
+ m.btnShowLog.Enabled = false;
+ m.btnShowLog.Visible = false;
+ }
+
+ m.Text = title;
+
+ m.lbInfo.Text = info;
+ m.lbMessage.Text = message;
+
+ return m.ShowDialog();
+ }
+
+ public static DialogResult Show(string title, string message, string info)
+ {
+ return Show(title, message, info, false);
+ }
+
+ public static DialogResult Show(string title, string message)
+ {
+ return Show(title, message, "", false);
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Examples.cs b/Triangle.NET/TestApp/Examples.cs
index e175a52..9ce16a4 100644
--- a/Triangle.NET/TestApp/Examples.cs
+++ b/Triangle.NET/TestApp/Examples.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp
+namespace MeshExplorer
{
using System;
using System.Collections.Generic;
@@ -12,10 +12,10 @@ namespace TestApp
using System.Text;
using TriangleNet;
using TriangleNet.IO;
+ using TriangleNet.Geometry;
///
/// Code of the online examples.
- ///
///
public static class Examples
{
@@ -39,7 +39,7 @@ namespace TestApp
// Read face polygon file and gernerate the delaunay triangulation
// of the PSLG. We reuse the mesh instance here.
- MeshData data = FileReader.ReadFile(pathToData + "face.poly");
+ InputGeometry data = FileReader.ReadFile(pathToData + "face.poly");
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "face.png", 200);
@@ -62,7 +62,7 @@ namespace TestApp
// Read spiral node file and gernerate the delaunay triangulation.
// Set the mesh quality option to true, which will set a default
// minimum angle of 20 degrees.
- MeshData data = FileReader.ReadNodeFile(pathToData + "spiral.node");
+ InputGeometry data = FileReader.ReadNodeFile(pathToData + "spiral.node");
mesh.SetOption(Options.Quality, true);
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "spiral-Angle-20.png", 200);
@@ -116,5 +116,74 @@ namespace TestApp
mesh.Refine();
ImageWriter.WritePng(mesh, "box-Refine-3.png", 200);
}
+
+ ///
+ /// Drawing the Voronoi diagram.
+ ///
+ public static void Example4()
+ {
+ ImageWriter.SetColorSchemeLight();
+
+ // Create mesh data (random point set)
+ //data.Points = Util.CreateCirclePoints(0, 0, 5, 50); // Ooops, TODO !!!
+ InputGeometry data = PolygonGenerator.CreateStarPoints(0, 0, 5, 10);
+
+ // Create a mesh instance.
+ Mesh mesh = new Mesh();
+
+ // Gernerate a delaunay triangulation
+ mesh.Triangulate(data);
+ ImageWriter.WritePng(mesh, "circle-mesh.png", 400);
+ ImageWriter.WriteVoronoiPng(mesh, "circle-voronoi.png", 400);
+ }
+
+ ///
+ /// Smoothing a mesh.
+ ///
+ public static void Example5()
+ {
+ ImageWriter.SetColorSchemeLight();
+
+ // Create a mesh instance.
+ Mesh mesh = new Mesh();
+
+ mesh.SetOption(Options.Quality, true);
+ mesh.SetOption(Options.MinAngle, 25);
+ mesh.SetOption(Options.MaxArea, 0.0075);
+ mesh.Triangulate(pathToData + "Smooth-Slit.poly");
+ mesh.Smooth();
+
+ ImageWriter.WritePng(mesh, "slit-smooth.png", 300);
+ }
+
+ ///
+ /// Smoothing a mesh.
+ ///
+ public static void ExampleXYZ()
+ {
+ ImageWriter.SetColorSchemeLight();
+
+ Mesh mesh = new Mesh();
+
+ mesh.SetOption(Options.Quality, true);
+ mesh.SetOption(Options.MinAngle, 25);
+ mesh.SetOption(Options.MaxArea, 0.05);
+
+ mesh.Triangulate(pathToData + "Smooth-Square.poly");
+
+ ImageWriter.WritePng(mesh, "test1.png", 300);
+
+ mesh.SetOption(Options.MaxArea, 0.01);
+
+ // Refine with new max area
+ mesh.Refine();
+
+ ImageWriter.WritePng(mesh, "test2.png", 300);
+
+ mesh.SetOption(Options.SteinerPoints, 50);
+ mesh.Triangulate(pathToData + "Smooth-Square.poly");
+
+ ImageWriter.WritePng(mesh, "test3.png", 300);
+ }
}
}
diff --git a/Triangle.NET/TestApp/FormLog.Designer.cs b/Triangle.NET/TestApp/FormLog.Designer.cs
new file mode 100644
index 0000000..0e3347e
--- /dev/null
+++ b/Triangle.NET/TestApp/FormLog.Designer.cs
@@ -0,0 +1,89 @@
+namespace MeshExplorer
+{
+ partial class FormLog
+ {
+ ///
+ /// 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.listLog = new System.Windows.Forms.ListView();
+ this.colMessage = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.colInfo = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.SuspendLayout();
+ //
+ // listLog
+ //
+ this.listLog.BackColor = System.Drawing.Color.White;
+ this.listLog.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.listLog.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.colMessage,
+ this.colInfo});
+ this.listLog.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.listLog.ForeColor = System.Drawing.Color.White;
+ this.listLog.FullRowSelect = true;
+ this.listLog.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
+ this.listLog.Location = new System.Drawing.Point(0, 0);
+ this.listLog.Name = "listLog";
+ this.listLog.Size = new System.Drawing.Size(584, 262);
+ this.listLog.TabIndex = 2;
+ this.listLog.UseCompatibleStateImageBehavior = false;
+ this.listLog.View = System.Windows.Forms.View.Details;
+ this.listLog.DoubleClick += new System.EventHandler(this.listLog_DoubleClick);
+ //
+ // colMessage
+ //
+ this.colMessage.Text = "Message";
+ this.colMessage.Width = 350;
+ //
+ // colInfo
+ //
+ this.colInfo.Text = "Info";
+ this.colInfo.Width = 200;
+ //
+ // FormLog
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(584, 262);
+ this.Controls.Add(this.listLog);
+ this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "FormLog";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.Text = "Log";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormLog_FormClosing);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.ListView listLog;
+ private System.Windows.Forms.ColumnHeader colMessage;
+ private System.Windows.Forms.ColumnHeader colInfo;
+ }
+}
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/FormLog.cs b/Triangle.NET/TestApp/FormLog.cs
new file mode 100644
index 0000000..5ecf4af
--- /dev/null
+++ b/Triangle.NET/TestApp/FormLog.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using TriangleNet.Log;
+
+namespace MeshExplorer
+{
+ public partial class FormLog : Form
+ {
+ public FormLog()
+ {
+ InitializeComponent();
+ }
+
+ public void UpdateItems()
+ {
+ listLog.Items.Clear();
+
+ ILog log = SimpleLog.Instance;
+
+ foreach (var item in log.Data)
+ {
+ listLog.Items.Add(CreateListViewItem(item));
+ }
+ }
+
+ private ListViewItem CreateListViewItem(SimpleLogItem item)
+ {
+ ListViewItem lvi = new ListViewItem(new string[] { item.Message, item.Info });
+
+ if (item.Level == LogLevel.Error)
+ {
+ lvi.ForeColor = Color.DarkRed;
+ }
+ else if (item.Level == LogLevel.Warning)
+ {
+ lvi.ForeColor = Color.Peru;
+ }
+ else
+ {
+ lvi.ForeColor = Color.Black;
+ }
+
+ lvi.UseItemStyleForSubItems = true;
+
+ return lvi;
+ }
+
+ private void FormLog_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason == CloseReason.UserClosing)
+ {
+ e.Cancel = true;
+ this.Hide();
+ }
+ }
+
+ private void listLog_DoubleClick(object sender, EventArgs e)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ foreach (var item in listLog.SelectedItems)
+ {
+ GetRowText(sb, item);
+ }
+
+ if (sb.Length > 0)
+ {
+ Clipboard.SetText(sb.ToString());
+ }
+ }
+
+ private void GetRowText(StringBuilder sb, object item)
+ {
+ var row = item as ListViewItem;
+
+ if (row != null)
+ {
+ foreach (var col in row.SubItems)
+ {
+ var lvi = col as ListViewItem.ListViewSubItem;
+
+ if (lvi != null)
+ {
+ sb.AppendLine(lvi.Text);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/FormMain.Designer.cs b/Triangle.NET/TestApp/FormMain.Designer.cs
index 189484a..a52ccd9 100644
--- a/Triangle.NET/TestApp/FormMain.Designer.cs
+++ b/Triangle.NET/TestApp/FormMain.Designer.cs
@@ -1,4 +1,4 @@
-namespace TestApp
+namespace MeshExplorer
{
partial class FormMain
{
@@ -28,148 +28,846 @@
///
private void InitializeComponent()
{
- this.btnStatistic = new TestApp.Controls.DarkButton();
- this.tbNumPoints = new TestApp.Controls.DarkTextBox();
- this.cbConvex = new TestApp.Controls.DarkCheckBox();
- this.cbQuality = new TestApp.Controls.DarkCheckBox();
- this.btnRun = new TestApp.Controls.DarkButton();
- this.btnOpen = new TestApp.Controls.DarkButton();
- this.btnRandPts = new TestApp.Controls.DarkButton();
- this.meshRenderer1 = new TestApp.MeshRenderer();
- this.lbTime = new System.Windows.Forms.Label();
+ this.splitContainer1 = new System.Windows.Forms.SplitContainer();
+ this.btnSmooth = new MeshExplorer.Controls.DarkButton();
+ this.btnMesh = new MeshExplorer.Controls.DarkButton();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.lbNumSeg = new System.Windows.Forms.Label();
+ this.lbNumSeg2 = new System.Windows.Forms.Label();
+ this.lbNumTri = new System.Windows.Forms.Label();
+ this.lbNumTri2 = new System.Windows.Forms.Label();
+ this.lbNumVert = new System.Windows.Forms.Label();
+ this.lbNumVert2 = new System.Windows.Forms.Label();
+ this.flatTabControl1 = new MeshExplorer.Controls.DarkTabControl();
+ this.tabPage1 = new System.Windows.Forms.TabPage();
+ this.lbMaxArea = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ this.lbMinAngle = new System.Windows.Forms.Label();
+ this.label9 = new System.Windows.Forms.Label();
+ this.label8 = new System.Windows.Forms.Label();
+ this.label5 = new System.Windows.Forms.Label();
+ this.slMaxArea = new MeshExplorer.Controls.DarkSlider();
+ this.slMinAngle = new MeshExplorer.Controls.DarkSlider();
+ this.cbConvex = new MeshExplorer.Controls.DarkCheckBox();
+ this.cbQuality = new MeshExplorer.Controls.DarkCheckBox();
+ this.tabPage2 = new System.Windows.Forms.TabPage();
+ this.label13 = new System.Windows.Forms.Label();
+ this.label12 = new System.Windows.Forms.Label();
+ this.label16 = new System.Windows.Forms.Label();
+ this.label15 = new System.Windows.Forms.Label();
+ this.label14 = new System.Windows.Forms.Label();
+ this.lbAngleMax = new System.Windows.Forms.Label();
+ this.lbRatioMax = new System.Windows.Forms.Label();
+ this.lbEdgeMax = new System.Windows.Forms.Label();
+ this.lbAreaMax = new System.Windows.Forms.Label();
+ this.lbAngleMin = new System.Windows.Forms.Label();
+ this.lbRatioMin = new System.Windows.Forms.Label();
+ this.lbEdgeMin = new System.Windows.Forms.Label();
+ this.lbAreaMin = new System.Windows.Forms.Label();
+ this.label10 = new System.Windows.Forms.Label();
+ this.label17 = new System.Windows.Forms.Label();
+ this.label11 = new System.Windows.Forms.Label();
+ this.angleHistogram1 = new MeshExplorer.Controls.AngleHistogram();
+ this.tabPage3 = new System.Windows.Forms.TabPage();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label7 = new System.Windows.Forms.Label();
+ this.lbShortcuts = new System.Windows.Forms.Label();
+ this.menuStrip1 = new System.Windows.Forms.MenuStrip();
+ this.fileMenu = new System.Windows.Forms.ToolStripMenuItem();
+ this.fileMenuOpen = new System.Windows.Forms.ToolStripMenuItem();
+ this.fileMenuSave = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ this.fileMenuQuit = new System.Windows.Forms.ToolStripMenuItem();
+ this.viewMenu = new System.Windows.Forms.ToolStripMenuItem();
+ this.viewMenuMQuality = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.viewMenuLog = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolsMenu = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolsMenuGen = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolsMenuPoly1 = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolsMenuRandPts = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolsMenuCheck = new System.Windows.Forms.ToolStripMenuItem();
+ this.meshRenderer1 = new MeshExplorer.Controls.MeshRenderer();
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
+ this.splitContainer1.Panel1.SuspendLayout();
+ this.splitContainer1.Panel2.SuspendLayout();
+ this.splitContainer1.SuspendLayout();
+ this.flatTabControl1.SuspendLayout();
+ this.tabPage1.SuspendLayout();
+ this.tabPage2.SuspendLayout();
+ this.tabPage3.SuspendLayout();
+ this.menuStrip1.SuspendLayout();
this.SuspendLayout();
//
- // btnStatistic
+ // splitContainer1
//
- this.btnStatistic.Location = new System.Drawing.Point(847, 12);
- this.btnStatistic.Name = "btnStatistic";
- this.btnStatistic.Size = new System.Drawing.Size(75, 23);
- this.btnStatistic.TabIndex = 11;
- this.btnStatistic.Text = "Statistic";
- this.btnStatistic.UseVisualStyleBackColor = true;
- this.btnStatistic.Click += new System.EventHandler(this.btnStatistic_Click);
+ this.splitContainer1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(68)))), ((int)(((byte)(68)))), ((int)(((byte)(68)))));
+ this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
+ this.splitContainer1.IsSplitterFixed = true;
+ this.splitContainer1.Location = new System.Drawing.Point(0, 0);
+ this.splitContainer1.Name = "splitContainer1";
//
- // tbNumPoints
+ // splitContainer1.Panel1
//
- this.tbNumPoints.BackColor = System.Drawing.Color.DimGray;
- this.tbNumPoints.Cursor = System.Windows.Forms.Cursors.IBeam;
- this.tbNumPoints.ForeColor = System.Drawing.Color.LightGray;
- this.tbNumPoints.Location = new System.Drawing.Point(244, 13);
- this.tbNumPoints.Name = "tbNumPoints";
- this.tbNumPoints.Size = new System.Drawing.Size(60, 21);
- this.tbNumPoints.TabIndex = 10;
- this.tbNumPoints.Text = "1000";
- this.tbNumPoints.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ this.splitContainer1.Panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.splitContainer1.Panel1.Controls.Add(this.btnSmooth);
+ this.splitContainer1.Panel1.Controls.Add(this.btnMesh);
+ this.splitContainer1.Panel1.Controls.Add(this.label4);
+ this.splitContainer1.Panel1.Controls.Add(this.label3);
+ this.splitContainer1.Panel1.Controls.Add(this.label2);
+ this.splitContainer1.Panel1.Controls.Add(this.lbNumSeg);
+ this.splitContainer1.Panel1.Controls.Add(this.lbNumSeg2);
+ this.splitContainer1.Panel1.Controls.Add(this.lbNumTri);
+ this.splitContainer1.Panel1.Controls.Add(this.lbNumTri2);
+ this.splitContainer1.Panel1.Controls.Add(this.lbNumVert);
+ this.splitContainer1.Panel1.Controls.Add(this.lbNumVert2);
+ this.splitContainer1.Panel1.Controls.Add(this.flatTabControl1);
+ this.splitContainer1.Panel1.Controls.Add(this.menuStrip1);
+ //
+ // splitContainer1.Panel2
+ //
+ this.splitContainer1.Panel2.BackColor = System.Drawing.Color.Black;
+ this.splitContainer1.Panel2.Controls.Add(this.meshRenderer1);
+ this.splitContainer1.Size = new System.Drawing.Size(984, 612);
+ this.splitContainer1.SplitterDistance = 280;
+ this.splitContainer1.SplitterWidth = 1;
+ this.splitContainer1.TabIndex = 0;
+ //
+ // btnSmooth
+ //
+ this.btnSmooth.Enabled = false;
+ this.btnSmooth.Location = new System.Drawing.Point(150, 196);
+ this.btnSmooth.Name = "btnSmooth";
+ this.btnSmooth.Size = new System.Drawing.Size(126, 23);
+ this.btnSmooth.TabIndex = 12;
+ this.btnSmooth.Text = "Smooth";
+ this.btnSmooth.UseVisualStyleBackColor = true;
+ this.btnSmooth.Click += new System.EventHandler(this.btnSmooth_Click);
+ //
+ // btnMesh
+ //
+ this.btnMesh.Enabled = false;
+ this.btnMesh.Location = new System.Drawing.Point(4, 196);
+ this.btnMesh.Name = "btnMesh";
+ this.btnMesh.Size = new System.Drawing.Size(126, 23);
+ this.btnMesh.TabIndex = 12;
+ this.btnMesh.Text = "Triangulate";
+ this.btnMesh.UseVisualStyleBackColor = true;
+ this.btnMesh.Click += new System.EventHandler(this.btnMesh_Click);
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.ForeColor = System.Drawing.Color.Gray;
+ this.label4.Location = new System.Drawing.Point(12, 121);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(60, 13);
+ this.label4.TabIndex = 7;
+ this.label4.Text = "Segments:";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.ForeColor = System.Drawing.Color.Gray;
+ this.label3.Location = new System.Drawing.Point(12, 142);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(56, 13);
+ this.label3.TabIndex = 9;
+ this.label3.Text = "Triangles:";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.ForeColor = System.Drawing.Color.Gray;
+ this.label2.Location = new System.Drawing.Point(12, 100);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(50, 13);
+ this.label2.TabIndex = 11;
+ this.label2.Text = "Vertices:";
+ //
+ // lbNumSeg
+ //
+ this.lbNumSeg.ForeColor = System.Drawing.Color.White;
+ this.lbNumSeg.Location = new System.Drawing.Point(95, 121);
+ this.lbNumSeg.Name = "lbNumSeg";
+ this.lbNumSeg.Size = new System.Drawing.Size(70, 13);
+ this.lbNumSeg.TabIndex = 3;
+ this.lbNumSeg.Text = "-";
+ this.lbNumSeg.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbNumSeg2
+ //
+ this.lbNumSeg2.ForeColor = System.Drawing.Color.Gray;
+ this.lbNumSeg2.Location = new System.Drawing.Point(182, 121);
+ this.lbNumSeg2.Name = "lbNumSeg2";
+ this.lbNumSeg2.Size = new System.Drawing.Size(70, 13);
+ this.lbNumSeg2.TabIndex = 3;
+ this.lbNumSeg2.Text = "-";
+ this.lbNumSeg2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbNumTri
+ //
+ this.lbNumTri.ForeColor = System.Drawing.Color.White;
+ this.lbNumTri.Location = new System.Drawing.Point(95, 142);
+ this.lbNumTri.Name = "lbNumTri";
+ this.lbNumTri.Size = new System.Drawing.Size(70, 13);
+ this.lbNumTri.TabIndex = 2;
+ this.lbNumTri.Text = "-";
+ this.lbNumTri.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbNumTri2
+ //
+ this.lbNumTri2.ForeColor = System.Drawing.Color.Gray;
+ this.lbNumTri2.Location = new System.Drawing.Point(182, 142);
+ this.lbNumTri2.Name = "lbNumTri2";
+ this.lbNumTri2.Size = new System.Drawing.Size(70, 13);
+ this.lbNumTri2.TabIndex = 2;
+ this.lbNumTri2.Text = "-";
+ this.lbNumTri2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbNumVert
+ //
+ this.lbNumVert.ForeColor = System.Drawing.Color.White;
+ this.lbNumVert.Location = new System.Drawing.Point(95, 100);
+ this.lbNumVert.Name = "lbNumVert";
+ this.lbNumVert.Size = new System.Drawing.Size(70, 13);
+ this.lbNumVert.TabIndex = 4;
+ this.lbNumVert.Text = "-";
+ this.lbNumVert.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbNumVert2
+ //
+ this.lbNumVert2.ForeColor = System.Drawing.Color.Gray;
+ this.lbNumVert2.Location = new System.Drawing.Point(182, 100);
+ this.lbNumVert2.Name = "lbNumVert2";
+ this.lbNumVert2.Size = new System.Drawing.Size(70, 13);
+ this.lbNumVert2.TabIndex = 4;
+ this.lbNumVert2.Text = "-";
+ this.lbNumVert2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // flatTabControl1
+ //
+ this.flatTabControl1.Alignment = System.Windows.Forms.TabAlignment.Bottom;
+ this.flatTabControl1.Controls.Add(this.tabPage1);
+ this.flatTabControl1.Controls.Add(this.tabPage2);
+ this.flatTabControl1.Controls.Add(this.tabPage3);
+ this.flatTabControl1.Location = new System.Drawing.Point(0, 224);
+ this.flatTabControl1.Name = "flatTabControl1";
+ this.flatTabControl1.SelectedIndex = 0;
+ this.flatTabControl1.Size = new System.Drawing.Size(280, 387);
+ this.flatTabControl1.TabIndex = 1;
+ //
+ // tabPage1
+ //
+ this.tabPage1.BackColor = System.Drawing.Color.DimGray;
+ this.tabPage1.Controls.Add(this.lbMaxArea);
+ this.tabPage1.Controls.Add(this.label6);
+ this.tabPage1.Controls.Add(this.lbMinAngle);
+ this.tabPage1.Controls.Add(this.label9);
+ this.tabPage1.Controls.Add(this.label8);
+ this.tabPage1.Controls.Add(this.label5);
+ this.tabPage1.Controls.Add(this.slMaxArea);
+ this.tabPage1.Controls.Add(this.slMinAngle);
+ this.tabPage1.Controls.Add(this.cbConvex);
+ this.tabPage1.Controls.Add(this.cbQuality);
+ this.tabPage1.ForeColor = System.Drawing.Color.White;
+ this.tabPage1.Location = new System.Drawing.Point(4, 4);
+ this.tabPage1.Name = "tabPage1";
+ this.tabPage1.Size = new System.Drawing.Size(272, 358);
+ this.tabPage1.TabIndex = 0;
+ this.tabPage1.Text = "Mesh Control";
+ //
+ // lbMaxArea
+ //
+ this.lbMaxArea.AutoSize = true;
+ this.lbMaxArea.Location = new System.Drawing.Point(227, 61);
+ this.lbMaxArea.Name = "lbMaxArea";
+ this.lbMaxArea.Size = new System.Drawing.Size(13, 13);
+ this.lbMaxArea.TabIndex = 14;
+ this.lbMaxArea.Text = "0";
+ //
+ // label6
+ //
+ this.label6.AutoSize = true;
+ this.label6.Location = new System.Drawing.Point(8, 61);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(81, 13);
+ this.label6.TabIndex = 14;
+ this.label6.Text = "Maximum area";
+ //
+ // lbMinAngle
+ //
+ this.lbMinAngle.AutoSize = true;
+ this.lbMinAngle.Location = new System.Drawing.Point(227, 39);
+ this.lbMinAngle.Name = "lbMinAngle";
+ this.lbMinAngle.Size = new System.Drawing.Size(19, 13);
+ this.lbMinAngle.TabIndex = 14;
+ this.lbMinAngle.Text = "20";
+ //
+ // label9
+ //
+ this.label9.BackColor = System.Drawing.Color.DimGray;
+ this.label9.ForeColor = System.Drawing.Color.DarkGray;
+ this.label9.Location = new System.Drawing.Point(8, 166);
+ this.label9.Name = "label9";
+ this.label9.Size = new System.Drawing.Size(258, 33);
+ this.label9.TabIndex = 14;
+ this.label9.Text = "Use the convex mesh option, if the convex hull should be included in the output.";
+ //
+ // label8
+ //
+ this.label8.BackColor = System.Drawing.Color.DimGray;
+ this.label8.ForeColor = System.Drawing.Color.DarkGray;
+ this.label8.Location = new System.Drawing.Point(8, 85);
+ this.label8.Name = "label8";
+ this.label8.Size = new System.Drawing.Size(258, 33);
+ this.label8.TabIndex = 14;
+ this.label8.Text = "Hint: maximum area values of 0 or 1 will be irgnored (no area constraints are set" +
+ ").";
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(8, 39);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(87, 13);
+ this.label5.TabIndex = 14;
+ this.label5.Text = "Minimum angle";
+ //
+ // slMaxArea
+ //
+ this.slMaxArea.BackColor = System.Drawing.Color.Transparent;
+ this.slMaxArea.CriticalPercent = ((uint)(0u));
+ this.slMaxArea.Location = new System.Drawing.Point(102, 58);
+ this.slMaxArea.Maximum = 100;
+ this.slMaxArea.Minimum = 0;
+ this.slMaxArea.Name = "slMaxArea";
+ this.slMaxArea.Size = new System.Drawing.Size(119, 18);
+ this.slMaxArea.TabIndex = 13;
+ this.slMaxArea.Text = "darkSlider1";
+ this.slMaxArea.Value = 0;
+ this.slMaxArea.ValueChanging += new System.EventHandler(this.slMaxArea_ValueChanging);
+ //
+ // slMinAngle
+ //
+ this.slMinAngle.BackColor = System.Drawing.Color.Transparent;
+ this.slMinAngle.CriticalPercent = ((uint)(89u));
+ this.slMinAngle.Location = new System.Drawing.Point(102, 36);
+ this.slMinAngle.Maximum = 100;
+ this.slMinAngle.Minimum = 0;
+ this.slMinAngle.Name = "slMinAngle";
+ this.slMinAngle.Size = new System.Drawing.Size(119, 18);
+ this.slMinAngle.TabIndex = 13;
+ this.slMinAngle.Text = "darkSlider1";
+ this.slMinAngle.Value = 50;
+ this.slMinAngle.ValueChanging += new System.EventHandler(this.slMinAngle_ValueChanging);
//
// cbConvex
//
- this.cbConvex.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.cbConvex.BackColor = System.Drawing.Color.DimGray;
this.cbConvex.Checked = false;
- this.cbConvex.Location = new System.Drawing.Point(506, 12);
+ this.cbConvex.Location = new System.Drawing.Point(11, 146);
this.cbConvex.Name = "cbConvex";
- this.cbConvex.Size = new System.Drawing.Size(110, 23);
- this.cbConvex.TabIndex = 9;
- this.cbConvex.Text = "Convex polygon";
+ this.cbConvex.Size = new System.Drawing.Size(115, 17);
+ this.cbConvex.TabIndex = 0;
+ this.cbConvex.Text = "Convex mesh";
this.cbConvex.UseVisualStyleBackColor = false;
//
// cbQuality
//
- this.cbQuality.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.cbQuality.BackColor = System.Drawing.Color.DimGray;
this.cbQuality.Checked = false;
- this.cbQuality.Location = new System.Drawing.Point(622, 12);
+ this.cbQuality.Location = new System.Drawing.Point(11, 13);
this.cbQuality.Name = "cbQuality";
- this.cbQuality.Size = new System.Drawing.Size(138, 23);
- this.cbQuality.TabIndex = 9;
- this.cbQuality.Text = "Produce quality mesh";
+ this.cbQuality.Size = new System.Drawing.Size(115, 17);
+ this.cbQuality.TabIndex = 0;
+ this.cbQuality.Text = "Quality mesh";
this.cbQuality.UseVisualStyleBackColor = false;
//
- // btnRun
+ // tabPage2
//
- this.btnRun.Location = new System.Drawing.Point(766, 12);
- this.btnRun.Name = "btnRun";
- this.btnRun.Size = new System.Drawing.Size(75, 23);
- this.btnRun.TabIndex = 8;
- this.btnRun.Text = "Triangulate";
- this.btnRun.UseVisualStyleBackColor = true;
- this.btnRun.Click += new System.EventHandler(this.btnRun_Click);
+ this.tabPage2.BackColor = System.Drawing.Color.DimGray;
+ this.tabPage2.Controls.Add(this.label13);
+ this.tabPage2.Controls.Add(this.label12);
+ this.tabPage2.Controls.Add(this.label16);
+ this.tabPage2.Controls.Add(this.label15);
+ this.tabPage2.Controls.Add(this.label14);
+ this.tabPage2.Controls.Add(this.lbAngleMax);
+ this.tabPage2.Controls.Add(this.lbRatioMax);
+ this.tabPage2.Controls.Add(this.lbEdgeMax);
+ this.tabPage2.Controls.Add(this.lbAreaMax);
+ this.tabPage2.Controls.Add(this.lbAngleMin);
+ this.tabPage2.Controls.Add(this.lbRatioMin);
+ this.tabPage2.Controls.Add(this.lbEdgeMin);
+ this.tabPage2.Controls.Add(this.lbAreaMin);
+ this.tabPage2.Controls.Add(this.label10);
+ this.tabPage2.Controls.Add(this.label17);
+ this.tabPage2.Controls.Add(this.label11);
+ this.tabPage2.Controls.Add(this.angleHistogram1);
+ this.tabPage2.ForeColor = System.Drawing.Color.White;
+ this.tabPage2.Location = new System.Drawing.Point(4, 4);
+ this.tabPage2.Name = "tabPage2";
+ this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPage2.Size = new System.Drawing.Size(272, 358);
+ this.tabPage2.TabIndex = 1;
+ this.tabPage2.Text = "Statistic";
//
- // btnOpen
+ // label13
//
- this.btnOpen.Location = new System.Drawing.Point(12, 12);
- this.btnOpen.Name = "btnOpen";
- this.btnOpen.Size = new System.Drawing.Size(110, 23);
- this.btnOpen.TabIndex = 7;
- this.btnOpen.Text = "Open File";
- this.btnOpen.UseVisualStyleBackColor = true;
- this.btnOpen.Click += new System.EventHandler(this.btnOpen_Click);
+ this.label13.AutoSize = true;
+ this.label13.ForeColor = System.Drawing.Color.DarkGray;
+ this.label13.Location = new System.Drawing.Point(196, 12);
+ this.label13.Name = "label13";
+ this.label13.Size = new System.Drawing.Size(56, 13);
+ this.label13.TabIndex = 11;
+ this.label13.Text = "Maximum";
//
- // btnRandPts
+ // label12
//
- this.btnRandPts.Location = new System.Drawing.Point(128, 12);
- this.btnRandPts.Name = "btnRandPts";
- this.btnRandPts.Size = new System.Drawing.Size(110, 23);
- this.btnRandPts.TabIndex = 6;
- this.btnRandPts.Text = "Random Points";
- this.btnRandPts.UseVisualStyleBackColor = true;
- this.btnRandPts.Click += new System.EventHandler(this.btnRandPts_Click);
+ this.label12.AutoSize = true;
+ this.label12.ForeColor = System.Drawing.Color.DarkGray;
+ this.label12.Location = new System.Drawing.Point(106, 12);
+ this.label12.Name = "label12";
+ this.label12.Size = new System.Drawing.Size(55, 13);
+ this.label12.TabIndex = 12;
+ this.label12.Text = "Minimum";
+ //
+ // label16
+ //
+ this.label16.AutoSize = true;
+ this.label16.ForeColor = System.Drawing.Color.DarkGray;
+ this.label16.Location = new System.Drawing.Point(8, 107);
+ this.label16.Name = "label16";
+ this.label16.Size = new System.Drawing.Size(40, 13);
+ this.label16.TabIndex = 9;
+ this.label16.Text = "Angle:";
+ //
+ // label15
+ //
+ this.label15.AutoSize = true;
+ this.label15.ForeColor = System.Drawing.Color.DarkGray;
+ this.label15.Location = new System.Drawing.Point(8, 84);
+ this.label15.Name = "label15";
+ this.label15.Size = new System.Drawing.Size(71, 13);
+ this.label15.TabIndex = 10;
+ this.label15.Text = "Aspect ratio:";
+ //
+ // label14
+ //
+ this.label14.AutoSize = true;
+ this.label14.ForeColor = System.Drawing.Color.DarkGray;
+ this.label14.Location = new System.Drawing.Point(9, 61);
+ this.label14.Name = "label14";
+ this.label14.Size = new System.Drawing.Size(73, 13);
+ this.label14.TabIndex = 15;
+ this.label14.Text = "Edge length:";
+ //
+ // lbAngleMax
+ //
+ this.lbAngleMax.ForeColor = System.Drawing.Color.White;
+ this.lbAngleMax.Location = new System.Drawing.Point(176, 107);
+ this.lbAngleMax.Name = "lbAngleMax";
+ this.lbAngleMax.Size = new System.Drawing.Size(76, 13);
+ this.lbAngleMax.TabIndex = 16;
+ this.lbAngleMax.Text = "-";
+ this.lbAngleMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbRatioMax
+ //
+ this.lbRatioMax.ForeColor = System.Drawing.Color.White;
+ this.lbRatioMax.Location = new System.Drawing.Point(176, 84);
+ this.lbRatioMax.Name = "lbRatioMax";
+ this.lbRatioMax.Size = new System.Drawing.Size(76, 13);
+ this.lbRatioMax.TabIndex = 13;
+ this.lbRatioMax.Text = "-";
+ this.lbRatioMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbEdgeMax
+ //
+ this.lbEdgeMax.ForeColor = System.Drawing.Color.White;
+ this.lbEdgeMax.Location = new System.Drawing.Point(176, 61);
+ this.lbEdgeMax.Name = "lbEdgeMax";
+ this.lbEdgeMax.Size = new System.Drawing.Size(76, 13);
+ this.lbEdgeMax.TabIndex = 14;
+ this.lbEdgeMax.Text = "-";
+ this.lbEdgeMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbAreaMax
+ //
+ this.lbAreaMax.ForeColor = System.Drawing.Color.White;
+ this.lbAreaMax.Location = new System.Drawing.Point(176, 39);
+ this.lbAreaMax.Name = "lbAreaMax";
+ this.lbAreaMax.Size = new System.Drawing.Size(76, 13);
+ this.lbAreaMax.TabIndex = 3;
+ this.lbAreaMax.Text = "-";
+ this.lbAreaMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbAngleMin
+ //
+ this.lbAngleMin.ForeColor = System.Drawing.Color.White;
+ this.lbAngleMin.Location = new System.Drawing.Point(94, 107);
+ this.lbAngleMin.Name = "lbAngleMin";
+ this.lbAngleMin.Size = new System.Drawing.Size(68, 13);
+ this.lbAngleMin.TabIndex = 4;
+ this.lbAngleMin.Text = "-";
+ this.lbAngleMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbRatioMin
+ //
+ this.lbRatioMin.ForeColor = System.Drawing.Color.White;
+ this.lbRatioMin.Location = new System.Drawing.Point(94, 84);
+ this.lbRatioMin.Name = "lbRatioMin";
+ this.lbRatioMin.Size = new System.Drawing.Size(68, 13);
+ this.lbRatioMin.TabIndex = 1;
+ this.lbRatioMin.Text = "-";
+ this.lbRatioMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbEdgeMin
+ //
+ this.lbEdgeMin.ForeColor = System.Drawing.Color.White;
+ this.lbEdgeMin.Location = new System.Drawing.Point(94, 61);
+ this.lbEdgeMin.Name = "lbEdgeMin";
+ this.lbEdgeMin.Size = new System.Drawing.Size(68, 13);
+ this.lbEdgeMin.TabIndex = 2;
+ this.lbEdgeMin.Text = "-";
+ this.lbEdgeMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // lbAreaMin
+ //
+ this.lbAreaMin.ForeColor = System.Drawing.Color.White;
+ this.lbAreaMin.Location = new System.Drawing.Point(94, 39);
+ this.lbAreaMin.Name = "lbAreaMin";
+ this.lbAreaMin.Size = new System.Drawing.Size(68, 13);
+ this.lbAreaMin.TabIndex = 7;
+ this.lbAreaMin.Text = "-";
+ this.lbAreaMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ //
+ // label10
+ //
+ this.label10.AutoSize = true;
+ this.label10.ForeColor = System.Drawing.Color.DarkGray;
+ this.label10.Location = new System.Drawing.Point(9, 39);
+ this.label10.Name = "label10";
+ this.label10.Size = new System.Drawing.Size(76, 13);
+ this.label10.TabIndex = 8;
+ this.label10.Text = "Triangle area:";
+ //
+ // label17
+ //
+ this.label17.AutoSize = true;
+ this.label17.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label17.ForeColor = System.Drawing.Color.White;
+ this.label17.Location = new System.Drawing.Point(8, 139);
+ this.label17.Name = "label17";
+ this.label17.Size = new System.Drawing.Size(97, 13);
+ this.label17.TabIndex = 5;
+ this.label17.Text = "Angle histogram:";
+ //
+ // label11
+ //
+ this.label11.AutoSize = true;
+ this.label11.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label11.ForeColor = System.Drawing.Color.White;
+ this.label11.Location = new System.Drawing.Point(8, 12);
+ this.label11.Name = "label11";
+ this.label11.Size = new System.Drawing.Size(50, 13);
+ this.label11.TabIndex = 6;
+ this.label11.Text = "Statistic:";
+ //
+ // angleHistogram1
+ //
+ this.angleHistogram1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
+ this.angleHistogram1.Font = new System.Drawing.Font("Segoe UI", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.angleHistogram1.Location = new System.Drawing.Point(6, 157);
+ this.angleHistogram1.Name = "angleHistogram1";
+ this.angleHistogram1.Size = new System.Drawing.Size(260, 195);
+ this.angleHistogram1.TabIndex = 0;
+ this.angleHistogram1.Text = "angleHistogram1";
+ //
+ // tabPage3
+ //
+ this.tabPage3.BackColor = System.Drawing.Color.DimGray;
+ this.tabPage3.Controls.Add(this.label1);
+ this.tabPage3.Controls.Add(this.label7);
+ this.tabPage3.Controls.Add(this.lbShortcuts);
+ this.tabPage3.Location = new System.Drawing.Point(4, 4);
+ this.tabPage3.Name = "tabPage3";
+ this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPage3.Size = new System.Drawing.Size(272, 358);
+ this.tabPage3.TabIndex = 2;
+ this.tabPage3.Text = "Shortcuts";
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(8, 14);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(108, 13);
+ this.label1.TabIndex = 1;
+ this.label1.Text = "Keyboard shortcuts";
+ //
+ // label7
+ //
+ this.label7.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label7.ForeColor = System.Drawing.Color.White;
+ this.label7.Location = new System.Drawing.Point(55, 37);
+ this.label7.Name = "label7";
+ this.label7.Size = new System.Drawing.Size(134, 108);
+ this.label7.TabIndex = 0;
+ this.label7.Text = "File Open\r\nFile Save\r\nReload Input\r\n\r\nTriangulate / Refine\r\nSmooth\r\n\r\nShow Log";
+ //
+ // lbShortcuts
+ //
+ this.lbShortcuts.ForeColor = System.Drawing.Color.White;
+ this.lbShortcuts.Location = new System.Drawing.Point(13, 37);
+ this.lbShortcuts.Name = "lbShortcuts";
+ this.lbShortcuts.Size = new System.Drawing.Size(36, 108);
+ this.lbShortcuts.TabIndex = 0;
+ this.lbShortcuts.Text = "F3\r\nF4\r\nF5\r\n\r\nF8\r\nF9\r\n\r\nF12";
+ this.lbShortcuts.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ //
+ // menuStrip1
+ //
+ this.menuStrip1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.menuStrip1.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.menuStrip1.GripMargin = new System.Windows.Forms.Padding(0);
+ this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.fileMenu,
+ this.viewMenu,
+ this.toolsMenu});
+ this.menuStrip1.Location = new System.Drawing.Point(0, 0);
+ this.menuStrip1.Name = "menuStrip1";
+ this.menuStrip1.Padding = new System.Windows.Forms.Padding(0);
+ this.menuStrip1.Size = new System.Drawing.Size(280, 24);
+ this.menuStrip1.TabIndex = 0;
+ this.menuStrip1.Text = "menuStrip1";
+ //
+ // fileMenu
+ //
+ this.fileMenu.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.fileMenu.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+ this.fileMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.fileMenuOpen,
+ this.fileMenuSave,
+ this.toolStripSeparator2,
+ this.fileMenuQuit});
+ this.fileMenu.Name = "fileMenu";
+ this.fileMenu.Size = new System.Drawing.Size(37, 24);
+ this.fileMenu.Text = "File";
+ //
+ // fileMenuOpen
+ //
+ this.fileMenuOpen.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+ this.fileMenuOpen.Name = "fileMenuOpen";
+ this.fileMenuOpen.Size = new System.Drawing.Size(103, 22);
+ this.fileMenuOpen.Text = "Open";
+ this.fileMenuOpen.Click += new System.EventHandler(this.fileMenuOpen_Click);
+ //
+ // fileMenuSave
+ //
+ this.fileMenuSave.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+ this.fileMenuSave.Name = "fileMenuSave";
+ this.fileMenuSave.Size = new System.Drawing.Size(103, 22);
+ this.fileMenuSave.Text = "Save";
+ this.fileMenuSave.Click += new System.EventHandler(this.fileMenuSave_Click);
+ //
+ // toolStripSeparator2
+ //
+ this.toolStripSeparator2.Name = "toolStripSeparator2";
+ this.toolStripSeparator2.Size = new System.Drawing.Size(100, 6);
+ //
+ // fileMenuQuit
+ //
+ this.fileMenuQuit.Name = "fileMenuQuit";
+ this.fileMenuQuit.Size = new System.Drawing.Size(103, 22);
+ this.fileMenuQuit.Text = "Quit";
+ this.fileMenuQuit.Click += new System.EventHandler(this.fileMenuQuit_Click);
+ //
+ // viewMenu
+ //
+ this.viewMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.viewMenuMQuality,
+ this.toolStripSeparator1,
+ this.viewMenuLog});
+ this.viewMenu.Name = "viewMenu";
+ this.viewMenu.Size = new System.Drawing.Size(44, 24);
+ this.viewMenu.Text = "View";
+ //
+ // viewMenuMQuality
+ //
+ this.viewMenuMQuality.Enabled = false;
+ this.viewMenuMQuality.Name = "viewMenuMQuality";
+ this.viewMenuMQuality.Size = new System.Drawing.Size(154, 22);
+ this.viewMenuMQuality.Text = "Mesh Quality ...";
+ this.viewMenuMQuality.Click += new System.EventHandler(this.viewMenuMQuality_Click);
+ //
+ // toolStripSeparator1
+ //
+ this.toolStripSeparator1.Name = "toolStripSeparator1";
+ this.toolStripSeparator1.Size = new System.Drawing.Size(151, 6);
+ //
+ // viewMenuLog
+ //
+ this.viewMenuLog.Name = "viewMenuLog";
+ this.viewMenuLog.Size = new System.Drawing.Size(154, 22);
+ this.viewMenuLog.Text = "Show Log";
+ this.viewMenuLog.Click += new System.EventHandler(this.viewMenuLog_Click);
+ //
+ // toolsMenu
+ //
+ this.toolsMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.toolsMenuGen,
+ this.toolsMenuCheck});
+ this.toolsMenu.Name = "toolsMenu";
+ this.toolsMenu.Size = new System.Drawing.Size(46, 24);
+ this.toolsMenu.Text = "Tools";
+ //
+ // toolsMenuGen
+ //
+ this.toolsMenuGen.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.toolsMenuPoly1,
+ this.toolsMenuRandPts});
+ this.toolsMenuGen.Name = "toolsMenuGen";
+ this.toolsMenuGen.Size = new System.Drawing.Size(152, 22);
+ this.toolsMenuGen.Text = "Generator";
+ //
+ // toolsMenuPoly1
+ //
+ this.toolsMenuPoly1.Name = "toolsMenuPoly1";
+ this.toolsMenuPoly1.Size = new System.Drawing.Size(153, 22);
+ this.toolsMenuPoly1.Text = "Star 1";
+ this.toolsMenuPoly1.Click += new System.EventHandler(this.toolsMenuPoly1_Click);
+ //
+ // toolsMenuRandPts
+ //
+ this.toolsMenuRandPts.Name = "toolsMenuRandPts";
+ this.toolsMenuRandPts.Size = new System.Drawing.Size(153, 22);
+ this.toolsMenuRandPts.Text = "Random points";
+ this.toolsMenuRandPts.Click += new System.EventHandler(this.toolsMenuRandPts_Click);
+ //
+ // toolsMenuCheck
+ //
+ this.toolsMenuCheck.Name = "toolsMenuCheck";
+ this.toolsMenuCheck.Size = new System.Drawing.Size(152, 22);
+ this.toolsMenuCheck.Text = "Check Mesh";
+ this.toolsMenuCheck.Click += new System.EventHandler(this.toolsMenuCheck_Click);
//
// meshRenderer1
//
this.meshRenderer1.BackColor = System.Drawing.Color.Black;
- this.meshRenderer1.Dock = System.Windows.Forms.DockStyle.Bottom;
- this.meshRenderer1.Location = new System.Drawing.Point(0, 52);
+ this.meshRenderer1.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.meshRenderer1.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.meshRenderer1.Location = new System.Drawing.Point(0, 0);
this.meshRenderer1.Name = "meshRenderer1";
- this.meshRenderer1.Size = new System.Drawing.Size(934, 600);
- this.meshRenderer1.TabIndex = 5;
+ this.meshRenderer1.Size = new System.Drawing.Size(703, 612);
+ this.meshRenderer1.TabIndex = 0;
this.meshRenderer1.Text = "meshRenderer1";
//
- // lbTime
- //
- this.lbTime.AutoSize = true;
- this.lbTime.ForeColor = System.Drawing.SystemColors.HotTrack;
- this.lbTime.Location = new System.Drawing.Point(323, 17);
- this.lbTime.Name = "lbTime";
- this.lbTime.Size = new System.Drawing.Size(0, 13);
- this.lbTime.TabIndex = 2;
- //
- // Form1
+ // FormMain
//
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(934, 652);
- this.Controls.Add(this.btnStatistic);
- this.Controls.Add(this.tbNumPoints);
- this.Controls.Add(this.cbConvex);
- this.Controls.Add(this.cbQuality);
- this.Controls.Add(this.btnRun);
- this.Controls.Add(this.btnOpen);
- this.Controls.Add(this.btnRandPts);
- this.Controls.Add(this.meshRenderer1);
- this.Controls.Add(this.lbTime);
+ this.ClientSize = new System.Drawing.Size(984, 612);
+ 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.FixedSingle;
- this.MaximizeBox = false;
- this.Name = "Form1";
- this.Text = "Delaunay Triangulation";
+ this.KeyPreview = true;
+ this.MainMenuStrip = this.menuStrip1;
+ this.MinimumSize = new System.Drawing.Size(1000, 650);
+ this.Name = "FormMain";
+ this.Text = "Triangle.NET - Mesh Explorer";
this.Load += new System.EventHandler(this.Form1_Load);
+ this.ResizeBegin += new System.EventHandler(this.ResizeBeginHandler);
+ this.ResizeEnd += new System.EventHandler(this.ResizeEndHandler);
+ this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
+ this.Resize += new System.EventHandler(this.ResizeHandler);
+ this.splitContainer1.Panel1.ResumeLayout(false);
+ this.splitContainer1.Panel1.PerformLayout();
+ this.splitContainer1.Panel2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
+ this.splitContainer1.ResumeLayout(false);
+ this.flatTabControl1.ResumeLayout(false);
+ this.tabPage1.ResumeLayout(false);
+ this.tabPage1.PerformLayout();
+ this.tabPage2.ResumeLayout(false);
+ this.tabPage2.PerformLayout();
+ this.tabPage3.ResumeLayout(false);
+ this.tabPage3.PerformLayout();
+ this.menuStrip1.ResumeLayout(false);
+ this.menuStrip1.PerformLayout();
this.ResumeLayout(false);
- this.PerformLayout();
}
#endregion
- private MeshRenderer meshRenderer1;
- private Controls.DarkButton btnRandPts;
- private Controls.DarkButton btnOpen;
- private Controls.DarkButton btnRun;
+ private System.Windows.Forms.SplitContainer splitContainer1;
+ private Controls.MeshRenderer meshRenderer1;
+ private System.Windows.Forms.MenuStrip menuStrip1;
+ private System.Windows.Forms.ToolStripMenuItem fileMenu;
+ private System.Windows.Forms.ToolStripMenuItem fileMenuOpen;
+ private System.Windows.Forms.ToolStripMenuItem fileMenuSave;
+ private Controls.DarkTabControl flatTabControl1;
+ private System.Windows.Forms.TabPage tabPage1;
+ private System.Windows.Forms.TabPage tabPage2;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label lbNumSeg2;
+ private System.Windows.Forms.Label lbNumTri2;
+ private System.Windows.Forms.Label lbNumVert2;
+ private System.Windows.Forms.Label lbNumSeg;
+ private System.Windows.Forms.Label lbNumTri;
+ private System.Windows.Forms.Label lbNumVert;
+ private Controls.DarkButton btnSmooth;
+ private Controls.DarkButton btnMesh;
private Controls.DarkCheckBox cbQuality;
- private Controls.DarkTextBox tbNumPoints;
- private Controls.DarkButton btnStatistic;
+ private Controls.AngleHistogram angleHistogram1;
+ private Controls.DarkSlider slMinAngle;
+ private System.Windows.Forms.TabPage tabPage3;
+ private System.Windows.Forms.Label lbShortcuts;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label7;
private Controls.DarkCheckBox cbConvex;
- private System.Windows.Forms.Label lbTime;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label5;
+ private Controls.DarkSlider slMaxArea;
+ private System.Windows.Forms.Label lbMaxArea;
+ private System.Windows.Forms.Label lbMinAngle;
+ private System.Windows.Forms.Label label9;
+ private System.Windows.Forms.Label label8;
+ private System.Windows.Forms.Label label13;
+ private System.Windows.Forms.Label label12;
+ private System.Windows.Forms.Label label16;
+ private System.Windows.Forms.Label label15;
+ private System.Windows.Forms.Label label14;
+ private System.Windows.Forms.Label lbAngleMax;
+ private System.Windows.Forms.Label lbRatioMax;
+ private System.Windows.Forms.Label lbEdgeMax;
+ private System.Windows.Forms.Label lbAreaMax;
+ private System.Windows.Forms.Label lbAngleMin;
+ private System.Windows.Forms.Label lbRatioMin;
+ private System.Windows.Forms.Label lbEdgeMin;
+ private System.Windows.Forms.Label lbAreaMin;
+ private System.Windows.Forms.Label label10;
+ private System.Windows.Forms.Label label17;
+ private System.Windows.Forms.Label label11;
+ private System.Windows.Forms.ToolStripMenuItem viewMenu;
+ private System.Windows.Forms.ToolStripMenuItem viewMenuMQuality;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+ private System.Windows.Forms.ToolStripMenuItem viewMenuLog;
+ private System.Windows.Forms.ToolStripMenuItem toolsMenu;
+ private System.Windows.Forms.ToolStripMenuItem toolsMenuGen;
+ private System.Windows.Forms.ToolStripMenuItem toolsMenuPoly1;
+ private System.Windows.Forms.ToolStripMenuItem toolsMenuRandPts;
+ private System.Windows.Forms.ToolStripMenuItem toolsMenuCheck;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
+ private System.Windows.Forms.ToolStripMenuItem fileMenuQuit;
}
}
diff --git a/Triangle.NET/TestApp/FormMain.cs b/Triangle.NET/TestApp/FormMain.cs
index 0911c7f..a56edf8 100644
--- a/Triangle.NET/TestApp/FormMain.cs
+++ b/Triangle.NET/TestApp/FormMain.cs
@@ -1,115 +1,126 @@
using System;
-using System.Drawing;
using System.Diagnostics;
-using System.Windows.Forms;
+using System.Drawing;
using System.IO;
-using System.Globalization;
+using System.Linq;
+using System.Windows.Forms;
using System.Collections.Generic;
+using MeshExplorer.Controls;
+using MeshExplorer.IO;
using TriangleNet;
+using TriangleNet.Geometry;
using TriangleNet.IO;
-using TestApp.Rendering;
+using TriangleNet.Tools;
-namespace TestApp
+namespace MeshExplorer
{
public partial class FormMain : Form
{
- Random rand = new Random(DateTime.Now.Millisecond);
-
- // Triangulation IO
- MeshData input;
+ Settings settings;
+ InputGeometry input;
Mesh mesh;
+ Statistic stats;
- // Filter index of the "Open file" dialog
- int dlgFilterIndex = 1;
-
- // Startup directory of the "Open file" dialog
- string dlgDirectory = Application.StartupPath;
-
- Statistic statistic = new Statistic();
- FormQuality formStats;
+ FormLog frmLog;
+ FormQuality frmQuality;
public FormMain()
{
InitializeComponent();
+
+ ToolStripManager.Renderer = new DarkToolStripRenderer();
}
- private double[][] CreateRandomPoints(int numPoints)
+ private void Form1_Load(object sender, EventArgs e)
{
- bool save = false;
+ oldClientSize = this.ClientSize;
- double[][] points = new double[numPoints][];
+ settings = new Settings();
- int width = meshRenderer1.Width;
- int height = meshRenderer1.Height;
- if (save)
+ meshRenderer1.Initialize();
+
+ stats = new Statistic();
+
+ //BatchTest();
+ }
+
+ void BatchTest()
+ {
+ try
{
- using (TextWriter fs = new StreamWriter(numPoints + ".txt"))
+ Mesh m = new Mesh();
+ m.SetOption(Options.MinAngle, 20);
+
+
+ for (int j = 0; j < 10; j++)
{
- fs.WriteLine("{0} 2 0 0", numPoints);
-
- for (int i = 0; i < numPoints; i++)
+ for (int i = 20; i > 0; i--)
{
- points[i] = new double[] {
- rand.NextDouble() * width,
- rand.NextDouble() * height };
+ var geom = PolygonGenerator.CreateRandomPoints(10 * i, 100, 100);
- fs.WriteLine(String.Format(CultureInfo.InvariantCulture.NumberFormat,
- "{0} {1:0.0} {2:0.0}", (i + 1), points[i][0], points[i][1]));
+ m.Triangulate(geom);
}
}
}
- else
+ catch (Exception e)
{
- for (int i = 0; i < numPoints; i++)
- {
- points[i] = new double[] {
- rand.NextDouble() * width,
- rand.NextDouble() * height };
- }
+ MessageBox.Show("BLUB\n" + e.Message);
}
-
- return points;
}
- private void Run()
+ private void Form1_KeyUp(object sender, KeyEventArgs e)
{
- if (input == null)
+ switch (e.KeyCode)
{
- return;
+ case Keys.F3:
+ Open();
+ break;
+ case Keys.F4:
+ Save();
+ break;
+ case Keys.F5:
+ Reload();
+ break;
+ case Keys.F8:
+ TriangulateOrRefine();
+ break;
+ case Keys.F9:
+ Smooth();
+ break;
+ case Keys.F12:
+ ShowLog();
+ break;
}
+ }
- Stopwatch sw = new Stopwatch();
+ private void btnMesh_Click(object sender, EventArgs e)
+ {
+ TriangulateOrRefine();
+ }
- mesh = new Mesh();
- mesh.SetOption(Options.Quality, cbQuality.Checked);
- mesh.SetOption(Options.Convex, cbConvex.Checked);
+ private void btnSmooth_Click(object sender, EventArgs e)
+ {
+ //Smooth();
+ }
- try
- {
- sw.Start();
- mesh.Triangulate(input);
- sw.Stop();
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- return;
- }
+ private void slMinAngle_ValueChanging(object sender, EventArgs e)
+ {
+ // Between 0 and 40 (step 1)
+ int angle = (slMinAngle.Value * 40) / 100;
+ lbMinAngle.Text = angle.ToString();
+ }
- meshRenderer1.SetData(mesh, false);
-
- statistic.Update(mesh, 10);
-
- if (formStats != null && !formStats.IsDisposed)
- {
- formStats.UpdateSatistic(statistic, sw.ElapsedMilliseconds, meshRenderer1.RenderTime);
- }
+ private void slMaxArea_ValueChanging(object sender, EventArgs e)
+ {
+ // Between 0 and 1 (step 0.01)
+ double area = slMaxArea.Value * 0.01;
+ lbMaxArea.Text = area.ToString(Util.Nfi);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
- Point pt = e.Location;
- pt.Offset(0, -meshRenderer1.Top);
+ System.Drawing.Point pt = e.Location;
+ pt.Offset(-splitContainer1.SplitterDistance, 0);
if (meshRenderer1.ClientRectangle.Contains(pt))
{
@@ -118,174 +129,397 @@ namespace TestApp
base.OnMouseWheel(e);
}
- private void Form1_Load(object sender, EventArgs e)
- {
- if (Directory.Exists(@"..\..\..\Data\"))
- {
- dlgDirectory = Path.GetFullPath(@"..\..\..\Data\");
+ #region Resize event handler
- //Examples.Example1();
- //Examples.Example2();
- //Examples.Example3();
- }
- else if (Directory.Exists(@"Data\"))
+ bool isResizing = false;
+ Size oldClientSize;
+
+ private void ResizeHandler(object sender, EventArgs e)
+ {
+ // Handle window minimize and maximize
+ if (!isResizing)
{
- dlgDirectory = Path.GetFullPath(@"Data\");
+ meshRenderer1.HandleResize();
}
}
- private void btnRandPts_Click(object sender, EventArgs e)
+ private void ResizeEndHandler(object sender, EventArgs e)
{
- btnRun.Text = "Triangulate";
+ isResizing = false;
- int n = 10;
- int.TryParse(tbNumPoints.Text, out n);
-
- input = new MeshData();
-
- input.Points = CreateRandomPoints(n);
-
- meshRenderer1.SetData(input, true);
+ if (this.ClientSize != this.oldClientSize)
+ {
+ this.oldClientSize = this.ClientSize;
+ meshRenderer1.HandleResize();
+ }
}
- private void btnOpen_Click(object sender, EventArgs e)
+ private void ResizeBeginHandler(object sender, EventArgs e)
{
- OpenFileDialog dlg = new OpenFileDialog();
- dlg.InitialDirectory = dlgDirectory;
- dlg.Filter = "Triangle polygon (*.node;*.poly)|*.node;*.poly|Polygon data (*.dat)|*.dat";
- dlg.FilterIndex = dlgFilterIndex;
+ isResizing = true;
+ }
- if (dlg.ShowDialog() == DialogResult.OK)
+ #endregion
+
+ #region State changes
+
+ private void HandleNewInput()
+ {
+ // Reset mesh
+ mesh = null;
+
+ // Reset state
+ settings.RefineMode = false;
+ settings.ExceptionThrown = false;
+
+ // Reset labels
+ lbNumVert2.Text = "-";
+ lbNumTri2.Text = "-";
+ lbNumSeg2.Text = "-";
+
+ lbNumVert.Text = input.Count.ToString();
+ lbNumSeg.Text = input.Segments.Count().ToString();
+ lbNumTri.Text = "0"; //input.Triangles == null ? "0" : input.Triangles.Length.ToString();
+
+ // Reset buttons
+ btnMesh.Enabled = true;
+ btnMesh.Text = "Triangulate";
+ btnSmooth.Enabled = false;
+
+ // Render input
+ meshRenderer1.SetData(input);
+
+ // Update window caption
+ this.Text = "Triangle.NET - Mesh Explorer - " + settings.CurrentFile;
+
+ // Disable menu items
+ viewMenuMQuality.Enabled = false;
+ }
+
+ private void HandleMeshChange()
+ {
+ // Render mesh
+ meshRenderer1.SetData(mesh);
+
+ // Previous mesh stats
+ lbNumVert2.Text = lbNumVert.Text;
+ lbNumTri2.Text = lbNumTri.Text;
+ lbNumSeg2.Text = lbNumSeg.Text;
+
+ // New mesh stats
+ lbNumVert.Text = stats.Vertices.ToString();
+ lbNumSeg.Text = stats.ConstrainedEdges.ToString();
+ lbNumTri.Text = stats.Triangles.ToString();
+
+ // Update statistics tab
+ angleHistogram1.SetData(stats.MinAngleHistogram, stats.MaxAngleHistogram);
+
+ lbAreaMin.Text = Util.DoubleToString(stats.SmallestArea);
+ lbAreaMax.Text = Util.DoubleToString(stats.LargestArea);
+ lbEdgeMin.Text = Util.DoubleToString(stats.ShortestEdge);
+ lbEdgeMax.Text = Util.DoubleToString(stats.LongestEdge);
+ lbRatioMin.Text = Util.DoubleToString(stats.ShortestAltitude);
+ lbRatioMax.Text = Util.DoubleToString(stats.LargestAspectRatio);
+ lbAngleMin.Text = Util.AngleToString(stats.SmallestAngle);
+ lbAngleMax.Text = Util.AngleToString(stats.LargestAngle);
+
+ // Enable menu items
+ viewMenuMQuality.Enabled = true;
+ }
+
+ #endregion
+
+ #region Commands
+
+ private void Open()
+ {
+ OpenFileDialog ofd = new OpenFileDialog();
+
+ ofd.Filter = settings.OfdFilter;
+ ofd.FilterIndex = settings.OfdFilterIndex;
+ ofd.InitialDirectory = settings.OfdDirectory;
+ ofd.FileName = "";
+
+ if (ofd.ShowDialog() == DialogResult.OK)
{
- dlgDirectory = Path.GetDirectoryName(dlg.FileName);
+ input = FileProcessor.Open(ofd.FileName);
- string file = dlg.FileName;
- string ext = Path.GetExtension(file);
-
- if (ext == ".dat")
+ if (input != null)
{
- dlgFilterIndex = 2;
- input = new MeshData();
- input.Points = ParseDatFile(file);
+ // Update settings
+ settings.CurrentFile = Path.GetFileName(ofd.FileName);
- int n = input.Points.Length;
- int[][] segments = new int[n][];
-
- for (int i = 0; i < n; i++)
- {
- segments[i] = new int[] { i, (i + 1) % n };
-
- }
- input.Segments = segments;
- }
- else
- {
- dlgFilterIndex = 1;
- try
- {
- input = FileReader.ReadFile(file);
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- input = null;
- return;
- }
+ HandleNewInput();
}
+ // else Message
- meshRenderer1.SetData(input, true);
-
- btnRun.Text = "Triangulate";
+ // Update folder settings
+ settings.OfdFilterIndex = ofd.FilterIndex;
+ settings.OfdDirectory = Path.GetFullPath(ofd.FileName);
}
}
- private void btnRun_Click(object sender, EventArgs e)
+ private void Save()
{
+ SaveFileDialog sfd = new SaveFileDialog();
+
+ sfd.Filter = settings.SfdFilter;
+ sfd.FilterIndex = settings.SfdFilterIndex;
+ sfd.InitialDirectory = settings.SfdDirectory;
+ sfd.FileName = "";
+
+ if (sfd.ShowDialog() == DialogResult.OK)
+ {
+ FileProcessor.Save(sfd.FileName, mesh);
+ }
+ }
+
+ private void Reload()
+ {
+ if (input != null)
+ {
+ mesh = null;
+ settings.RefineMode = false;
+ settings.ExceptionThrown = false;
+
+ HandleNewInput();
+ }
+ }
+
+ private void TriangulateOrRefine()
+ {
+ if (input == null || settings.ExceptionThrown) return;
+
+ if (settings.RefineMode == false)
+ {
+ Triangulate();
+
+ if (cbQuality.Checked)
+ {
+ btnMesh.Text = "Refine";
+ //btnSmooth.Enabled = true;
+ }
+ }
+ else
+ {
+ Refine();
+ }
+ }
+
+ private void Triangulate()
+ {
+ if (input == null) return;
+
+ //Stopwatch sw = new Stopwatch();
+
+ mesh = new Mesh();
+
if (cbQuality.Checked)
{
- if (btnRun.Text == "Triangulate")
+ mesh.SetOption(Options.Quality, true);
+
+ int angle = (slMinAngle.Value * 40) / 100;
+ mesh.SetOption(Options.MinAngle, angle);
+
+ double area = slMaxArea.Value * 0.01;
+
+ if (area > 0 && area < 1)
{
- btnRun.Text = "Refine";
+ var size = input.Bounds;
- Run();
- }
- else
- {
- Stopwatch sw = new Stopwatch();
+ double min = Math.Min(size.Width, size.Height);
- try
- {
- sw.Start();
- mesh.Refine(statistic.LargestArea / 2);
- sw.Stop();
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- return;
- }
-
- meshRenderer1.SetData(mesh, false);
-
- statistic.Update(mesh, 10);
-
- if (formStats != null && !formStats.IsDisposed)
- {
- formStats.UpdateSatistic(statistic, sw.ElapsedMilliseconds, meshRenderer1.RenderTime);
- }
+ mesh.SetOption(Options.MaxArea, area * min);
}
}
- else
+
+ if (cbConvex.Checked)
{
- btnRun.Text = "Triangulate";
- Run();
+ mesh.SetOption(Options.Convex, true);
}
+
+ try
+ {
+ //sw.Start();
+ mesh.Triangulate(input);
+ //sw.Stop();
+
+ stats.Update(mesh, 10);
+
+ HandleMeshChange();
+
+ if (cbQuality.Checked)
+ {
+ settings.RefineMode = true;
+ }
+ }
+ catch (Exception ex)
+ {
+ settings.ExceptionThrown = true;
+ DarkMessageBox.Show("Exception - Triangulate", ex.Message);
+ }
+
+ UpdateLog();
}
- private void btnStatistic_Click(object sender, EventArgs e)
+ private void Refine()
{
- if (formStats == null)
+ if (mesh == null) return;
+
+ Stopwatch sw = new Stopwatch();
+
+ double area = slMaxArea.Value * 0.01;
+
+ if (area > 0 && area < 1)
{
- formStats = new FormQuality();
+ mesh.SetOption(Options.MaxArea, area * stats.LargestArea);
}
- if (!formStats.Visible)
+ int angle = (slMinAngle.Value * 40) / 100;
+ mesh.SetOption(Options.MinAngle, angle);
+
+ try
{
- formStats.UpdateSatistic(this.statistic, -1, -1);
- formStats.Show(this);
+ sw.Start();
+ mesh.Refine();
+ sw.Stop();
+
+ stats.Update(mesh, 10);
+
+ HandleMeshChange();
}
- else
+ catch (Exception ex)
{
- formStats.Hide();
+ settings.ExceptionThrown = true;
+ DarkMessageBox.Show("Exception - Refine", ex.Message);
}
+
+ UpdateLog();
}
- public static double[][] ParseDatFile(string filename)
+ private void Smooth()
{
- NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
+ if (mesh == null || settings.ExceptionThrown) return;
- List points = new List();
+ Stopwatch sw = new Stopwatch();
- string line;
- string[] split;
-
- using (TextReader reader = new StreamReader(filename))
+ try
{
- while ((line = reader.ReadLine()) != null)
- {
- split = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+ sw.Start();
+ mesh.Smooth();
+ sw.Stop();
- if (split.Length == 2)
- {
- points.Add(new double[] {
- double.Parse(split[0], nfi),
- double.Parse(split[1], nfi)
- });
- }
- }
+ stats.Update(mesh, 10);
+
+ HandleMeshChange();
+ }
+ catch (Exception ex)
+ {
+ settings.ExceptionThrown = true;
+ DarkMessageBox.Show("Exception - Smooth", ex.Message);
}
- return points.ToArray();
+ UpdateLog();
}
+
+ private void ShowLog()
+ {
+ if (frmLog == null)
+ {
+ frmLog = new FormLog();
+ }
+
+ UpdateLog();
+
+ if (!frmLog.Visible)
+ {
+ frmLog.Show(this);
+ }
+ }
+
+ private void UpdateLog()
+ {
+ if (frmLog != null)
+ {
+ frmLog.UpdateItems();
+ }
+ }
+
+ private void ShowQuality()
+ {
+ if (frmQuality == null)
+ {
+ frmQuality = new FormQuality();
+ }
+
+ //UpdateLog();
+
+ if (!frmQuality.Visible)
+ {
+ frmQuality.Show(this);
+ }
+ }
+
+ #endregion
+
+ #region Menu Handler
+
+ private void fileMenuOpen_Click(object sender, EventArgs e)
+ {
+ Open();
+ }
+
+ private void fileMenuSave_Click(object sender, EventArgs ev)
+ {
+ if (mesh != null)
+ {
+ Save();
+ }
+ }
+
+ private void viewMenuLog_Click(object sender, EventArgs e)
+ {
+ ShowLog();
+ }
+
+ private void toolsMenuPoly1_Click(object sender, EventArgs e)
+ {
+ input = PolygonGenerator.StarInBox(20);
+ settings.CurrentFile = "star *";
+ HandleNewInput();
+ }
+
+ private void toolsMenuRandPts_Click(object sender, EventArgs e)
+ {
+ input = PolygonGenerator.CreateRandomPoints(10, 120, 100);
+ settings.CurrentFile = "points *";
+ HandleNewInput();
+ }
+
+ private void toolsMenuCheck_Click(object sender, EventArgs e)
+ {
+ if (mesh != null)
+ {
+ mesh.Check();
+ ShowLog();
+ }
+ }
+
+ private void viewMenuMQuality_Click(object sender, EventArgs e)
+ {
+ if (mesh != null)
+ {
+ ShowQuality();
+ }
+
+ frmQuality.UpdateQuality(meshRenderer1.Data);
+ }
+
+ private void fileMenuQuit_Click(object sender, EventArgs e)
+ {
+ this.Close();
+ }
+
+ #endregion
}
}
diff --git a/Triangle.NET/TestApp/FormMain.resx b/Triangle.NET/TestApp/FormMain.resx
index 29dcb1b..0f6d8eb 100644
--- a/Triangle.NET/TestApp/FormMain.resx
+++ b/Triangle.NET/TestApp/FormMain.resx
@@ -117,4 +117,7 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 17, 17
+
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/FormQuality.Designer.cs b/Triangle.NET/TestApp/FormQuality.Designer.cs
index 38c7a6b..ec5ce91 100644
--- a/Triangle.NET/TestApp/FormQuality.Designer.cs
+++ b/Triangle.NET/TestApp/FormQuality.Designer.cs
@@ -1,4 +1,4 @@
-namespace TestApp
+namespace MeshExplorer
{
partial class FormQuality
{
@@ -29,422 +29,33 @@
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
- this.label2 = new System.Windows.Forms.Label();
- this.label3 = new System.Windows.Forms.Label();
- this.label4 = new System.Windows.Forms.Label();
- this.label5 = new System.Windows.Forms.Label();
- this.label6 = new System.Windows.Forms.Label();
- this.label7 = new System.Windows.Forms.Label();
- this.label8 = new System.Windows.Forms.Label();
- this.label9 = new System.Windows.Forms.Label();
- this.label10 = new System.Windows.Forms.Label();
- this.label11 = new System.Windows.Forms.Label();
- this.label12 = new System.Windows.Forms.Label();
- this.label13 = new System.Windows.Forms.Label();
- this.label14 = new System.Windows.Forms.Label();
- this.label15 = new System.Windows.Forms.Label();
- this.label16 = new System.Windows.Forms.Label();
- this.label17 = new System.Windows.Forms.Label();
- this.lbNumInput = new System.Windows.Forms.Label();
- this.lbNumOutput = new System.Windows.Forms.Label();
- this.lbNumTri = new System.Windows.Forms.Label();
- this.lbNumEdge = new System.Windows.Forms.Label();
- this.lbNumBoundary = new System.Windows.Forms.Label();
- this.lbCalcTime = new System.Windows.Forms.Label();
- this.lbRenderTime = new System.Windows.Forms.Label();
- this.lbAreaMin = new System.Windows.Forms.Label();
- this.lbAreaMax = new System.Windows.Forms.Label();
- this.lbEdgeMin = new System.Windows.Forms.Label();
- this.lbEdgeMax = new System.Windows.Forms.Label();
- this.lbRatioMin = new System.Windows.Forms.Label();
- this.lbRatioMax = new System.Windows.Forms.Label();
- this.lbAngleMin = new System.Windows.Forms.Label();
- this.lbAngleMax = new System.Windows.Forms.Label();
- this.histogram1 = new TestApp.Controls.AngleHistogram();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
- this.label1.ForeColor = System.Drawing.Color.Gray;
- this.label1.Location = new System.Drawing.Point(11, 36);
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
- this.label1.Size = new System.Drawing.Size(79, 13);
+ this.label1.Size = new System.Drawing.Size(38, 13);
this.label1.TabIndex = 0;
- this.label1.Text = "Input vertices:";
+ this.label1.Text = "-";
//
- // label2
- //
- this.label2.AutoSize = true;
- this.label2.ForeColor = System.Drawing.Color.Gray;
- this.label2.Location = new System.Drawing.Point(11, 59);
- this.label2.Name = "label2";
- this.label2.Size = new System.Drawing.Size(79, 13);
- this.label2.TabIndex = 0;
- this.label2.Text = "Mesh vertices:";
- //
- // label3
- //
- this.label3.AutoSize = true;
- this.label3.ForeColor = System.Drawing.Color.Gray;
- this.label3.Location = new System.Drawing.Point(11, 81);
- this.label3.Name = "label3";
- this.label3.Size = new System.Drawing.Size(86, 13);
- this.label3.TabIndex = 0;
- this.label3.Text = "Mesh triangles:";
- //
- // label4
- //
- this.label4.AutoSize = true;
- this.label4.ForeColor = System.Drawing.Color.Gray;
- this.label4.Location = new System.Drawing.Point(11, 103);
- this.label4.Name = "label4";
- this.label4.Size = new System.Drawing.Size(72, 13);
- this.label4.TabIndex = 0;
- this.label4.Text = "Mesh edges:";
- //
- // label5
- //
- this.label5.AutoSize = true;
- this.label5.ForeColor = System.Drawing.Color.Gray;
- this.label5.Location = new System.Drawing.Point(11, 125);
- this.label5.Name = "label5";
- this.label5.Size = new System.Drawing.Size(136, 13);
- this.label5.TabIndex = 0;
- this.label5.Text = "Exterior boundary edges:";
- //
- // label6
- //
- this.label6.AutoSize = true;
- this.label6.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label6.ForeColor = System.Drawing.Color.White;
- this.label6.Location = new System.Drawing.Point(12, 9);
- this.label6.Name = "label6";
- this.label6.Size = new System.Drawing.Size(39, 13);
- this.label6.TabIndex = 0;
- this.label6.Text = "Mesh:";
- //
- // label7
- //
- this.label7.AutoSize = true;
- this.label7.ForeColor = System.Drawing.Color.Gray;
- this.label7.Location = new System.Drawing.Point(12, 191);
- this.label7.Name = "label7";
- this.label7.Size = new System.Drawing.Size(79, 13);
- this.label7.TabIndex = 0;
- this.label7.Text = "Triangulation:";
- //
- // label8
- //
- this.label8.AutoSize = true;
- this.label8.ForeColor = System.Drawing.Color.Gray;
- this.label8.Location = new System.Drawing.Point(12, 212);
- this.label8.Name = "label8";
- this.label8.Size = new System.Drawing.Size(64, 13);
- this.label8.TabIndex = 0;
- this.label8.Text = "Rendering:";
- //
- // label9
- //
- this.label9.AutoSize = true;
- this.label9.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label9.ForeColor = System.Drawing.Color.White;
- this.label9.Location = new System.Drawing.Point(11, 266);
- this.label9.Name = "label9";
- this.label9.Size = new System.Drawing.Size(47, 13);
- this.label9.TabIndex = 0;
- this.label9.Text = "Quality:";
- //
- // label10
- //
- this.label10.AutoSize = true;
- this.label10.ForeColor = System.Drawing.Color.Gray;
- this.label10.Location = new System.Drawing.Point(12, 296);
- this.label10.Name = "label10";
- this.label10.Size = new System.Drawing.Size(76, 13);
- this.label10.TabIndex = 0;
- this.label10.Text = "Triangle area:";
- //
- // label11
- //
- this.label11.AutoSize = true;
- this.label11.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label11.ForeColor = System.Drawing.Color.White;
- this.label11.Location = new System.Drawing.Point(12, 163);
- this.label11.Name = "label11";
- this.label11.Size = new System.Drawing.Size(65, 13);
- this.label11.TabIndex = 0;
- this.label11.Text = "Stopwatch:";
- //
- // label12
- //
- this.label12.AutoSize = true;
- this.label12.ForeColor = System.Drawing.Color.Gray;
- this.label12.Location = new System.Drawing.Point(109, 266);
- this.label12.Name = "label12";
- this.label12.Size = new System.Drawing.Size(55, 13);
- this.label12.TabIndex = 0;
- this.label12.Text = "Minimum";
- //
- // label13
- //
- this.label13.AutoSize = true;
- this.label13.ForeColor = System.Drawing.Color.Gray;
- this.label13.Location = new System.Drawing.Point(199, 266);
- this.label13.Name = "label13";
- this.label13.Size = new System.Drawing.Size(56, 13);
- this.label13.TabIndex = 0;
- this.label13.Text = "Maximum";
- //
- // label14
- //
- this.label14.AutoSize = true;
- this.label14.ForeColor = System.Drawing.Color.Gray;
- this.label14.Location = new System.Drawing.Point(12, 320);
- this.label14.Name = "label14";
- this.label14.Size = new System.Drawing.Size(73, 13);
- this.label14.TabIndex = 0;
- this.label14.Text = "Edge length:";
- //
- // label15
- //
- this.label15.AutoSize = true;
- this.label15.ForeColor = System.Drawing.Color.Gray;
- this.label15.Location = new System.Drawing.Point(11, 343);
- this.label15.Name = "label15";
- this.label15.Size = new System.Drawing.Size(71, 13);
- this.label15.TabIndex = 0;
- this.label15.Text = "Aspect ratio:";
- //
- // label16
- //
- this.label16.AutoSize = true;
- this.label16.ForeColor = System.Drawing.Color.Gray;
- this.label16.Location = new System.Drawing.Point(11, 366);
- this.label16.Name = "label16";
- this.label16.Size = new System.Drawing.Size(40, 13);
- this.label16.TabIndex = 0;
- this.label16.Text = "Angle:";
- //
- // label17
- //
- this.label17.AutoSize = true;
- this.label17.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
- this.label17.ForeColor = System.Drawing.Color.White;
- this.label17.Location = new System.Drawing.Point(11, 412);
- this.label17.Name = "label17";
- this.label17.Size = new System.Drawing.Size(97, 13);
- this.label17.TabIndex = 0;
- this.label17.Text = "Angle histogram:";
- //
- // lbNumInput
- //
- this.lbNumInput.AutoSize = true;
- this.lbNumInput.ForeColor = System.Drawing.Color.White;
- this.lbNumInput.Location = new System.Drawing.Point(171, 36);
- this.lbNumInput.Name = "lbNumInput";
- this.lbNumInput.Size = new System.Drawing.Size(11, 13);
- this.lbNumInput.TabIndex = 0;
- this.lbNumInput.Text = "-";
- //
- // lbNumOutput
- //
- this.lbNumOutput.AutoSize = true;
- this.lbNumOutput.ForeColor = System.Drawing.Color.White;
- this.lbNumOutput.Location = new System.Drawing.Point(171, 59);
- this.lbNumOutput.Name = "lbNumOutput";
- this.lbNumOutput.Size = new System.Drawing.Size(11, 13);
- this.lbNumOutput.TabIndex = 0;
- this.lbNumOutput.Text = "-";
- //
- // lbNumTri
- //
- this.lbNumTri.AutoSize = true;
- this.lbNumTri.ForeColor = System.Drawing.Color.White;
- this.lbNumTri.Location = new System.Drawing.Point(171, 81);
- this.lbNumTri.Name = "lbNumTri";
- this.lbNumTri.Size = new System.Drawing.Size(11, 13);
- this.lbNumTri.TabIndex = 0;
- this.lbNumTri.Text = "-";
- //
- // lbNumEdge
- //
- this.lbNumEdge.AutoSize = true;
- this.lbNumEdge.ForeColor = System.Drawing.Color.White;
- this.lbNumEdge.Location = new System.Drawing.Point(171, 103);
- this.lbNumEdge.Name = "lbNumEdge";
- this.lbNumEdge.Size = new System.Drawing.Size(11, 13);
- this.lbNumEdge.TabIndex = 0;
- this.lbNumEdge.Text = "-";
- //
- // lbNumBoundary
- //
- this.lbNumBoundary.AutoSize = true;
- this.lbNumBoundary.ForeColor = System.Drawing.Color.White;
- this.lbNumBoundary.Location = new System.Drawing.Point(171, 125);
- this.lbNumBoundary.Name = "lbNumBoundary";
- this.lbNumBoundary.Size = new System.Drawing.Size(11, 13);
- this.lbNumBoundary.TabIndex = 0;
- this.lbNumBoundary.Text = "-";
- //
- // lbCalcTime
- //
- this.lbCalcTime.AutoSize = true;
- this.lbCalcTime.ForeColor = System.Drawing.Color.White;
- this.lbCalcTime.Location = new System.Drawing.Point(171, 191);
- this.lbCalcTime.Name = "lbCalcTime";
- this.lbCalcTime.Size = new System.Drawing.Size(11, 13);
- this.lbCalcTime.TabIndex = 0;
- this.lbCalcTime.Text = "-";
- //
- // lbRenderTime
- //
- this.lbRenderTime.AutoSize = true;
- this.lbRenderTime.ForeColor = System.Drawing.Color.White;
- this.lbRenderTime.Location = new System.Drawing.Point(171, 212);
- this.lbRenderTime.Name = "lbRenderTime";
- this.lbRenderTime.Size = new System.Drawing.Size(11, 13);
- this.lbRenderTime.TabIndex = 0;
- this.lbRenderTime.Text = "-";
- //
- // lbAreaMin
- //
- this.lbAreaMin.ForeColor = System.Drawing.Color.White;
- this.lbAreaMin.Location = new System.Drawing.Point(97, 296);
- this.lbAreaMin.Name = "lbAreaMin";
- this.lbAreaMin.Size = new System.Drawing.Size(68, 13);
- this.lbAreaMin.TabIndex = 0;
- this.lbAreaMin.Text = "-";
- this.lbAreaMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbAreaMax
- //
- this.lbAreaMax.ForeColor = System.Drawing.Color.White;
- this.lbAreaMax.Location = new System.Drawing.Point(179, 296);
- this.lbAreaMax.Name = "lbAreaMax";
- this.lbAreaMax.Size = new System.Drawing.Size(76, 13);
- this.lbAreaMax.TabIndex = 0;
- this.lbAreaMax.Text = "-";
- this.lbAreaMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbEdgeMin
- //
- this.lbEdgeMin.ForeColor = System.Drawing.Color.White;
- this.lbEdgeMin.Location = new System.Drawing.Point(97, 320);
- this.lbEdgeMin.Name = "lbEdgeMin";
- this.lbEdgeMin.Size = new System.Drawing.Size(68, 13);
- this.lbEdgeMin.TabIndex = 0;
- this.lbEdgeMin.Text = "-";
- this.lbEdgeMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbEdgeMax
- //
- this.lbEdgeMax.ForeColor = System.Drawing.Color.White;
- this.lbEdgeMax.Location = new System.Drawing.Point(179, 320);
- this.lbEdgeMax.Name = "lbEdgeMax";
- this.lbEdgeMax.Size = new System.Drawing.Size(76, 13);
- this.lbEdgeMax.TabIndex = 0;
- this.lbEdgeMax.Text = "-";
- this.lbEdgeMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbRatioMin
- //
- this.lbRatioMin.ForeColor = System.Drawing.Color.White;
- this.lbRatioMin.Location = new System.Drawing.Point(97, 343);
- this.lbRatioMin.Name = "lbRatioMin";
- this.lbRatioMin.Size = new System.Drawing.Size(68, 13);
- this.lbRatioMin.TabIndex = 0;
- this.lbRatioMin.Text = "-";
- this.lbRatioMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbRatioMax
- //
- this.lbRatioMax.ForeColor = System.Drawing.Color.White;
- this.lbRatioMax.Location = new System.Drawing.Point(179, 343);
- this.lbRatioMax.Name = "lbRatioMax";
- this.lbRatioMax.Size = new System.Drawing.Size(76, 13);
- this.lbRatioMax.TabIndex = 0;
- this.lbRatioMax.Text = "-";
- this.lbRatioMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbAngleMin
- //
- this.lbAngleMin.ForeColor = System.Drawing.Color.White;
- this.lbAngleMin.Location = new System.Drawing.Point(97, 366);
- this.lbAngleMin.Name = "lbAngleMin";
- this.lbAngleMin.Size = new System.Drawing.Size(68, 13);
- this.lbAngleMin.TabIndex = 0;
- this.lbAngleMin.Text = "-";
- this.lbAngleMin.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // lbAngleMax
- //
- this.lbAngleMax.ForeColor = System.Drawing.Color.White;
- this.lbAngleMax.Location = new System.Drawing.Point(179, 366);
- this.lbAngleMax.Name = "lbAngleMax";
- this.lbAngleMax.Size = new System.Drawing.Size(76, 13);
- this.lbAngleMax.TabIndex = 0;
- this.lbAngleMax.Text = "-";
- this.lbAngleMax.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
- //
- // histogram1
- //
- this.histogram1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(76)))), ((int)(((byte)(76)))), ((int)(((byte)(76)))));
- this.histogram1.Location = new System.Drawing.Point(15, 428);
- this.histogram1.Name = "histogram1";
- this.histogram1.Size = new System.Drawing.Size(257, 212);
- this.histogram1.TabIndex = 1;
- this.histogram1.Text = "histogram1";
- //
- // Form2
+ // FormQuality
//
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(284, 652);
- this.Controls.Add(this.histogram1);
- this.Controls.Add(this.label8);
- this.Controls.Add(this.label13);
- this.Controls.Add(this.label12);
- this.Controls.Add(this.label16);
- this.Controls.Add(this.label15);
- this.Controls.Add(this.label14);
- this.Controls.Add(this.lbAngleMax);
- this.Controls.Add(this.lbRatioMax);
- this.Controls.Add(this.lbEdgeMax);
- this.Controls.Add(this.lbAreaMax);
- this.Controls.Add(this.lbAngleMin);
- this.Controls.Add(this.lbRatioMin);
- this.Controls.Add(this.lbEdgeMin);
- this.Controls.Add(this.lbAreaMin);
- this.Controls.Add(this.label10);
- this.Controls.Add(this.label17);
- this.Controls.Add(this.label9);
- this.Controls.Add(this.label7);
- this.Controls.Add(this.label11);
- this.Controls.Add(this.label6);
- this.Controls.Add(this.label5);
- this.Controls.Add(this.label4);
- this.Controls.Add(this.label3);
- this.Controls.Add(this.label2);
- this.Controls.Add(this.lbRenderTime);
- this.Controls.Add(this.lbCalcTime);
- this.Controls.Add(this.lbNumBoundary);
- this.Controls.Add(this.lbNumEdge);
- this.Controls.Add(this.lbNumTri);
- this.Controls.Add(this.lbNumOutput);
- this.Controls.Add(this.lbNumInput);
+ this.ClientSize = new System.Drawing.Size(200, 300);
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.Gray;
- this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
- this.Name = "Form2";
- this.ShowIcon = false;
+ this.Name = "FormQuality";
this.ShowInTaskbar = false;
- this.Text = "Mesh Statistic";
- this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form2_FormClosing);
+ this.Text = "Mesh Quality";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormQuality_FormClosing);
this.ResumeLayout(false);
this.PerformLayout();
@@ -453,37 +64,5 @@
#endregion
private System.Windows.Forms.Label label1;
- private System.Windows.Forms.Label label2;
- private System.Windows.Forms.Label label3;
- private System.Windows.Forms.Label label4;
- private System.Windows.Forms.Label label5;
- private System.Windows.Forms.Label label6;
- private System.Windows.Forms.Label label7;
- private System.Windows.Forms.Label label8;
- private System.Windows.Forms.Label label9;
- private System.Windows.Forms.Label label10;
- private System.Windows.Forms.Label label11;
- private System.Windows.Forms.Label label12;
- private System.Windows.Forms.Label label13;
- private System.Windows.Forms.Label label14;
- private System.Windows.Forms.Label label15;
- private System.Windows.Forms.Label label16;
- private System.Windows.Forms.Label label17;
- private System.Windows.Forms.Label lbNumInput;
- private System.Windows.Forms.Label lbNumOutput;
- private System.Windows.Forms.Label lbNumTri;
- private System.Windows.Forms.Label lbNumEdge;
- private System.Windows.Forms.Label lbNumBoundary;
- private System.Windows.Forms.Label lbCalcTime;
- private System.Windows.Forms.Label lbRenderTime;
- private System.Windows.Forms.Label lbAreaMin;
- private System.Windows.Forms.Label lbAreaMax;
- private System.Windows.Forms.Label lbEdgeMin;
- private System.Windows.Forms.Label lbEdgeMax;
- private System.Windows.Forms.Label lbRatioMin;
- private System.Windows.Forms.Label lbRatioMax;
- private System.Windows.Forms.Label lbAngleMin;
- private System.Windows.Forms.Label lbAngleMax;
- private Controls.AngleHistogram histogram1;
}
}
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/FormQuality.cs b/Triangle.NET/TestApp/FormQuality.cs
index c5eaa1a..6606983 100644
--- a/Triangle.NET/TestApp/FormQuality.cs
+++ b/Triangle.NET/TestApp/FormQuality.cs
@@ -6,77 +6,36 @@ using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
-using TriangleNet;
-using System.Globalization;
+using TriangleNet.IO;
+using MeshExplorer.Rendering;
-namespace TestApp
+namespace MeshExplorer
{
public partial class FormQuality : Form
{
- static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
-
public FormQuality()
{
InitializeComponent();
-
}
- public void UpdateSatistic(Statistic stat, long calcTime, long renderTime)
+ public void UpdateQuality(RenderData data)
{
- UpdateMesh(stat);
- UpdateQuality(stat);
- UpdateTime(calcTime, renderTime);
-
- histogram1.SetData(stat.AngleHistogram);
- }
-
- private void UpdateMesh(Statistic stat)
- {
- lbNumInput.Text = stat.InputVertices.ToString();
- lbNumOutput.Text = stat.Vertices.ToString();
- lbNumTri.Text = stat.Triangles.ToString();
- lbNumEdge.Text = stat.Edges.ToString();
- lbNumBoundary.Text = stat.BoundaryEdges.ToString();
- }
-
- private void UpdateQuality(Statistic stat)
- {
- lbAreaMin.Text = stat.SmallestArea.ToString("0.00000", nfi);
- lbAreaMax.Text = stat.LargestArea.ToString("0.00000", nfi);
- lbEdgeMin.Text = stat.ShortestEdge.ToString("0.00000", nfi);
- lbEdgeMax.Text = stat.LongestEdge.ToString("0.00000", nfi);
- lbRatioMin.Text = stat.ShortestAltitude.ToString("0.00000", nfi);
- lbRatioMax.Text = stat.LargestAspectRatio.ToString("0.00000", nfi);
- lbAngleMin.Text = stat.SmallestAngle.ToString("0.00000", nfi);
- lbAngleMax.Text = stat.LargestAngle.ToString("0.00000", nfi);
- }
-
- private void UpdateTime(long calcTime, long renderTime)
- {
- if (calcTime > 0)
+ if (data != null)
{
- lbCalcTime.Text = calcTime + " ms";
- }
- else
- {
- lbCalcTime.Text = "-";
- }
+ //MeshQuality q = new MeshQuality();
+ //string s = q.Update(data);
- if (renderTime > 0)
- {
- lbRenderTime.Text = renderTime + " ms";
- }
- else
- {
- lbRenderTime.Text = "-";
+ //label1.Text = s;
}
}
- private void Form2_FormClosing(object sender, FormClosingEventArgs e)
+ private void FormQuality_FormClosing(object sender, FormClosingEventArgs e)
{
- if (e.CloseReason != CloseReason.UserClosing) return;
- e.Cancel = true;
- this.Hide();
+ if (e.CloseReason == CloseReason.UserClosing)
+ {
+ e.Cancel = true;
+ this.Hide();
+ }
}
}
}
diff --git a/Triangle.NET/TestApp/IO/FileProcessor.cs b/Triangle.NET/TestApp/IO/FileProcessor.cs
index 1671bbe..348378c 100644
--- a/Triangle.NET/TestApp/IO/FileProcessor.cs
+++ b/Triangle.NET/TestApp/IO/FileProcessor.cs
@@ -65,11 +65,11 @@ namespace MeshExplorer.IO
if (ext == ".node" || ext == ".poly")
{
- //provider = new TriangleFile();
+ provider = new TriangleFile();
}
else if (ext == ".json")
{
- //provider = new JsonFile();
+ provider = new JsonFile();
}
else if (ext == ".dat")
{
diff --git a/Triangle.NET/TestApp/IO/Formats/JsonFile.cs b/Triangle.NET/TestApp/IO/Formats/JsonFile.cs
new file mode 100644
index 0000000..d3ad046
--- /dev/null
+++ b/Triangle.NET/TestApp/IO/Formats/JsonFile.cs
@@ -0,0 +1,134 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.IO.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.IO;
+ using System.IO;
+ using MeshExplorer.Rendering;
+ using TriangleNet.Geometry;
+ using TriangleNet;
+
+ ///
+ /// TODO: Update summary.
+ ///
+ public class JsonFile : MeshExplorer.IO.IMeshFormat
+ {
+ ///
+ /// Gets the supported file extensions.
+ ///
+ public string[] Extensions
+ {
+ get { return new string[] { ".json" }; }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public InputGeometry Read(string filename)
+ {
+ string json = File.ReadAllText(filename);
+
+ JsonParser parser = new JsonParser("json");
+ object rawData = parser.Decode();
+
+ InputGeometry data = new InputGeometry();
+
+ List triangles = new List();
+
+ return data;
+ }
+
+ public void Write(string filename, Mesh data)
+ {
+ using (StreamWriter writer = new StreamWriter(filename))
+ {
+ int nv = data.NumberOfVertices;
+ int ns = data.NumberOfSegments;
+ int ne = data.NumberOfTriangles;
+ int nn = data.NumberOfTriangles;
+ int i = 0;
+
+ string sep = String.Empty;
+
+ // Header
+ writer.Write("{{\"format\":\"{0}\",\"dim\":2", ne > 0 ? "mesh" : (ns > 0 ? "poly" : "nodes"));
+
+ // Write the coordinates
+ writer.Write(",\"points\":[");
+ foreach (var item in data.Vertices)
+ {
+ sep = (i == nv - 1) ? String.Empty : ", ";
+
+ writer.Write("{0},{1}{2}",
+ item.X.ToString(Util.Nfi),
+ item.Y.ToString(Util.Nfi), sep);
+
+ i++;
+ }
+ writer.Write("]");
+
+ // Write the segments
+ if (ns > 0)
+ {
+ writer.Write(",\"segments\":[");
+ foreach (var item in data.Segments)
+ {
+ sep = (i == ns - 1) ? String.Empty : ", ";
+
+ writer.Write("{0},{1}{2}",
+ item.P0, item.P1, sep);
+
+ i++;
+ }
+
+ writer.Write("]");
+ }
+
+ // Write the elements
+ if (ne > 0)
+ {
+ writer.Write(",\"triangles\":[");
+ foreach (var item in data.Triangles)
+ {
+ sep = (i == ne - 1) ? String.Empty : ", ";
+
+ writer.Write("{0},{1},{2}{3}",
+ item.P0, item.P1, item.P2, sep);
+
+ i++;
+ }
+ writer.Write("]");
+ }
+
+ // Write neighbors
+ if (nn > 0)
+ {
+ writer.Write(",\"neighbors\":[");
+ //for (int i = 0; i < nn; i++)
+ //{
+ // sep = (i == nn - 1) ? String.Empty : ", ";
+
+ // writer.Write("{0},{1},{2}{3}",
+ // data.Neighbors[i][0],
+ // data.Neighbors[i][1],
+ // data.Neighbors[i][2], sep);
+
+ //}
+ writer.Write("]");
+ }
+
+ writer.Write("}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Triangle.NET/TestApp/IO/Formats/TriangleFile.cs b/Triangle.NET/TestApp/IO/Formats/TriangleFile.cs
new file mode 100644
index 0000000..c5642ad
--- /dev/null
+++ b/Triangle.NET/TestApp/IO/Formats/TriangleFile.cs
@@ -0,0 +1,133 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer.IO.Formats
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.IO;
+ using System.IO;
+ using TriangleNet.Geometry;
+ using TriangleNet;
+
+ ///
+ /// TODO: Update summary.
+ ///
+ public class TriangleFile : MeshExplorer.IO.IMeshFormat
+ {
+ ///
+ /// Gets the supported file extensions.
+ ///
+ public string[] Extensions
+ {
+ get { return new string[] { ".node", ".poly" }; }
+ }
+
+
+ public InputGeometry Read(string file)
+ {
+ string supp = Path.ChangeExtension(file, ".ele");
+
+ return FileReader.ReadFile(file, File.Exists(supp));
+ }
+
+ public void Write(string file, Mesh data)
+ {
+ if (data.NumberOfVertices > 0)
+ {
+ WritePoly(file, data);
+
+ if (data.Triangles != null)
+ {
+ file = Path.ChangeExtension(file, "ele");
+
+ WriteElements(file, data);
+ }
+ }
+ }
+
+ private void WritePoly(string file, Mesh data)
+ {
+ int i = 0;
+ int n = data.NumberOfVertices;
+ bool markers = true;
+
+ using (StreamWriter writer = new StreamWriter(file))
+ {
+ // Write nodes
+ writer.WriteLine("{0} 2 0 {1}", n, markers ? "1" : "0");
+
+ // TODO: point attributes
+ foreach (var item in data.Vertices)
+ {
+ writer.Write("{0} {1} {2}", i++,
+ item.X.ToString(Util.Nfi),
+ item.Y.ToString(Util.Nfi));
+
+ if (markers)
+ {
+ writer.Write(" {0}", item.Boundary);
+ }
+
+ writer.WriteLine();
+ }
+
+ // Write segments
+ n = data.NumberOfSegments;
+ i = 0;
+
+ // Number of segments, number of boundary markers (zero or one).
+ writer.WriteLine("{0} {1}", n, markers ? "1" : "0");
+
+ foreach (var item in data.Segments)
+ {
+ writer.Write("{0} {1} {2}", i,
+ item.P0, item.P1);
+
+ if (markers)
+ {
+ writer.Write(" {0}", item.Boundary);
+ }
+
+ writer.WriteLine();
+ }
+
+ // Write holes
+ n = data.Holes.Count;
+
+ writer.WriteLine("{0}", n);
+
+ foreach (var item in data.Holes)
+ {
+ writer.WriteLine("{0} {1}",
+ data.Holes[i].X.ToString(Util.Nfi),
+ data.Holes[i].Y.ToString(Util.Nfi));
+ }
+
+ // TODO: Regions
+ }
+ }
+
+ public void WriteElements(string file, Mesh data)
+ {
+ using (StreamWriter writer = new StreamWriter(file))
+ {
+ int i = 0;
+
+ // TODO: attributes
+ writer.WriteLine("{0} 3 0", data.NumberOfTriangles);
+
+ foreach (var item in data.Triangles)
+ {
+ writer.WriteLine("{0} {1} {2} {3}", i++,
+ item.P0, item.P1, item.P2);
+ }
+ }
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/ImageWriter.cs b/Triangle.NET/TestApp/ImageWriter.cs
index a0711f1..b3037cb 100644
--- a/Triangle.NET/TestApp/ImageWriter.cs
+++ b/Triangle.NET/TestApp/ImageWriter.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp
+namespace MeshExplorer
{
using System;
using System.Drawing;
@@ -20,8 +20,7 @@ namespace TestApp
///
public static class ImageWriter
{
- // Number of input points
- static int NumberOfInputPoints = 0;
+ static PointF[] points;
// Default color scheme (dark)
static Color bgColor = Color.Black;
@@ -30,7 +29,7 @@ namespace TestApp
static Color lnColor = Color.FromArgb(30, 30, 30);
static Color sgColor = Color.Blue;
static Color trColor = Color.FromArgb(30, 40, 50);
-
+
///
/// Sets the color scheme.
///
@@ -39,7 +38,7 @@ namespace TestApp
/// Steiner points color.
/// Line color.
/// Segment color.
- public static void SetColorScheme(Color background, Color points, Color steiner,
+ public static void SetColorScheme(Color background, Color points, Color steiner,
Color lines, Color segments, Color triangles)
{
bgColor = background;
@@ -113,38 +112,20 @@ namespace TestApp
/// The target width of the image (pixel).
public static void WritePng(Mesh mesh, string filename, int width)
{
- NumberOfInputPoints = mesh.NumberOfInputPoints;
+ int i = 0, n = mesh.NumberOfVertices;
+
+ points = new PointF[n];
+
+ foreach (var pt in mesh.Vertices)
+ {
+ points[i++] = new PointF((float)pt.X, (float)pt.Y);
+ }
if (String.IsNullOrWhiteSpace(filename))
{
filename = String.Format("mesh-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
}
- MeshData data = mesh.GetMeshData(true, true, false);
-
- // Mesh bounds
- float minx = float.MaxValue;
- float maxx = float.MinValue;
- float miny = float.MaxValue;
- float maxy = float.MinValue;
-
- float x, y;
-
- int n = data.Points.Length;
-
- // Calculate bounds
- for (int i = 0; i < n; i++)
- {
- x = (float)data.Points[i][0];
- y = (float)data.Points[i][1];
-
- // Update bounding box
- if (minx > x) minx = x;
- if (maxx < x) maxx = x;
- if (miny > y) miny = y;
- if (maxy < y) maxy = y;
- }
-
Bitmap bitmap;
// Check if the specified width is reasonable
@@ -166,20 +147,87 @@ namespace TestApp
}
else
{
+ var bounds = mesh.Bounds;
// World margin on each side
- float margin = (maxy - miny) * 0.05f;
- float scale = width / (maxx - minx + 2 * margin);
+ float margin = (float)bounds.Height * 0.05f;
+ float scale = width / ((float)bounds.Width + 2 * margin);
- bitmap = new Bitmap(width, (int)((maxy - miny + 2 * margin) * scale), PixelFormat.Format32bppArgb);
+ bitmap = new Bitmap(width, (int)((bounds.Height + 2 * margin) * scale), PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(bgColor);
// Transform world to screen
g.ScaleTransform(scale, -scale);
- g.TranslateTransform(-minx + margin, -maxy - margin);
+ g.TranslateTransform(-(float)bounds.Xmin + margin, -(float)bounds.Ymax - margin);
- DrawMesh(g, data, scale);
+ DrawMesh(g, mesh, scale);
+
+ g.Dispose();
+ }
+
+ if (Path.GetExtension(filename) != ".png")
+ {
+ filename += ".png";
+ }
+
+ bitmap.Save(filename, ImageFormat.Png);
+ }
+
+ ///
+ /// Draws the voronoi diagram and writes the image file.
+ ///
+ /// The mesh to visualize.
+ /// The filename (only PNG supported).
+ /// The target width of the image (pixel).
+ public static void WriteVoronoiPng(Mesh mesh, string filename, int width)
+ {
+ if (String.IsNullOrWhiteSpace(filename))
+ {
+ filename = String.Format("mesh-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
+ }
+
+ VoronoiData data = DataWriter.WriteVoronoi(mesh);
+
+ int n = data.Points.Length;
+
+ var bounds = mesh.Bounds;
+
+ Bitmap bitmap;
+
+ // Check if the specified width is reasonable
+ if (width < 2 * Math.Sqrt(n))
+ {
+ bitmap = new Bitmap(400, 200);
+ Graphics g = Graphics.FromImage(bitmap);
+ g.Clear(Color.Black);
+
+ string message = String.Format("Sorry, I won't render {0} points on such a small image!", n);
+
+ SizeF sz = g.MeasureString(message, SystemFonts.DefaultFont);
+
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+ g.DrawString(message, SystemFonts.DefaultFont, Brushes.White,
+ 200 - sz.Width / 2, 100 - sz.Height / 2);
+
+ g.Dispose();
+ }
+ else
+ {
+ // World margin on each side
+ float margin = (float)bounds.Height * 0.05f;
+ float scale = width / ((float)bounds.Width + 2 * margin);
+
+ bitmap = new Bitmap(width, (int)((bounds.Height + 2 * margin) * scale), PixelFormat.Format32bppArgb);
+
+ Graphics g = Graphics.FromImage(bitmap);
+ g.Clear(bgColor);
+
+ // Transform world to screen
+ g.ScaleTransform(scale, -scale);
+ g.TranslateTransform(-(float)bounds.Xmin + margin, -(float)bounds.Ymax - margin);
+
+ DrawVoronoi(g, mesh, data, scale);
g.Dispose();
}
@@ -195,11 +243,11 @@ namespace TestApp
///
/// Draw mesh to the graphics object.
///
- private static void DrawMesh(Graphics g, MeshData mesh, float scale)
+ private static void DrawMesh(Graphics g, Mesh mesh, float scale)
{
g.SmoothingMode = SmoothingMode.AntiAlias;
// Colors
-
+
Brush bgBrush = new SolidBrush(bgColor);
Brush ptBrush = new SolidBrush(ptColor);
Brush spBrush = new SolidBrush(spColor);
@@ -213,46 +261,38 @@ namespace TestApp
PointF p1, p2, p3;
- int[] tmp;
-
// Draw triangle edges
- int n = mesh.Triangles == null ? 0 : mesh.Triangles.Length;
-
- for (int i = 0; i < n; i++)
+ foreach (var tri in mesh.Triangles)
{
- tmp = mesh.Triangles[i];
-
- p1 = new PointF((float)mesh.Points[tmp[0]][0], (float)mesh.Points[tmp[0]][1]);
- p2 = new PointF((float)mesh.Points[tmp[1]][0], (float)mesh.Points[tmp[1]][1]);
- p3 = new PointF((float)mesh.Points[tmp[2]][0], (float)mesh.Points[tmp[2]][1]);
+ p1 = points[tri.P0];
+ p2 = points[tri.P1];
+ p3 = points[tri.P2];
// Fill triangle
g.FillPolygon(trBrush, new PointF[] { p1, p2, p3 });
}
// Draw edges
+ /*
n = mesh.Edges == null ? 0 : mesh.Edges.Length;
for (int i = 0; i < n; i++)
{
tmp = mesh.Edges[i];
- p1 = new PointF((float)mesh.Points[tmp[0]][0], (float)mesh.Points[tmp[0]][1]);
- p2 = new PointF((float)mesh.Points[tmp[1]][0], (float)mesh.Points[tmp[1]][1]);
+ p1 = new PointF((float)mesh.Points[tmp[0]].X, (float)mesh.Points[tmp[0]].Y);
+ p2 = new PointF((float)mesh.Points[tmp[1]].X, (float)mesh.Points[tmp[1]].Y);
// Draw line
g.DrawLine(lnBrush, p1, p2);
}
+ * */
// Draw segments
- n = mesh.Segments == null ? 0 : mesh.Segments.Length;
-
- for (int i = 0; i < n; i++)
+ foreach (var seg in mesh.Segments)
{
- tmp = mesh.Segments[i];
-
- p1 = new PointF((float)mesh.Points[tmp[0]][0], (float)mesh.Points[tmp[0]][1]);
- p2 = new PointF((float)mesh.Points[tmp[1]][0], (float)mesh.Points[tmp[1]][1]);
+ p1 = points[seg.P0];
+ p2 = points[seg.P1];
// Draw line
g.DrawLine(sgBrush, p1, p2);
@@ -262,19 +302,14 @@ namespace TestApp
float radius = 1.5f / scale, x, y;
// Draw points
- n = mesh.Points.Length;
-
- if (NumberOfInputPoints <= 0)
- {
- NumberOfInputPoints = n;
- }
+ int n = mesh.NumberOfInputPoints;
for (int i = 0; i < n; i++)
{
- x = (float)mesh.Points[i][0];
- y = (float)mesh.Points[i][1];
+ x = points[i].X;
+ y = points[i].Y;
- if (i < NumberOfInputPoints)
+ if (i < n)
{
g.FillEllipse(ptBrush, x - radius, y - radius, 2 * radius, 2 * radius);
//g.DrawEllipse(ptBrush, x - radius, y - radius, 2 * radius, 2 * radius);
@@ -293,5 +328,214 @@ namespace TestApp
sgBrush.Dispose();
trBrush.Dispose();
}
+
+ ///
+ /// Draw mesh to the graphics object.
+ ///
+ private static void DrawVoronoi(Graphics g, Mesh mesh, VoronoiData voronoi, float scale)
+ {
+ g.SmoothingMode = SmoothingMode.AntiAlias;
+ // Colors
+
+ Brush bgBrush = new SolidBrush(bgColor);
+ Brush ptBrush = new SolidBrush(ptColor);
+ Brush spBrush = new SolidBrush(spColor);
+ Brush trBrush = new SolidBrush(trColor);
+
+ // Scale the pens to 1 pixel width
+ //Pen ptBrush = new Pen(ptColor, 1 / scale);
+ //Pen spBrush = new Pen(spColor, 1 / scale);
+ Pen lnBrush = new Pen(lnColor, 1 / scale);
+ Pen sgBrush = new Pen(sgColor, 1 / scale);
+
+ PointF p1, p2;
+
+ int[] tmp;
+
+ BBox bounds = new BBox(mesh.Bounds);
+
+ // Enlarge 50%
+ bounds.Extend(0.5f);
+
+ // Draw edges
+ int n = voronoi.Edges == null ? 0 : voronoi.Edges.Length;
+
+ for (int i = 0; i < n; i++)
+ {
+ var seg = voronoi.Edges[i];
+
+ if (seg.P1 == -1)
+ {
+ // Infinite voronoi edge
+ p1 = new PointF((float)voronoi.Points[seg.P0].X, (float)voronoi.Points[seg.P0].Y);
+ p2 = VoronoiBoxIntersection(bounds, voronoi.Points[seg.P0], voronoi.Directions[i]);
+ }
+ else
+ {
+ p1 = new PointF((float)voronoi.Points[seg.P0].X, (float)voronoi.Points[seg.P0].Y);
+ p2 = new PointF((float)voronoi.Points[seg.P1].X, (float)voronoi.Points[seg.P1].Y);
+ }
+
+ // Draw line
+ g.DrawLine(lnBrush, p1, p2);
+ }
+
+ // Shrink 50%
+ bounds.Extend(-0.5f);
+
+ // Scale the points radius to 2 pixel.
+ float radius = 1.5f / scale, x, y;
+
+ // Draw points
+ n = voronoi.Points.Length;
+
+ for (int i = 0; i < n; i++)
+ {
+ x = (float)voronoi.Points[i].X;
+ y = (float)voronoi.Points[i].Y;
+
+ g.FillEllipse(ptBrush, x - radius, y - radius, 2 * radius, 2 * radius);
+ //g.DrawEllipse(ptBrush, x - radius, y - radius, 2 * radius, 2 * radius);
+ }
+
+ // Draw input points
+ n = voronoi.InputPoints.Length;
+
+ for (int i = 0; i < n; i++)
+ {
+ x = (float)voronoi.InputPoints[i].X;
+ y = (float)voronoi.InputPoints[i].Y;
+
+ g.FillEllipse(spBrush, x - radius, y - radius, 2 * radius, 2 * radius);
+ //g.DrawEllipse(spBrush, x - radius, y - radius, 2 * radius, 2 * radius);
+ }
+
+ bgBrush.Dispose();
+ ptBrush.Dispose();
+ spBrush.Dispose();
+ lnBrush.Dispose();
+ sgBrush.Dispose();
+ trBrush.Dispose();
+ }
+
+ private static PointF VoronoiBoxIntersection(BBox bounds, TriangleNet.Geometry.Point pt, double[] direction)
+ {
+ double x = pt.X;
+ double y = pt.Y;
+ double dx = direction[0];
+ double dy = direction[1];
+
+ double t1, x1, y1, t2, x2, y2;
+
+ // Check if point is inside the bounds
+ if (x < bounds.MinX || x > bounds.MaxX || y < bounds.MinY || y > bounds.MaxY)
+ {
+ throw new ArgumentException("Point must be located inside the bounding box.");
+ }
+
+ // Calculate the cut through the vertical boundaries
+ if (dx < 0)
+ {
+ // Line going to the left: intersect with x = bounds.MinX
+ t1 = (bounds.MinX - x) / dx;
+ x1 = bounds.MinX;
+ y1 = y + t1 * dy;
+ }
+ else if (dx > 0)
+ {
+ // Line going to the right: intersect with x = bounds.MaxX
+ t1 = (bounds.MaxX - x) / dx;
+ x1 = bounds.MaxX;
+ y1 = y + t1 * dy;
+ }
+ else
+ {
+ // Line going straight up or down: no intersection possible
+ t1 = double.MaxValue;
+ x1 = y1 = 0;
+ }
+
+ // Calculate the cut through upper and lower boundaries
+ if (dy < 0)
+ {
+ // Line going downwards: intersect with y = bounds.MinY
+ t2 = (bounds.MinY - y) / dy;
+ x2 = x + t2 * dx;
+ y2 = bounds.MinY;
+ }
+ else if (dx > 0)
+ {
+ // Line going upwards: intersect with y = bounds.MaxY
+ t2 = (bounds.MaxY - y) / dy;
+ x2 = x + t2 * dx;
+ y2 = bounds.MaxY;
+ }
+ else
+ {
+ // Horizontal line: no intersection possible
+ t2 = double.MaxValue;
+ x2 = y2 = 0;
+ }
+
+ if (t1 < t2)
+ {
+ return new PointF((float)x1, (float)y1);
+ }
+
+ return new PointF((float)x2, (float)y2);
+ }
+
+ ///
+ /// Bounding box.
+ ///
+ struct BBox
+ {
+ public float MinX;
+ public float MaxX;
+ public float MinY;
+ public float MaxY;
+
+ public float Width { get { return MaxX - MinX; } }
+ public float Height { get { return MaxY - MinY; } }
+
+ public BBox(TriangleNet.Geometry.BoundingBox box)
+ {
+ MinX = (float)box.Xmin;
+ MaxX = (float)box.Xmax;
+ MinY = (float)box.Ymin;
+ MaxY = (float)box.Ymax;
+ }
+
+ public void Reset()
+ {
+ MinX = float.MaxValue;
+ MaxX = float.MinValue;
+ MinY = float.MaxValue;
+ MaxY = float.MinValue;
+ }
+
+ public void Update(TriangleNet.Geometry.Point pt)
+ {
+ float x = (float)pt.X;
+ float y = (float)pt.Y;
+
+ // Update bounding box
+ if (MinX > x) MinX = x;
+ if (MaxX < x) MaxX = x;
+ if (MinY > y) MinY = y;
+ if (MaxY < y) MaxY = y;
+ }
+
+ public void Extend(float amount)
+ {
+ float dx = amount * this.Width;
+ float dy = amount * this.Height;
+
+ MinX -= dx;
+ MaxX += dx;
+ MinY -= dy;
+ MaxY += dy;
+ }
+ }
}
}
diff --git a/Triangle.NET/TestApp/Mesh Explorer.csproj b/Triangle.NET/TestApp/Mesh Explorer.csproj
index 4b52f34..49a561a 100644
--- a/Triangle.NET/TestApp/Mesh Explorer.csproj
+++ b/Triangle.NET/TestApp/Mesh Explorer.csproj
@@ -46,6 +46,7 @@
+
Component
@@ -55,10 +56,29 @@
Component
+
+ Component
+
+
+ Component
+
+
+ Component
+
Component
+
+
+ Form
+
+
+ Form
+
+
+ FormLog.cs
+
Form
@@ -77,12 +97,16 @@
+
+
+
+
FormMain.cs
diff --git a/Triangle.NET/TestApp/PolygonGenerator.cs b/Triangle.NET/TestApp/PolygonGenerator.cs
new file mode 100644
index 0000000..cc6a254
--- /dev/null
+++ b/Triangle.NET/TestApp/PolygonGenerator.cs
@@ -0,0 +1,115 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using MeshExplorer.IO;
+ using TriangleNet.IO;
+ using MeshExplorer.Rendering;
+ using TriangleNet.Geometry;
+
+ ///
+ /// TODO: Update summary.
+ ///
+ public static class PolygonGenerator
+ {
+ public static InputGeometry StarInBox(int n)
+ {
+ InputGeometry input = new InputGeometry(n + 4);
+
+ input.AddPoint(0, 0); // Center
+
+ double x, y, r, e, step = 2 * Math.PI / n;
+
+ for (int i = 0; i < n; i++)
+ {
+ e = Util.Random.NextDouble() * step * 0.7;
+ r = (Util.Random.NextDouble() + 0.7) * 0.5;
+ x = r * Math.Cos(i * step + e);
+ y = r * Math.Sin(i * step + e);
+
+ input.AddPoint(x, y);
+ input.AddSegment(0, i + 1);
+ }
+
+ input.AddPoint(-1, -1); // Box
+ input.AddPoint(1, -1);
+ input.AddPoint(1, 1);
+ input.AddPoint(-1, 1);
+
+ n = input.Count;
+ input.AddSegment(n - 1, n - 2);
+ input.AddSegment(n - 2, n - 3);
+ input.AddSegment(n - 3, n - 4);
+ input.AddSegment(n - 4, n - 1);
+
+ return input;
+ }
+
+
+ public static InputGeometry CreateRandomPoints(int numPoints, int width, int height)
+ {
+ InputGeometry input = new InputGeometry(numPoints);
+
+ for (int i = 0; i < numPoints; i++)
+ {
+ input.AddPoint(Util.Random.NextDouble() * width,
+ Util.Random.NextDouble() * height);
+ }
+
+ return input;
+ }
+
+ public static InputGeometry CreateCirclePoints(double x, double y, double r, int n)
+ {
+ InputGeometry input = new InputGeometry(n + 1);
+
+ // Add center
+ input.AddPoint(x, y);
+
+ double angle = 0, step = 2 * Math.PI / n;
+
+ while (angle < 2 * Math.PI)
+ {
+ input.AddPoint(r * Math.Cos(angle), r * Math.Sin(angle));
+ angle += step;
+ }
+
+ return input;
+ }
+
+ public static InputGeometry CreateStarPoints(double x, double y, double r, int n)
+ {
+ InputGeometry input = new InputGeometry(n + 1);
+
+ // Add center
+ input.AddPoint(x, y);
+
+ double angle = 0, step = 2 * Math.PI / n;
+
+ while (angle < 2 * Math.PI)
+ {
+ input.AddPoint(r * Math.Cos(angle), r * Math.Sin(angle));
+ angle += step;
+ }
+
+ angle = step / 2;
+ r /= 1.5;
+
+ while (angle < 2 * Math.PI)
+ {
+ input.AddPoint(r * Math.Cos(angle), r * Math.Sin(angle));
+ angle += step;
+ }
+
+ return input;
+ }
+ }
+}
diff --git a/Triangle.NET/TestApp/Program.cs b/Triangle.NET/TestApp/Program.cs
index ef7d4ae..928c59e 100644
--- a/Triangle.NET/TestApp/Program.cs
+++ b/Triangle.NET/TestApp/Program.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
-namespace TestApp
+namespace MeshExplorer
{
static class Program
{
diff --git a/Triangle.NET/TestApp/Rendering/RenderData.cs b/Triangle.NET/TestApp/Rendering/RenderData.cs
index c9ed18c..b46d030 100644
--- a/Triangle.NET/TestApp/Rendering/RenderData.cs
+++ b/Triangle.NET/TestApp/Rendering/RenderData.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp.Rendering
+namespace MeshExplorer.Rendering
{
using System;
using System.Collections.Generic;
@@ -13,42 +13,82 @@ namespace TestApp.Rendering
using TriangleNet.IO;
using System.Drawing;
using TriangleNet;
+ using TriangleNet.Data;
+ using TriangleNet.Geometry;
public class RenderData
{
public PointF[] Points;
- public int[][] Triangles;
- public int[][] Edges;
- public int[][] Segments;
+
+ public Edge[] Edges;
+ public Edge[] Segments;
+ public IEnumerable Triangles;
+
public int NumberOfInputPoints;
public RectangleF Bounds;
+ public void SetData(InputGeometry data)
+ {
+ int n = data.Count;
+ int i = 0;
+
+ this.NumberOfInputPoints = n;
+
+ this.Triangles = null;
+ this.Edges = null;
+
+ // Convert points to float
+ this.Points = new PointF[n];
+ foreach (var pt in data.Points)
+ {
+ this.Points[i++] = new PointF((float)pt.X, (float)pt.Y);
+ }
+
+ this.Bounds = new RectangleF(
+ (float)data.Bounds.Xmin,
+ (float)data.Bounds.Ymin,
+ (float)data.Bounds.Width,
+ (float)data.Bounds.Height);
+
+ // Copy segments
+ this.Segments = data.Segments.ToArray();
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// This methods assumes that the mesh.Renumber() has been called.
public void SetData(Mesh mesh)
{
- NumberOfInputPoints = mesh.NumberOfInputPoints;
+ mesh.Renumber();
- SetData(mesh.GetMeshData(true, true, false), mesh.NumberOfInputPoints);
- }
+ this.NumberOfInputPoints = mesh.NumberOfInputPoints;
- public void SetData(MeshData data)
- {
- SetData(data, data.Points.Length);
- }
+ this.Triangles = mesh.Triangles;
- public void SetData(MeshData data, int inputCount)
- {
- NumberOfInputPoints = inputCount;
+ int n = mesh.NumberOfVertices;
- int n = data.Points.Length;
-
- // Reset
- Triangles = null;
- Edges = null;
- Segments = null;
-
- // Copy points
+ // Convert points to float
this.Points = new PointF[n];
+ SetPoints(mesh.Vertices);
+
+ // Get edges (more efficient than rendering triangles)
+ EdgeEnumerator e = new EdgeEnumerator(mesh);
+
+ List edgeList = new List(mesh.NumberOfEdges);
+
+ while (e.MoveNext())
+ {
+ edgeList.Add(e.Current);
+ }
+
+ this.Edges = edgeList.ToArray();
+ }
+
+ private void SetPoints(IEnumerable points)
+ {
// Bounds
float minx = float.MaxValue;
float maxx = float.MinValue;
@@ -56,11 +96,12 @@ namespace TestApp.Rendering
float maxy = float.MinValue;
float x, y;
+ int i = 0;
- for (int i = 0; i < n; i += 1)
+ foreach (var pt in points)
{
- x = (float)data.Points[i][0];
- y = (float)data.Points[i][1];
+ x = (float)pt.X;
+ y = (float)pt.Y;
// Update bounding box
if (minx > x) minx = x;
if (maxx < x) maxx = x;
@@ -68,55 +109,11 @@ namespace TestApp.Rendering
if (maxy < y) maxy = y;
this.Points[i] = new PointF(x, y);
+
+ i++;
}
this.Bounds = new RectangleF(minx, miny, maxx - minx, maxy - miny);
-
- n = data.Edges == null ? 0 : data.Edges.Length;
-
- // Copy edges
- if (data.Edges != null && n > 0)
- {
- Edges = new int[n][];
-
- for (int i = 0; i < n; i++)
- {
- Edges[i] = new int[2];
- Edges[i][0] = data.Edges[i][0];
- Edges[i][1] = data.Edges[i][1];
- }
- }
-
- n = data.Segments == null ? 0 : data.Segments.Length;
-
- // Copy segments
- if (data.Segments != null && n > 0)
- {
- Segments = new int[n][];
-
- for (int i = 0; i < n; i++)
- {
- Segments[i] = new int[2];
- Segments[i][0] = data.Segments[i][0];
- Segments[i][1] = data.Segments[i][1];
- }
- }
-
- n = data.Triangles == null ? 0 : data.Triangles.Length;
-
- // Copy triangles
- if (data.Triangles != null && n > 0)
- {
- Triangles = new int[n][];
-
- for (int i = 0; i < n; i++)
- {
- Triangles[i] = new int[3];
- Triangles[i][0] = data.Triangles[i][0];
- Triangles[i][1] = data.Triangles[i][1];
- Triangles[i][2] = data.Triangles[i][2];
- }
- }
}
}
}
diff --git a/Triangle.NET/TestApp/Rendering/Zoom.cs b/Triangle.NET/TestApp/Rendering/Zoom.cs
index b3b8595..5512a5e 100644
--- a/Triangle.NET/TestApp/Rendering/Zoom.cs
+++ b/Triangle.NET/TestApp/Rendering/Zoom.cs
@@ -4,7 +4,7 @@
//
// -----------------------------------------------------------------------
-namespace TestApp.Rendering
+namespace MeshExplorer.Rendering
{
using System;
using System.Collections.Generic;
@@ -18,8 +18,7 @@ namespace TestApp.Rendering
class Zoom
{
// The complete mesh
- int screenWidth;
- int screenHeight;
+ Rectangle Screen { get; set; }
// The complete mesh
RectangleF World { get; set; }
@@ -40,8 +39,7 @@ namespace TestApp.Rendering
public void Initialize(Rectangle screen, RectangleF world)
{
- this.screenWidth = screen.Width;
- this.screenHeight = screen.Height;
+ this.Screen = screen;
this.World = world;
this.Level = 1;
@@ -50,22 +48,57 @@ namespace TestApp.Rendering
float worldMargin = (world.Width < world.Height) ? world.Height * 0.05f : world.Width * 0.05f;
// Get the initial viewport (complete mesh centered on the screen)
- float screenRatio = this.screenWidth / (float)this.screenHeight;
+ float screenRatio = screen.Width / (float)screen.Height;
float worldRatio = world.Width / world.Height;
- float scale = (world.Width + worldMargin) / this.screenWidth;
+ float scale = (world.Width + worldMargin) / screen.Width;
if (screenRatio > worldRatio)
{
- scale = (world.Height + worldMargin) / this.screenHeight;
+ scale = (world.Height + worldMargin) / screen.Height;
}
float centerX = world.X + world.Width / 2;
float centerY = world.Y + world.Height / 2;
// TODO: Add initial margin
- this.Viewport = new RectangleF(centerX - this.screenWidth * scale / 2,
- centerY - this.screenHeight * scale / 2,
+ this.Viewport = new RectangleF(centerX - screen.Width * scale / 2,
+ centerY - screen.Height * scale / 2,
+ screen.Width * scale,
+ screen.Height * scale);
+
+ this.ClipMargin = this.Viewport.Width * 0.05f;
+
+ this.World = this.Viewport;
+ }
+
+ public void Resize(Rectangle screen, RectangleF world)
+ {
+ this.Screen = screen;
+
+ this.World = world;
+ this.Level = 1;
+
+ // Add a margin so there's some space around the border
+ float worldMargin = (World.Width < World.Height) ? World.Height * 0.05f : World.Width * 0.05f;
+
+ // Get the initial viewport (complete mesh centered on the screen)
+ float screenRatio = screen.Width / (float)screen.Height;
+ float worldRatio = World.Width / World.Height;
+
+ float scale = (World.Width + worldMargin) / screen.Width;
+
+ if (screenRatio > worldRatio)
+ {
+ scale = (World.Height + worldMargin) / screen.Height;
+ }
+
+ float centerX = World.X + World.Width / 2;
+ float centerY = World.Y + World.Height / 2;
+
+ // TODO: Add initial margin
+ this.Viewport = new RectangleF(centerX - screen.Width * scale / 2,
+ centerY - screen.Height * scale / 2,
screen.Width * scale,
screen.Height * scale);
@@ -155,8 +188,14 @@ namespace TestApp.Rendering
public PointF WorldToScreen(PointF pt)
{
- return new PointF((pt.X - Viewport.X) / Viewport.Width * screenWidth,
- (1 - (pt.Y - Viewport.Y) / Viewport.Height) * screenHeight);
+ return new PointF((pt.X - Viewport.X) / Viewport.Width * Screen.Width,
+ (1 - (pt.Y - Viewport.Y) / Viewport.Height) * Screen.Height);
+ }
+
+ public PointF ScreenToWorld(float ptX, float ptY)
+ {
+ return new PointF(Viewport.X + Viewport.Width * ptX,
+ Viewport.Y + Viewport.Height * (1 - ptY));
}
public void Reset()
diff --git a/Triangle.NET/TestApp/Settings.cs b/Triangle.NET/TestApp/Settings.cs
new file mode 100644
index 0000000..f3c48c1
--- /dev/null
+++ b/Triangle.NET/TestApp/Settings.cs
@@ -0,0 +1,71 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace MeshExplorer
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.IO;
+ using System.Windows.Forms;
+
+ ///
+ /// TODO: Update summary.
+ ///
+ public class Settings
+ {
+ // Open file dialog
+ public string OfdDirectory { get; set; }
+ public string OfdFilter { get; set; }
+ public int OfdFilterIndex{ get; set; }
+
+ // Save file dialog
+ public string SfdDirectory { get; set; }
+ public string SfdFilter { get; set; }
+ public int SfdFilterIndex { get; set; }
+
+ public string CurrentFile { get; set; }
+
+ public bool RefineMode { get; set; }
+ public bool ExceptionThrown { get; set; }
+
+ public Settings()
+ {
+ if (Directory.Exists(@"..\..\..\Data\"))
+ {
+ OfdDirectory = Path.GetFullPath(@"..\..\..\Data\");
+ }
+ else if (Directory.Exists(@"Data\"))
+ {
+ OfdDirectory = Path.GetFullPath(@"Data\");
+ }
+ else
+ {
+ //System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase;
+ OfdDirectory = Application.StartupPath;
+ }
+
+ OfdFilter = "Triangle file (*.node;*.poly)|*.node;*.poly";
+ OfdFilter += "|Triangle.NET JSON (*.json)|*.json";
+ OfdFilter += "|Polygon data (*.dat)|*.dat";
+ //OfdFilter += "|COMSOL mesh (*.mphtxt)|*.mphtxt";
+ //OfdFilter += "|AVS UCD data (*.ucd)|*.ucd";
+ //OfdFilter += "|VTK data (*.vtk)|*.vtk";
+
+ OfdFilterIndex = 0;
+
+ SfdDirectory = OfdDirectory;
+ SfdFilter = OfdFilter;
+ SfdFilterIndex = 1;
+
+ CurrentFile = "";
+
+ RefineMode = false;
+ ExceptionThrown = false;
+ }
+ }
+}
diff --git a/Triangle.NET/Triangle/Algorithm/Dwyer.cs b/Triangle.NET/Triangle/Algorithm/Dwyer.cs
index 0b56db4..fb2415e 100644
--- a/Triangle.NET/Triangle/Algorithm/Dwyer.cs
+++ b/Triangle.NET/Triangle/Algorithm/Dwyer.cs
@@ -76,7 +76,7 @@ namespace TriangleNet.Algorithm
{
var a = sortarray[i];
int j = i - 1;
- while (j >= left && (sortarray[j].pt.X > a.pt.X || (sortarray[j].pt.X == a.pt.X && sortarray[j].pt.Y > a.pt.Y)))
+ while (j >= left && (sortarray[j].x > a.x || (sortarray[j].x == a.x && sortarray[j].y > a.y)))
{
sortarray[j + 1] = sortarray[j];
j--;
@@ -89,8 +89,8 @@ namespace TriangleNet.Algorithm
// Choose a random pivot to split the array.
pivot = rand.Next(left, right);
- pivotx = sortarray[pivot].pt.X;
- pivoty = sortarray[pivot].pt.Y;
+ pivotx = sortarray[pivot].x;
+ pivoty = sortarray[pivot].y;
// Split the array.
left--;
right++;
@@ -101,17 +101,17 @@ namespace TriangleNet.Algorithm
{
left++;
}
- while ((left <= right) && ((sortarray[left].pt.X < pivotx) ||
- ((sortarray[left].pt.X == pivotx) &&
- (sortarray[left].pt.Y < pivoty))));
+ while ((left <= right) && ((sortarray[left].x < pivotx) ||
+ ((sortarray[left].x == pivotx) &&
+ (sortarray[left].y < pivoty))));
// Search for a vertex whose x-coordinate is too small for the right.
do
{
right--;
}
- while ((left <= right) && ((sortarray[right].pt.X > pivotx) ||
- ((sortarray[right].pt.X == pivotx) &&
- (sortarray[right].pt.Y > pivoty))));
+ while ((left <= right) && ((sortarray[right].x > pivotx) ||
+ ((sortarray[right].x == pivotx) &&
+ (sortarray[right].y > pivoty))));
if (left < right)
{
@@ -295,10 +295,10 @@ namespace TriangleNet.Algorithm
ref Otri farright, int axis)
{
Otri leftcand = default(Otri), rightcand = default(Otri);
- Otri baseedge = default(Otri);
Otri nextedge = default(Otri);
Otri sidecasing = default(Otri), topcasing = default(Otri), outercasing = default(Otri);
Otri checkedge = default(Otri);
+ Otri baseedge = default(Otri);
Vertex innerleftdest;
Vertex innerrightorg;
Vertex innerleftapex, innerrightapex;
@@ -326,7 +326,7 @@ namespace TriangleNet.Algorithm
// The pointers to the extremal vertices are shifted to point to the
// topmost and bottommost vertex of each hull, rather than the
// leftmost and rightmost vertices.
- while (farleftapex.pt.Y < farleftpt.pt.Y)
+ while (farleftapex.y < farleftpt.y)
{
farleft.LnextSelf();
farleft.SymSelf();
@@ -335,7 +335,7 @@ namespace TriangleNet.Algorithm
}
innerleft.Sym(ref checkedge);
checkvertex = checkedge.Apex();
- while (checkvertex.pt.Y > innerleftdest.pt.Y)
+ while (checkvertex.y > innerleftdest.y)
{
checkedge.Lnext(ref innerleft);
innerleftapex = innerleftdest;
@@ -343,7 +343,7 @@ namespace TriangleNet.Algorithm
innerleft.Sym(ref checkedge);
checkvertex = checkedge.Apex();
}
- while (innerrightapex.pt.Y < innerrightorg.pt.Y)
+ while (innerrightapex.y < innerrightorg.y)
{
innerright.LnextSelf();
innerright.SymSelf();
@@ -352,7 +352,7 @@ namespace TriangleNet.Algorithm
}
farright.Sym(ref checkedge);
checkvertex = checkedge.Apex();
- while (checkvertex.pt.Y > farrightpt.pt.Y)
+ while (checkvertex.y > farrightpt.y)
{
checkedge.Lnext(ref farright);
farrightapex = farrightpt;
@@ -366,7 +366,7 @@ namespace TriangleNet.Algorithm
{
changemade = false;
// Make innerleftdest the "bottommost" vertex of the left hull.
- if (Primitives.CounterClockwise(innerleftdest.pt, innerleftapex.pt, innerrightorg.pt) > 0.0)
+ if (Primitives.CounterClockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0)
{
innerleft.LprevSelf();
innerleft.SymSelf();
@@ -375,7 +375,7 @@ namespace TriangleNet.Algorithm
changemade = true;
}
// Make innerrightorg the "bottommost" vertex of the right hull.
- if (Primitives.CounterClockwise(innerrightapex.pt, innerrightorg.pt, innerleftdest.pt) > 0.0)
+ if (Primitives.CounterClockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0)
{
innerright.LnextSelf();
innerright.SymSelf();
@@ -384,6 +384,7 @@ namespace TriangleNet.Algorithm
changemade = true;
}
} while (changemade);
+
// Find the two candidates to be the next "gear tooth."
innerleft.Sym(ref leftcand);
innerright.Sym(ref rightcand);
@@ -418,12 +419,12 @@ namespace TriangleNet.Algorithm
// Walk up the gap between the two triangulations, knitting them together.
while (true)
{
- // Have we reached the top? (This isn't quite the right question,
- // because even though the left triangulation might seem finished now,
- // moving up on the right triangulation might reveal a new vertex of
- // the left triangulation. And vice-versa.)
- leftfinished = Primitives.CounterClockwise(upperleft.pt, lowerleft.pt, lowerright.pt) <= 0.0;
- rightfinished = Primitives.CounterClockwise(upperright.pt, lowerleft.pt, lowerright.pt) <= 0.0;
+ // Have we reached the top? (This isn't quite the right question,
+ // because even though the left triangulation might seem finished now,
+ // moving up on the right triangulation might reveal a new vertex of
+ // the left triangulation. And vice-versa.)
+ leftfinished = Primitives.CounterClockwise(upperleft, lowerleft, lowerright) <= 0.0;
+ rightfinished = Primitives.CounterClockwise(upperright, lowerleft, lowerright) <= 0.0;
if (leftfinished && rightfinished)
{
// Create the top new bounding triangle.
@@ -450,7 +451,7 @@ namespace TriangleNet.Algorithm
// The pointers to the extremal vertices are restored to the
// leftmost and rightmost vertices (rather than topmost and
// bottommost).
- while (checkvertex.pt.X < farleftpt.pt.X)
+ while (checkvertex.x < farleftpt.x)
{
checkedge.Lprev(ref farleft);
farleftapex = farleftpt;
@@ -458,7 +459,7 @@ namespace TriangleNet.Algorithm
farleft.Sym(ref checkedge);
checkvertex = checkedge.Apex();
}
- while (farrightapex.pt.X > farrightpt.pt.X)
+ while (farrightapex.x > farrightpt.x)
{
farright.LprevSelf();
farright.SymSelf();
@@ -480,7 +481,7 @@ namespace TriangleNet.Algorithm
if (nextapex != null)
{
// Check whether the edge is Delaunay.
- badedge = Primitives.InCircle(lowerleft.pt, lowerright.pt, upperleft.pt, nextapex.pt) > 0.0;
+ badedge = Primitives.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
while (badedge)
{
// Eliminate the edge with an edge flip. As a result, the
@@ -510,7 +511,7 @@ namespace TriangleNet.Algorithm
if (nextapex != null)
{
// Check whether the edge is Delaunay.
- badedge = Primitives.InCircle(lowerleft.pt, lowerright.pt, upperleft.pt, nextapex.pt) > 0.0;
+ badedge = Primitives.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
}
else
{
@@ -532,7 +533,7 @@ namespace TriangleNet.Algorithm
if (nextapex != null)
{
// Check whether the edge is Delaunay.
- badedge = Primitives.InCircle(lowerleft.pt, lowerright.pt, upperright.pt, nextapex.pt) > 0.0;
+ badedge = Primitives.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
while (badedge)
{
// Eliminate the edge with an edge flip. As a result, the
@@ -562,7 +563,7 @@ namespace TriangleNet.Algorithm
if (nextapex != null)
{
// Check whether the edge is Delaunay.
- badedge = Primitives.InCircle(lowerleft.pt, lowerright.pt, upperright.pt, nextapex.pt) > 0.0;
+ badedge = Primitives.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
}
else
{
@@ -573,7 +574,7 @@ namespace TriangleNet.Algorithm
}
}
if (leftfinished || (!rightfinished &&
- (Primitives.InCircle(upperleft.pt, lowerleft.pt, lowerright.pt, upperright.pt) > 0.0)))
+ (Primitives.InCircle(upperleft, lowerleft, lowerright, upperright) > 0.0)))
{
// Knit the triangulations, adding an edge from 'lowerleft'
// to 'upperright'.
@@ -663,7 +664,7 @@ namespace TriangleNet.Algorithm
mesh.MakeTriangle(ref tri1);
mesh.MakeTriangle(ref tri2);
mesh.MakeTriangle(ref tri3);
- area = Primitives.CounterClockwise(sortarray[left].pt, sortarray[left + 1].pt, sortarray[left + 2].pt);
+ area = Primitives.CounterClockwise(sortarray[left], sortarray[left + 1], sortarray[left + 2]);
if (area == 0.0)
{
// Three collinear vertices; the triangulation is two edges.
@@ -759,10 +760,13 @@ namespace TriangleNet.Algorithm
divider = vertices >> 1;
// Recursively triangulate each half.
DivconqRecurse(left, left + divider - 1, 1 - axis, ref farleft, ref innerleft);
+ ///dbgWriter.Write();
DivconqRecurse(left + divider, right, 1 - axis, ref innerright, ref farright);
+ ///dbgWriter.Write();
// Merge the two triangulations into one.
MergeHulls(ref farleft, ref innerleft, ref innerright, ref farright, axis);
+ ///dbgWriter.Write();
}
}
@@ -792,6 +796,7 @@ namespace TriangleNet.Algorithm
dissolveedge.Lnext(ref deadtriangle);
dissolveedge.LprevSelf();
dissolveedge.SymSelf();
+
// If no PSLG is involved, set the boundary markers of all the vertices
// on the convex hull. If a PSLG is used, this step is done later.
if (!Behavior.Poly)
@@ -810,6 +815,7 @@ namespace TriangleNet.Algorithm
dissolveedge.Dissolve();
// Find the next bounding triangle.
deadtriangle.Sym(ref dissolveedge);
+
// Delete the bounding triangle.
mesh.TriangleDealloc(deadtriangle.triangle);
} while (!dissolveedge.Equal(startghost));
@@ -817,6 +823,8 @@ namespace TriangleNet.Algorithm
return hullsize;
}
+ IO.DebugWriter dbgWriter;
+
///
/// Form a Delaunay triangulation by the divide-and-conquer method.
///
@@ -833,7 +841,10 @@ namespace TriangleNet.Algorithm
this.mesh = m;
+ dbgWriter = new IO.DebugWriter(m);
+
// Allocate an array of pointers to vertices for sorting.
+ // TODO: use ToArray
this.sortarray = new Vertex[m.invertices];
i = 0;
foreach (var v in m.vertices.Values)
@@ -847,13 +858,13 @@ namespace TriangleNet.Algorithm
i = 0;
for (j = 1; j < m.invertices; j++)
{
- if ((sortarray[i].pt.X == sortarray[j].pt.X)
- && (sortarray[i].pt.Y == sortarray[j].pt.Y))
+ if ((sortarray[i].x == sortarray[j].x)
+ && (sortarray[i].y == sortarray[j].y))
{
if (Behavior.Verbose)
{
SimpleLog.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].hash),
"DivConquer.DivconqDelaunay()");
}
sortarray[j].type = VertexType.UndeadVertex;
diff --git a/Triangle.NET/Triangle/Algorithm/Incremental.cs b/Triangle.NET/Triangle/Algorithm/Incremental.cs
index 15622d2..d1c4850 100644
--- a/Triangle.NET/Triangle/Algorithm/Incremental.cs
+++ b/Triangle.NET/Triangle/Algorithm/Incremental.cs
@@ -9,6 +9,7 @@ namespace TriangleNet.Algorithm
{
using TriangleNet.Data;
using TriangleNet.Log;
+ using TriangleNet.Geometry;
///
/// Builds a delaunay triangulation using the incremental algorithm.
@@ -25,31 +26,25 @@ namespace TriangleNet.Algorithm
/// used by the point location routines, but (mostly) ignored by the
/// Delaunay edge flip routines.
///
- void BoundingBox()
+ void GetBoundingBox()
{
Otri inftri = default(Otri); // Handle for the triangular bounding box.
- double width;
+ BoundingBox box = mesh.bounds;
// Find the width (or height, whichever is larger) of the triangulation.
- width = mesh.xmax - mesh.xmin;
- if (mesh.ymax - mesh.ymin > width)
+ double width = box.Width;
+ if (box.Height > width)
{
- width = mesh.ymax - mesh.ymin;
+ width = box.Height;
}
if (width == 0.0)
{
width = 1.0;
}
// Create the vertices of the bounding box.
- mesh.infvertex1 = new Vertex();
- mesh.infvertex2 = new Vertex();
- mesh.infvertex3 = new Vertex();
- mesh.infvertex1.pt.X = mesh.xmin - 50.0 * width;
- mesh.infvertex1.pt.Y = mesh.ymin - 40.0 * width;
- mesh.infvertex2.pt.X = mesh.xmax + 50.0 * width;
- mesh.infvertex2.pt.Y = mesh.ymin - 40.0 * width;
- mesh.infvertex3.pt.X = 0.5 * (mesh.xmin + mesh.xmax);
- mesh.infvertex3.pt.Y = mesh.ymax + 60.0 * width;
+ mesh.infvertex1 = new Vertex(box.Xmin - 50.0 * width, box.Ymin - 40.0 * width);
+ mesh.infvertex2 = new Vertex(box.Xmax + 50.0 * width, box.Ymin - 40.0 * width);
+ mesh.infvertex3 = new Vertex(0.5 * (box.Xmin + box.Xmax), box.Ymax + 60.0 * width);
// Create the bounding box.
mesh.MakeTriangle(ref inftri);
@@ -160,7 +155,7 @@ namespace TriangleNet.Algorithm
Otri starttri = new Otri();
// Create a triangular bounding box.
- BoundingBox();
+ GetBoundingBox();
foreach (var v in mesh.vertices.Values)
{
@@ -170,7 +165,7 @@ namespace TriangleNet.Algorithm
{
if (Behavior.Verbose)
{
- SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.",
+ SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.",
"Incremental.IncrementalDelaunay()");
}
v.type = VertexType.UndeadVertex;
diff --git a/Triangle.NET/Triangle/Algorithm/SweepLine.cs b/Triangle.NET/Triangle/Algorithm/SweepLine.cs
index 6f9064c..5252085 100644
--- a/Triangle.NET/Triangle/Algorithm/SweepLine.cs
+++ b/Triangle.NET/Triangle/Algorithm/SweepLine.cs
@@ -13,27 +13,14 @@ namespace TriangleNet.Algorithm
using System.Text;
using TriangleNet.Data;
using TriangleNet.Log;
+ using TriangleNet.Geometry;
+ using TriangleNet.Tools;
///
/// Builds a delaunay triangulation using the sweepline algorithm.
///
class SweepLine
{
- ///
- /// Introducing a new class which aggregates a sweep event is the easiest way
- /// to handle the pointer magic of the original code (casting a sweep event
- /// to vertex etc.).
- ///
- class SweepEventVertex : Vertex
- {
- public SweepEvent evt;
-
- public SweepEventVertex(SweepEvent e)
- {
- evt = e;
- }
- }
-
static int randomseed = 1;
static int SAMPLERATE = 10;
@@ -187,8 +174,8 @@ namespace TriangleNet.Algorithm
thisvertex = v;
evt = new SweepEvent();
evt.vertexEvent = thisvertex;
- evt.xkey = thisvertex.pt.X;
- evt.ykey = thisvertex.pt.Y;
+ evt.xkey = thisvertex.x;
+ evt.ykey = thisvertex.y;
HeapInsert(eventheap, i++, evt);
}
@@ -198,7 +185,7 @@ namespace TriangleNet.Algorithm
#region Splaytree
- SplayNode Splay(SplayNode splaytree, Vertex searchpoint, ref Otri searchtri)
+ SplayNode Splay(SplayNode splaytree, Point searchpoint, ref Otri searchtri)
{
SplayNode child, grandchild;
SplayNode lefttree, righttree;
@@ -342,7 +329,7 @@ namespace TriangleNet.Algorithm
}
}
- SplayNode SplayInsert(SplayNode splayroot, Otri newkey, Vertex searchpoint)
+ SplayNode SplayInsert(SplayNode splayroot, Otri newkey, Point searchpoint)
{
SplayNode newsplaynode;
@@ -378,22 +365,22 @@ namespace TriangleNet.Algorithm
double ccwabc;
double xac, yac, xbc, ybc;
double aclen2, bclen2;
- Vertex searchpoint = new Vertex(mesh.nextras);
+ Point searchpoint = new Point(); // TODO: mesh.nextras
Otri dummytri = default(Otri);
- ccwabc = Primitives.CounterClockwise(pa.pt, pb.pt, pc.pt);
- xac = pa.pt.X - pc.pt.X;
- yac = pa.pt.Y - pc.pt.Y;
- xbc = pb.pt.X - pc.pt.X;
- ybc = pb.pt.Y - pc.pt.Y;
+ ccwabc = Primitives.CounterClockwise(pa, pb, pc);
+ xac = pa.x - pc.x;
+ yac = pa.y - pc.y;
+ xbc = pb.x - pc.x;
+ ybc = pb.y - pc.y;
aclen2 = xac * xac + yac * yac;
bclen2 = xbc * xbc + ybc * ybc;
- searchpoint.pt.X = pc.pt.X - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc);
- searchpoint.pt.Y = topy;
+ searchpoint.x = pc.x - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc);
+ searchpoint.y = topy;
return SplayInsert(Splay(splayroot, searchpoint, ref dummytri), newkey, searchpoint);
}
- bool RightOfHyperbola(ref Otri fronttri, Vertex newsite)
+ bool RightOfHyperbola(ref Otri fronttri, Point newsite)
{
Vertex leftvertex, rightvertex;
double dxa, dya, dxb, dyb;
@@ -402,26 +389,26 @@ namespace TriangleNet.Algorithm
leftvertex = fronttri.Dest();
rightvertex = fronttri.Apex();
- if ((leftvertex.pt.Y < rightvertex.pt.Y) ||
- ((leftvertex.pt.Y == rightvertex.pt.Y) &&
- (leftvertex.pt.X < rightvertex.pt.X)))
+ if ((leftvertex.y < rightvertex.y) ||
+ ((leftvertex.y == rightvertex.y) &&
+ (leftvertex.x < rightvertex.x)))
{
- if (newsite.pt.X >= rightvertex.pt.X)
+ if (newsite.x >= rightvertex.x)
{
return true;
}
}
else
{
- if (newsite.pt.X <= leftvertex.pt.X)
+ if (newsite.x <= leftvertex.x)
{
return false;
}
}
- dxa = leftvertex.pt.X - newsite.pt.X;
- dya = leftvertex.pt.Y - newsite.pt.Y;
- dxb = rightvertex.pt.X - newsite.pt.X;
- dyb = rightvertex.pt.Y - newsite.pt.Y;
+ dxa = leftvertex.x - newsite.x;
+ dya = leftvertex.y - newsite.y;
+ dxb = rightvertex.x - newsite.x;
+ dyb = rightvertex.y - newsite.y;
return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya);
}
@@ -432,16 +419,16 @@ namespace TriangleNet.Algorithm
Statistic.CircleTopCount++;
- xac = pa.pt.X - pc.pt.X;
- yac = pa.pt.Y - pc.pt.Y;
- xbc = pb.pt.X - pc.pt.X;
- ybc = pb.pt.Y - pc.pt.Y;
- xab = pa.pt.X - pb.pt.X;
- yab = pa.pt.Y - pb.pt.Y;
+ xac = pa.x - pc.x;
+ yac = pa.y - pc.y;
+ xbc = pb.x - pc.x;
+ ybc = pb.y - pc.y;
+ xab = pa.x - pb.x;
+ yab = pa.y - pb.y;
aclen2 = xac * xac + yac * yac;
bclen2 = xbc * xbc + ybc * ybc;
ablen2 = xab * xab + yab * yab;
- return pc.pt.Y + (xac * bclen2 - xbc * aclen2 + Math.Sqrt(aclen2 * bclen2 * ablen2)) / (2.0 * ccwabc);
+ return pc.y + (xac * bclen2 - xbc * aclen2 + Math.Sqrt(aclen2 * bclen2 * ablen2)) / (2.0 * ccwabc);
}
void Check4DeadEvent(ref Otri checktri, SweepEvent[] eventheap, ref int heapsize)
@@ -506,6 +493,7 @@ namespace TriangleNet.Algorithm
dissolveedge.Lnext(ref deadtriangle);
dissolveedge.LprevSelf();
dissolveedge.SymSelf();
+
// If no PSLG is involved, set the boundary markers of all the vertices
// on the convex hull. If a PSLG is used, this step is done later.
if (!Behavior.Poly)
@@ -524,6 +512,7 @@ namespace TriangleNet.Algorithm
dissolveedge.Dissolve();
// Find the next bounding triangle.
deadtriangle.Sym(ref dissolveedge);
+
// Delete the bounding triangle.
mesh.TriangleDealloc(deadtriangle.triangle);
} while (!dissolveedge.Equal(startghost));
@@ -537,7 +526,7 @@ namespace TriangleNet.Algorithm
// Nonexistent x value used as a flag to mark circle events in sweepline
// Delaunay algorithm.
- xminextreme = 10 * mesh.xmin - 9 * mesh.xmax;
+ xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax;
SweepEvent[] eventheap;
@@ -589,8 +578,8 @@ namespace TriangleNet.Algorithm
secondvertex = eventheap[0].vertexEvent;
HeapDelete(eventheap, heapsize, 0);
heapsize--;
- if ((firstvertex.pt.X == secondvertex.pt.X) &&
- (firstvertex.pt.Y == secondvertex.pt.Y))
+ if ((firstvertex.x == secondvertex.x) &&
+ (firstvertex.y == secondvertex.y))
{
if (Behavior.Verbose)
{
@@ -600,8 +589,8 @@ namespace TriangleNet.Algorithm
secondvertex.type = VertexType.UndeadVertex;
mesh.undeads++;
}
- } while ((firstvertex.pt.X == secondvertex.pt.X) &&
- (firstvertex.pt.Y == secondvertex.pt.Y));
+ } while ((firstvertex.x == secondvertex.x) &&
+ (firstvertex.y == secondvertex.y));
lefttri.SetOrg(firstvertex);
lefttri.SetDest(secondvertex);
righttri.SetOrg(secondvertex);
@@ -615,7 +604,7 @@ namespace TriangleNet.Algorithm
HeapDelete(eventheap, heapsize, 0);
heapsize--;
check4events = true;
- if (nextevent.xkey < mesh.xmin)
+ if (nextevent.xkey < mesh.bounds.Xmin)
{
fliptri = nextevent.otriEvent;
fliptri.Oprev(ref farlefttri);
@@ -645,8 +634,8 @@ namespace TriangleNet.Algorithm
else
{
nextvertex = nextevent.vertexEvent;
- if ((nextvertex.pt.X == lastvertex.pt.X) &&
- (nextvertex.pt.Y == lastvertex.pt.Y))
+ if ((nextvertex.x == lastvertex.x) &&
+ (nextvertex.y == lastvertex.y))
{
if (Behavior.Verbose)
{
@@ -714,7 +703,7 @@ namespace TriangleNet.Algorithm
leftvertex = farlefttri.Apex();
midvertex = lefttri.Dest();
rightvertex = lefttri.Apex();
- lefttest = Primitives.CounterClockwise(leftvertex.pt, midvertex.pt, rightvertex.pt);
+ lefttest = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex);
if (lefttest > 0.0)
{
newevent = new SweepEvent();
@@ -729,7 +718,7 @@ namespace TriangleNet.Algorithm
leftvertex = righttri.Apex();
midvertex = righttri.Org();
rightvertex = farrighttri.Apex();
- righttest = Primitives.CounterClockwise(leftvertex.pt, midvertex.pt, rightvertex.pt);
+ righttest = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex);
if (righttest > 0.0)
{
newevent = new SweepEvent();
@@ -748,5 +737,66 @@ namespace TriangleNet.Algorithm
bottommost.LprevSelf();
return RemoveGhosts(ref bottommost);
}
+
+ #region Internal classes
+
+ ///
+ /// A node in a heap used to store events for the sweepline Delaunay algorithm.
+ ///
+ ///
+ /// Only used in the sweepline algorithm.
+ ///
+ /// Nodes do not point directly to their parents or children in the heap. Instead, each
+ /// node knows its position in the heap, and can look up its parent and children in a
+ /// separate array. To distinguish site events from circle events, all circle events are
+ /// given an invalid (smaller than 'xmin') x-coordinate 'xkey'.
+ ///
+ class SweepEvent
+ {
+ public double xkey, ykey; // Coordinates of the event.
+ public Vertex vertexEvent; // Vertex event.
+ public Otri otriEvent; // Circle event.
+ public int heapposition; // Marks this event's position in the heap.
+ }
+
+ ///
+ /// Introducing a new class which aggregates a sweep event is the easiest way
+ /// to handle the pointer magic of the original code (casting a sweep event
+ /// to vertex etc.).
+ ///
+ class SweepEventVertex : Vertex
+ {
+ public SweepEvent evt;
+
+ public SweepEventVertex(SweepEvent e)
+ {
+ evt = e;
+ }
+ }
+
+ ///
+ /// A node in the splay tree.
+ ///
+ ///
+ /// Only used in the sweepline algorithm.
+ ///
+ /// Each node holds an oriented ghost triangle that represents a boundary edge
+ /// of the growing triangulation. When a circle event covers two boundary edges
+ /// with a triangle, so that they are no longer boundary edges, those edges are
+ /// not immediately deleted from the tree; rather, they are lazily deleted when
+ /// they are next encountered. (Since only a random sample of boundary edges are
+ /// kept in the tree, lazy deletion is faster.) 'keydest' is used to verify that
+ /// a triangle is still the same as when it entered the splay tree; if it has
+ /// been rotated (due to a circle event), it no longer represents a boundary
+ /// edge and should be deleted.
+ ///
+ class SplayNode
+ {
+ public Otri keyedge; // Lprev of an edge on the front.
+ public Vertex keydest; // Used to verify that splay node is still live.
+ public SplayNode lchild, rchild; // Children in splay tree.
+ }
+
+ #endregion
}
}
diff --git a/Triangle.NET/Triangle/BadTriQueue.cs b/Triangle.NET/Triangle/BadTriQueue.cs
index f7fd187..ac98753 100644
--- a/Triangle.NET/Triangle/BadTriQueue.cs
+++ b/Triangle.NET/Triangle/BadTriQueue.cs
@@ -11,8 +11,13 @@ namespace TriangleNet
using TriangleNet.Data;
///
- /// TODO: Update summary.
+ /// A (priority) queue for bad triangles.
///
+ ///
+ // The queue is actually a set of 4096 queues. I use multiple queues to
+ // give priority to smaller angles. I originally implemented a heap, but
+ // the queues are faster by a larger margin than I'd suspected.
+ ///
class BadTriQueue
{
static readonly double SQRT2 = 1.4142135623730950488016887242096980785696718753769480732;
@@ -20,11 +25,10 @@ namespace TriangleNet
public int Count { get { return this.count; } }
// Variables that maintain the bad triangle queues. The queues are
- // ordered from 4095 (highest priority) to 0 (lowest priority).
-
- BadTriangle[] queuefront;//[4096];
- BadTriangle[] queuetail;//[4096];
- int[] nextnonemptyq;//[4096];
+ // ordered from 4095 (highest priority) to 0 (lowest priority).
+ BadTriangle[] queuefront;
+ BadTriangle[] queuetail;
+ int[] nextnonemptyq;
int firstnonemptyq;
int count;
@@ -42,17 +46,10 @@ namespace TriangleNet
count = 0;
}
- #region Queue
-
///
/// Add a bad triangle data structure to the end of a queue.
///
- ///
- ///
- // The queue is actually a set of 4096 queues. I use multiple queues to
- // give priority to smaller angles. I originally implemented a heap, but
- // the queues are faster by a larger margin than I'd suspected.
- ///
+ /// The bad triangle to enqueue.
public void Enqueue(BadTriangle badtri)
{
double length, multiplier;
@@ -154,9 +151,6 @@ namespace TriangleNet
///
///
///
- ///
- /// Allocates a badtriang data structure for the triangle, then passes it to enqueuebadtriang().
- ///
public void Enqueue(ref Otri enqtri, double minedge, Vertex enqapex, Vertex enqorg, Vertex enqdest)
{
// Allocate space for the bad triangle.
@@ -172,8 +166,6 @@ namespace TriangleNet
Vertex dest = enqtri.Dest();
Vertex apex = enqtri.Apex();
- //badtriangles.Add(newbad);
-
Enqueue(newbad);
}
@@ -183,8 +175,6 @@ namespace TriangleNet
///
public BadTriangle Dequeue()
{
- BadTriangle result;
-
// If no queues are nonempty, return NULL.
if (firstnonemptyq < 0)
{
@@ -194,18 +184,17 @@ namespace TriangleNet
this.count--;
// Find the first triangle of the highest-priority queue.
- result = queuefront[firstnonemptyq];
+ BadTriangle result = queuefront[firstnonemptyq];
// Remove the triangle from the queue.
queuefront[firstnonemptyq] = result.nexttriang;
// If this queue is now empty, note the new highest-priority
- // nonempty queue.
+ // nonempty queue.
if (result == queuetail[firstnonemptyq])
{
firstnonemptyq = nextnonemptyq[firstnonemptyq];
}
+
return result;
}
-
- #endregion
}
}
diff --git a/Triangle.NET/Triangle/Behavior.cs b/Triangle.NET/Triangle/Behavior.cs
index 7f0a13b..df358e5 100644
--- a/Triangle.NET/Triangle/Behavior.cs
+++ b/Triangle.NET/Triangle/Behavior.cs
@@ -15,32 +15,104 @@ namespace TriangleNet
///
static class Behavior
{
+ ///
+ /// Input is a Planar Straight Line Graph.
+ ///
public static bool Poly { get; set; }
+ ///
+ /// Quality mesh generation.
+ ///
public static bool Quality { get; set; }
+ ///
+ /// Apply a maximum triangle area constraint.
+ ///
public static bool VarArea { get; set; }
+ ///
+ /// Apply a maximum triangle area constraint.
+ ///
public static bool FixedArea { get; set; }
+ ///
+ /// Apply a user-defined triangle constraint.
+ ///
public static bool Usertest { get; set; }
+ ///
+ /// Apply attributes to identify triangles in certain regions.
+ ///
public static bool RegionAttrib { get; set; }
+ ///
+ /// Enclose the convex hull with segments.
+ ///
public static bool Convex { get; set; }
+ ///
+ /// Jettison unused vertices from output.
+ ///
public static bool Jettison { get; set; }
+ ///
+ /// Compute boundary information.
+ ///
public static bool UseBoundaryMarkers { get; set; }
+ ///
+ /// Ignores holes in polygons.
+ ///
public static bool NoHoles { get; set; }
+ ///
+ /// No exact arithmetic.
+ ///
public static bool NoExact { get; set; }
+ ///
+ /// Conforming Delaunay (all triangles are truly Delaunay).
+ ///
public static bool ConformDel { get; set; }
+ ///
+ /// Algorithm to use for triangulation.
+ ///
public static TriangulationAlgorithm Algorithm { get; set; }
+ ///
+ /// Log detailed information.
+ ///
public static bool Verbose { get; set; }
- public static bool UseSegments { get; set; }
+ ///
+ /// Use segments (should not be set manually)
+ ///
+ public static bool UseSegments { get; set; } // TODO: internal set
- public static int NoBisect { get; set; } // <- int
+ ///
+ /// Suppresses boundary segment splitting.
+ ///
+ public static int NoBisect { get; set; } // <- int !
+ ///
+ /// Use maximum number of added Steiner points.
+ ///
public static int Steiner { get; set; }
+ ///
+ /// Minimum angle constraint.
+ ///
public static double MinAngle { get; set; }
+ ///
+ /// (should not be set manually)
+ ///
public static double GoodAngle { get; set; }
+ ///
+ /// (should not be set manually)
+ ///
public static double Offconstant { get; set; }
+ ///
+ /// Maximum area constraint.
+ ///
public static double MaxArea { get; set; }
+ ///
+ /// Maximum angle constraint.
+ ///
public static double MaxAngle { get; set; }
+ ///
+ /// (should not be set manually)
+ ///
public static double MaxGoodAngle { get; set; }
+ ///
+ /// Load behavior defaults.
+ ///
public static void Init()
{
Poly = false;
diff --git a/Triangle.NET/Triangle/Carver.cs b/Triangle.NET/Triangle/Carver.cs
index e4505ed..5883194 100644
--- a/Triangle.NET/Triangle/Carver.cs
+++ b/Triangle.NET/Triangle/Carver.cs
@@ -9,6 +9,7 @@ namespace TriangleNet
{
using TriangleNet.Data;
using System;
+ using TriangleNet.Geometry;
using System.Collections.Generic;
///
@@ -18,6 +19,7 @@ namespace TriangleNet
{
Mesh mesh;
+
public Carver(Mesh mesh)
{
this.mesh = mesh;
@@ -28,7 +30,7 @@ namespace TriangleNet
/// protected by subsegments. Where there are subsegments, set boundary
/// markers as appropriate.
///
- void InfectHull()
+ private void InfectHull()
{
Otri hulltri = default(Otri);
Otri nexttri = default(Otri);
@@ -50,7 +52,7 @@ namespace TriangleNet
{
// Is the triangle protected by a subsegment?
hulltri.SegPivot(ref hullsubseg);
- if (hullsubseg.ss == Mesh.dummysub)
+ if (hullsubseg.seg == Mesh.dummysub)
{
// The triangle is not protected; infect it.
if (!hulltri.IsInfected())
@@ -62,9 +64,9 @@ namespace TriangleNet
else
{
// The triangle is protected; set boundary markers if appropriate.
- if (hullsubseg.ss.boundary == 0)
+ if (hullsubseg.seg.boundary == 0)
{
- hullsubseg.ss.boundary = 1;
+ hullsubseg.seg.boundary = 1;
horg = hulltri.Org();
hdest = hulltri.Dest();
if (horg.mark == 0)
@@ -86,6 +88,7 @@ namespace TriangleNet
nexttri.Copy(ref hulltri);
hulltri.Oprev(ref nexttri);
}
+
} while (!hulltri.Equal(starttri));
}
@@ -108,19 +111,19 @@ namespace TriangleNet
{
Otri testtri = default(Otri);
Otri neighbor = default(Otri);
- Triangle virusloop;
Osub neighborsubseg = default(Osub);
Vertex testvertex;
Vertex norg, ndest;
- //Vertex deadorg, deaddest, deadapex;
+
bool killorg;
// Loop through all the infected triangles, spreading the virus to
// their neighbors, then to their neighbors' neighbors.
for (int i = 0; i < mesh.viri.Count; i++)
- {
- virusloop = mesh.viri[i];
- testtri.triangle = virusloop;
+ {
+ // WARNING: Don't use foreach, mesh.viri list may get modified.
+
+ testtri.triangle = mesh.viri[i];
// A triangle is marked as infected by messing with one of its pointers
// to subsegments, setting it to an illegal value. Hence, we have to
// temporarily uninfect this triangle so that we can examine its
@@ -138,16 +141,16 @@ namespace TriangleNet
// Check if the neighbor is nonexistent or already infected.
if ((neighbor.triangle == Mesh.dummytri) || neighbor.IsInfected())
{
- if (neighborsubseg.ss != Mesh.dummysub)
+ if (neighborsubseg.seg != Mesh.dummysub)
{
// There is a subsegment separating the triangle from its
- // neighbor, but both triangles are dying, so the subsegment
- // dies too.
- mesh.SubsegDealloc(neighborsubseg.ss);
+ // neighbor, but both triangles are dying, so the subsegment
+ // dies too.
+ mesh.SubsegDealloc(neighborsubseg.seg);
if (neighbor.triangle != Mesh.dummytri)
{
// Make sure the subsegment doesn't get deallocated again
- // later when the infected neighbor is visited.
+ // later when the infected neighbor is visited.
neighbor.Uninfect();
neighbor.SegDissolve();
neighbor.Infect();
@@ -156,7 +159,7 @@ namespace TriangleNet
}
else
{ // The neighbor exists and is not infected.
- if (neighborsubseg.ss == Mesh.dummysub)
+ if (neighborsubseg.seg == Mesh.dummysub)
{
// There is no subsegment protecting the neighbor, so
// the neighbor becomes infected.
@@ -165,13 +168,14 @@ namespace TriangleNet
mesh.viri.Add(neighbor.triangle);
}
else
- { // The neighbor is protected by a subsegment.
+ {
+ // The neighbor is protected by a subsegment.
// Remove this triangle from the subsegment.
neighborsubseg.TriDissolve();
// The subsegment becomes a boundary. Set markers accordingly.
- if (neighborsubseg.ss.boundary == 0)
+ if (neighborsubseg.seg.boundary == 0)
{
- neighborsubseg.ss.boundary = 1;
+ neighborsubseg.seg.boundary = 1;
}
norg = neighbor.Org();
ndest = neighbor.Dest();
@@ -191,17 +195,16 @@ namespace TriangleNet
testtri.Infect();
}
- for (int i = 0; i < mesh.viri.Count; i++)
+ foreach (var virus in mesh.viri)
{
- virusloop = mesh.viri[i];
- testtri.triangle = virusloop;
+ testtri.triangle = virus;
// Check each of the three corners of the triangle for elimination.
// This is done by walking around each vertex, checking if it is
// still connected to at least one live triangle.
for (testtri.orient = 0; testtri.orient < 3; testtri.orient++)
{
- testvertex=testtri.Org();
+ testvertex = testtri.Org();
// Check if the vertex has already been tested.
if (testvertex != null)
{
@@ -266,7 +269,7 @@ namespace TriangleNet
if (neighbor.triangle == Mesh.dummytri)
{
// There is no neighboring triangle on this edge, so this edge
- // is a boundary edge. This triangle is being deleted, so this
+ // is a boundary edge. This triangle is being deleted, so this
// boundary edge is deleted.
mesh.hullsize--;
}
@@ -282,6 +285,7 @@ namespace TriangleNet
// Return the dead triangle to the pool of triangles.
mesh.TriangleDealloc(testtri.triangle);
}
+
// Empty the virus pool.
mesh.viri.Clear();
}
@@ -312,6 +316,8 @@ namespace TriangleNet
// neighbors.
for (int i = 0; i < mesh.viri.Count; i++)
{
+ // WARNING: Don't use foreach, mesh.viri list may get modified.
+
testtri.triangle = mesh.viri[i];
// A triangle is marked as infected by messing with one of its pointers
// to subsegments, setting it to an illegal value. Hence, we have to
@@ -340,7 +346,7 @@ namespace TriangleNet
// Make sure the neighbor exists, is not already infected, and
// isn't protected by a subsegment.
if ((neighbor.triangle != Mesh.dummytri) && !neighbor.IsInfected()
- && (neighborsubseg.ss == Mesh.dummysub))
+ && (neighborsubseg.seg == Mesh.dummysub))
{
// Infect the neighbor.
neighbor.Infect();
@@ -364,14 +370,10 @@ namespace TriangleNet
mesh.viri.Clear();
}
///
- /// Find the holes and infect them. Find the area constraints and infect
+ /// Find the holes and infect them. Find the area constraints and infect
/// them. Infect the convex hull. Spread the infection and kill triangles.
/// Spread the area constraints.
///
- ///
- ///
- ///
- ///
public void CarveHoles()
{
Otri searchtri = default(Otri);
@@ -379,8 +381,7 @@ namespace TriangleNet
Vertex searchorg, searchdest;
LocateResult intersect;
- int numRegions = mesh.regions.Count;
- Otri[] regiontris = (numRegions > 0) ? new Otri[numRegions] : null;
+ Otri[] regionTris = null;
if (!Behavior.Convex)
{
@@ -393,10 +394,9 @@ namespace TriangleNet
{
// Infect each triangle in which a hole lies.
foreach (var hole in mesh.holes)
- {
+ {
// Ignore holes that aren't within the bounds of the mesh.
- if ((hole.X >= mesh.xmin) && (hole.X <= mesh.xmax)
- && (hole.Y >= mesh.ymin) && (hole.Y <= mesh.ymax))
+ if (mesh.bounds.Contains(hole))
{
// Start searching from some triangle on the outer boundary.
searchtri.triangle = Mesh.dummytri;
@@ -407,7 +407,7 @@ namespace TriangleNet
// falls within the starting triangle.
searchorg = searchtri.Org();
searchdest = searchtri.Dest();
- if (Primitives.CounterClockwise(searchorg.pt, searchdest.pt, hole) > 0.0)
+ if (Primitives.CounterClockwise(searchorg, searchdest, hole) > 0.0)
{
// Find a triangle that contains the hole.
intersect = mesh.Locate(hole, ref searchtri);
@@ -427,17 +427,18 @@ namespace TriangleNet
// work when the triangulation is no longer convex. (Incidentally, this is the reason why
// regional attributes and area constraints can't be used when refining a preexisting mesh,
// which might not be convex; they can only be used with a freshly triangulated PSLG.)
- if (numRegions > 0)
+ if (mesh.regions.Count > 0)
{
+ regionTris = new Otri[mesh.regions.Count];
+
int i = 0;
// Find the starting triangle for each region.
foreach (var region in mesh.regions)
{
- regiontris[i].triangle = Mesh.dummytri;
+ regionTris[i].triangle = Mesh.dummytri;
// Ignore region points that aren't within the bounds of the mesh.
- if ((region.pt.X >= mesh.xmin) && (region.pt.X <= mesh.xmax) &&
- (region.pt.Y >= mesh.ymin) && (region.pt.Y <= mesh.ymax))
+ if (mesh.bounds.Contains(region.point))
{
// Start searching from some triangle on the outer boundary.
searchtri.triangle = Mesh.dummytri;
@@ -448,15 +449,15 @@ namespace TriangleNet
// region point falls within the starting triangle.
searchorg = searchtri.Org();
searchdest = searchtri.Dest();
- if (Primitives.CounterClockwise(searchorg.pt, searchdest.pt, region.pt) > 0.0)
+ if (Primitives.CounterClockwise(searchorg, searchdest, region.point) > 0.0)
{
// Find a triangle that contains the region point.
- intersect = mesh.Locate(region.pt, ref searchtri);
+ intersect = mesh.Locate(region.point, ref searchtri);
if ((intersect != LocateResult.Outside) && (!searchtri.IsInfected()))
{
// Record the triangle for processing after the
// holes have been carved.
- searchtri.Copy(ref regiontris[i]);
+ searchtri.Copy(ref regionTris[i]);
}
}
}
@@ -472,7 +473,7 @@ namespace TriangleNet
}
// The virus pool should be empty now.
- if (numRegions > 0)
+ if (regionTris != null)
{
if (Behavior.RegionAttrib)
{
@@ -489,19 +490,19 @@ namespace TriangleNet
}
}
- for (int i = 0; i < numRegions; i++)
+ for (int i = 0; i < regionTris.Length; i++)
{
- if (regiontris[i].triangle != Mesh.dummytri)
+ if (regionTris[i].triangle != Mesh.dummytri)
{
// Make sure the triangle under consideration still exists.
// It may have been eaten by the virus.
- if (!Otri.IsDead(regiontris[i].triangle))
+ if (!Otri.IsDead(regionTris[i].triangle))
{
// Put one triangle in the virus pool.
- regiontris[i].Infect();
- mesh.viri.Add(regiontris[i].triangle);
+ regionTris[i].Infect();
+ mesh.viri.Add(regionTris[i].triangle);
// Apply one region's attribute and/or area constraint.
- RegionPlague(mesh.regions[i].attribute, mesh.regions[i].area);
+ RegionPlague(mesh.regions[i].Attribute, mesh.regions[i].Area);
// The virus pool should be empty now.
}
}
@@ -514,16 +515,8 @@ namespace TriangleNet
}
}
- // Free up memory.
- if (((mesh.holes.Count > 0) && !Behavior.NoHoles) || !Behavior.Convex || (numRegions > 0))
- {
- mesh.viri.Clear();
- }
-
- if (numRegions > 0)
- {
- regiontris = null;
- }
+ // Free up memory (virus pool should be empty anyway).
+ mesh.viri.Clear();
}
}
}
diff --git a/Triangle.NET/Triangle/Data/BadSubseg.cs b/Triangle.NET/Triangle/Data/BadSubseg.cs
index 03a9347..d95d8b7 100644
--- a/Triangle.NET/Triangle/Data/BadSubseg.cs
+++ b/Triangle.NET/Triangle/Data/BadSubseg.cs
@@ -39,7 +39,7 @@ namespace TriangleNet.Data
public override string ToString()
{
- return String.Format("B-SID {0}", encsubseg.ss.Hash);
+ return String.Format("B-SID {0}", encsubseg.seg.hash);
}
};
}
diff --git a/Triangle.NET/Triangle/Data/BadTriangle.cs b/Triangle.NET/Triangle/Data/BadTriangle.cs
index d98bf34..bc68f1f 100644
--- a/Triangle.NET/Triangle/Data/BadTriangle.cs
+++ b/Triangle.NET/Triangle/Data/BadTriangle.cs
@@ -36,7 +36,7 @@ namespace TriangleNet.Data
}
public override string ToString()
{
- return String.Format("B-TID {0}", poortri.triangle.Hash);
+ return String.Format("B-TID {0}", poortri.triangle.hash);
}
}
}
diff --git a/Triangle.NET/Triangle/Data/FlipStacker.cs b/Triangle.NET/Triangle/Data/FlipStacker.cs
deleted file mode 100644
index 517ab5c..0000000
--- a/Triangle.NET/Triangle/Data/FlipStacker.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
-// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
-//
-// -----------------------------------------------------------------------
-
-namespace TriangleNet.Data
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- ///
- /// A stack of triangles flipped during the most recent vertex insertion.
- ///
- ///
- /// The stack is used to undo the vertex insertion if the vertex encroaches
- /// upon a subsegment.
- ///
- class FlipStacker
- {
- public Otri flippedtri; // A recently flipped triangle.
- public FlipStacker prevflip; // Previous flip in the stack.
- }
-}
diff --git a/Triangle.NET/Triangle/Data/Osub.cs b/Triangle.NET/Triangle/Data/Osub.cs
index ca2be29..4a7a334 100644
--- a/Triangle.NET/Triangle/Data/Osub.cs
+++ b/Triangle.NET/Triangle/Data/Osub.cs
@@ -23,16 +23,16 @@ namespace TriangleNet.Data
///
struct Osub
{
- public Subseg ss;
- public int ssorient; // Ranges from 0 to 1.
+ public Segment seg;
+ public int orient; // Ranges from 0 to 1.
public override string ToString()
{
- if (ss == null)
+ if (seg == null)
{
return "O-TID [null]";
}
- return String.Format("O-SID {0}", ss.Hash);
+ return String.Format("O-SID {0}", seg.hash);
}
#region Osub primitives
@@ -44,8 +44,8 @@ namespace TriangleNet.Data
///
public void Sym(ref Osub o2)
{
- o2.ss = ss;
- o2.ssorient = 1 - ssorient;
+ o2.seg = seg;
+ o2.orient = 1 - orient;
}
///
@@ -53,7 +53,7 @@ namespace TriangleNet.Data
///
public void SymSelf()
{
- ssorient = 1 - ssorient;
+ orient = 1 - orient;
}
///
@@ -64,7 +64,7 @@ namespace TriangleNet.Data
///
public void Pivot(ref Osub o2)
{
- o2 = ss.subsegs[ssorient];
+ o2 = seg.subsegs[orient];
//sdecode(sptr, o2);
}
@@ -73,7 +73,7 @@ namespace TriangleNet.Data
///
public void PivotSelf()
{
- this = ss.subsegs[ssorient];
+ this = seg.subsegs[orient];
//sdecode(sptr, osub);
}
@@ -85,7 +85,7 @@ namespace TriangleNet.Data
///
public void Next(ref Osub o2)
{
- o2 = ss.subsegs[1 - ssorient];
+ o2 = seg.subsegs[1 - orient];
//sdecode(sptr, o2);
}
@@ -94,7 +94,7 @@ namespace TriangleNet.Data
///
public void NextSelf()
{
- this = ss.subsegs[1 - ssorient];
+ this = seg.subsegs[1 - orient];
//sdecode(sptr, osub);
}
@@ -103,7 +103,7 @@ namespace TriangleNet.Data
///
public Vertex Org()
{
- return ss.vertices[ssorient];
+ return seg.vertices[orient];
}
///
@@ -111,7 +111,7 @@ namespace TriangleNet.Data
///
public Vertex Dest()
{
- return ss.vertices[1 - ssorient];
+ return seg.vertices[1 - orient];
}
///
@@ -119,7 +119,7 @@ namespace TriangleNet.Data
///
public void SetOrg(Vertex ptr)
{
- ss.vertices[ssorient] = ptr;
+ seg.vertices[orient] = ptr;
}
///
@@ -127,7 +127,7 @@ namespace TriangleNet.Data
///
public void SetDest(Vertex ptr)
{
- ss.vertices[1 - ssorient] = ptr;
+ seg.vertices[1 - orient] = ptr;
}
///
@@ -135,7 +135,7 @@ namespace TriangleNet.Data
///
public Vertex SegOrg()
{
- return ss.vertices[2 + ssorient];
+ return seg.vertices[2 + orient];
}
///
@@ -143,7 +143,7 @@ namespace TriangleNet.Data
///
public Vertex SegDest()
{
- return ss.vertices[3 - ssorient];
+ return seg.vertices[3 - orient];
}
///
@@ -151,7 +151,7 @@ namespace TriangleNet.Data
///
public void SetSegOrg(Vertex ptr)
{
- ss.vertices[2 + ssorient] = ptr;
+ seg.vertices[2 + orient] = ptr;
}
///
@@ -159,7 +159,7 @@ namespace TriangleNet.Data
///
public void SetSegDest(Vertex ptr)
{
- ss.vertices[3 - ssorient] = ptr;
+ seg.vertices[3 - orient] = ptr;
}
///
@@ -169,7 +169,7 @@ namespace TriangleNet.Data
/// setting boundary conditions in finite element solvers.
public int Mark()
{
- return ss.boundary;
+ return seg.boundary;
}
///
@@ -177,7 +177,7 @@ namespace TriangleNet.Data
///
public void SetMark(int value)
{
- ss.boundary = value;
+ seg.boundary = value;
}
///
@@ -185,8 +185,8 @@ namespace TriangleNet.Data
///
public void Bond(ref Osub o2)
{
- ss.subsegs[ssorient] = o2;
- o2.ss.subsegs[o2.ssorient] = this;
+ seg.subsegs[orient] = o2;
+ o2.seg.subsegs[o2.orient] = this;
}
///
@@ -196,7 +196,7 @@ namespace TriangleNet.Data
/// connected to this subsegment.
public void Dissolve()
{
- ss.subsegs[ssorient].ss = Mesh.dummysub;
+ seg.subsegs[orient].seg = Mesh.dummysub;
}
///
@@ -204,8 +204,8 @@ namespace TriangleNet.Data
///
public void Copy(ref Osub o2)
{
- o2.ss = ss;
- o2.ssorient = ssorient;
+ o2.seg = seg;
+ o2.orient = orient;
}
///
@@ -213,24 +213,24 @@ namespace TriangleNet.Data
///
public bool Equal(Osub o2)
{
- return ((ss == o2.ss) && (ssorient == o2.ssorient));
+ return ((seg == o2.seg) && (orient == o2.orient));
}
///
/// Check a subsegment's deallocation.
///
- public static bool IsDead(Subseg sub)
+ public static bool IsDead(Segment sub)
{
- return sub.subsegs[0].ss == null;
+ return sub.subsegs[0].seg == null;
}
///
/// Set a subsegment's deallocation.
///
- public static void Kill(Subseg sub)
+ public static void Kill(Segment sub)
{
- sub.subsegs[0].ss = null;
- sub.subsegs[1].ss = null;
+ sub.subsegs[0].seg = null;
+ sub.subsegs[1].seg = null;
}
///
@@ -238,7 +238,7 @@ namespace TriangleNet.Data
///
public void TriPivot(ref Otri ot)
{
- ot = ss.triangles[ssorient];
+ ot = seg.triangles[orient];
//decode(ptr, otri)
}
@@ -247,7 +247,7 @@ namespace TriangleNet.Data
///
public void TriDissolve()
{
- ss.triangles[ssorient].triangle = Mesh.dummytri;
+ seg.triangles[orient].triangle = Mesh.dummytri;
}
#endregion
diff --git a/Triangle.NET/Triangle/Data/Otri.cs b/Triangle.NET/Triangle/Data/Otri.cs
index bf661bb..339fc59 100644
--- a/Triangle.NET/Triangle/Data/Otri.cs
+++ b/Triangle.NET/Triangle/Data/Otri.cs
@@ -32,7 +32,7 @@ namespace TriangleNet.Data
{
return "O-TID [null]";
}
- return String.Format("O-TID {0}", triangle.Hash);
+ return String.Format("O-TID {0}", triangle.hash);
}
#region Otri primitives
@@ -372,8 +372,14 @@ namespace TriangleNet.Data
///
public void Bond(ref Otri o2)
{
- triangle.neighbors[orient] = o2;
- o2.triangle.neighbors[o2.orient] = this;
+ //triangle.neighbors[orient]= o2;
+ //o2.triangle.neighbors[o2.orient] = this;
+
+ triangle.neighbors[orient].triangle = o2.triangle;
+ triangle.neighbors[orient].orient = o2.orient;
+
+ o2.triangle.neighbors[o2.orient].triangle = this.triangle;
+ o2.triangle.neighbors[o2.orient].orient = this.orient;
}
///
@@ -462,7 +468,7 @@ namespace TriangleNet.Data
public void SegBond(ref Osub os)
{
triangle.subsegs[orient] = os;
- os.ss.triangles[os.ssorient] = this;
+ os.seg.triangles[os.orient] = this;
}
///
@@ -470,7 +476,7 @@ namespace TriangleNet.Data
///
public void SegDissolve()
{
- triangle.subsegs[orient].ss = Mesh.dummysub;
+ triangle.subsegs[orient].seg = Mesh.dummysub;
}
#endregion
diff --git a/Triangle.NET/Triangle/Data/Point2.cs b/Triangle.NET/Triangle/Data/Point2.cs
deleted file mode 100644
index afc6735..0000000
--- a/Triangle.NET/Triangle/Data/Point2.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
-// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
-//
-// -----------------------------------------------------------------------
-
-namespace TriangleNet.Data
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- ///
- /// Represents a 2D point.
- ///
- public struct Point2
- {
- public double X;
- public double Y;
-
- public Point2(double x, double y)
- {
- this.X = x;
- this.Y = y;
- }
-
- public bool Equals(Point2 p)
- {
- // Return true if the fields match:
- return (X == p.X) && (Y == p.Y);
- }
- }
-}
diff --git a/Triangle.NET/Triangle/Data/Region.cs b/Triangle.NET/Triangle/Data/Region.cs
deleted file mode 100644
index 053833b..0000000
--- a/Triangle.NET/Triangle/Data/Region.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
-// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
-//
-// -----------------------------------------------------------------------
-
-namespace TriangleNet.Data
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- ///
- /// TODO: Update summary.
- ///
- struct Region
- {
- internal Point2 pt;
- internal double attribute;
- internal double area;
-
- public Region(double[] region)
- {
- pt = new Point2(region[0], region[1]);
- attribute = region[2];
- area = region[3];
- }
- }
-}
diff --git a/Triangle.NET/Triangle/Data/Subseg.cs b/Triangle.NET/Triangle/Data/Segment.cs
similarity index 55%
rename from Triangle.NET/Triangle/Data/Subseg.cs
rename to Triangle.NET/Triangle/Data/Segment.cs
index 7551d54..108fb1d 100644
--- a/Triangle.NET/Triangle/Data/Subseg.cs
+++ b/Triangle.NET/Triangle/Data/Segment.cs
@@ -18,32 +18,25 @@ namespace TriangleNet.Data
///
/// Each subsegment contains two pointers to adjoining subsegments, plus
/// four pointers to vertices, plus two pointers to adjoining triangles,
- /// plus one boundary marker, plus one segment number.
+ /// plus one boundary marker.
///
- class Subseg
+ public class Segment
{
- // Start at -1, so dummysub has that ID
- private static int hashSeed = -1;
- internal int Hash;
+ // Hash for dictionary. Will be set by mesh instance.
+ internal int hash;
- // The ID is only used for mesh output.
- //public int ID;
+ internal Osub[] subsegs;
+ internal Vertex[] vertices;
+ internal Otri[] triangles;
+ internal int boundary;
- public Osub[] subsegs;
- public Vertex[] vertices;
- public Otri[] triangles;
- public int boundary;
- //public int segment;
-
- public Subseg()
+ public Segment()
{
- Hash = hashSeed++;
-
// Initialize the two adjoining subsegments to be the omnipresent
- // subsegment.
+ // subsegment.
subsegs = new Osub[2];
- subsegs[0].ss = Mesh.dummysub;
- subsegs[1].ss = Mesh.dummysub;
+ subsegs[0].seg = Mesh.dummysub;
+ subsegs[1].seg = Mesh.dummysub;
// Four NULL vertices.
vertices = new Vertex[4];
@@ -57,29 +50,42 @@ namespace TriangleNet.Data
boundary = 0;
}
+ #region Public properties
+
///
- /// Reset the hash seed.
+ /// Gets the first endpoints vertex id.
///
- /// The new has seed value.
- /// Reset value will usally 0, if a new triangulation starts,
- /// or the number of subsegments, if refinement is done.
- internal static void ResetHashSeed(int value)
+ public int P0
{
- if (value < 0)
- {
- throw new ArgumentException("A hash seed must be non negative.");
- }
- hashSeed = value;
+ get { return this.vertices[0].id; }
}
+ ///
+ /// Gets the seconds endpoints vertex id.
+ ///
+ public int P1
+ {
+ get { return this.vertices[1].id; }
+ }
+
+ ///
+ /// Gets the segment boundary mark.
+ ///
+ public int Boundary
+ {
+ get { return this.boundary; }
+ }
+
+ #endregion
+
public override int GetHashCode()
{
- return this.Hash;
+ return this.hash;
}
public override string ToString()
{
- return String.Format("SID {0}", Hash);
+ return String.Format("SID {0}", hash);
}
}
}
diff --git a/Triangle.NET/Triangle/Data/SplayNode.cs b/Triangle.NET/Triangle/Data/SplayNode.cs
deleted file mode 100644
index b04080f..0000000
--- a/Triangle.NET/Triangle/Data/SplayNode.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
-// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
-//
-// -----------------------------------------------------------------------
-
-namespace TriangleNet.Data
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- ///
- /// A node in the splay tree.
- ///
- ///
- /// Only used in the sweepline algorithm.
- ///
- /// Each node holds an oriented ghost triangle that represents a boundary edge
- /// of the growing triangulation. When a circle event covers two boundary edges
- /// with a triangle, so that they are no longer boundary edges, those edges are
- /// not immediately deleted from the tree; rather, they are lazily deleted when
- /// they are next encountered. (Since only a random sample of boundary edges are
- /// kept in the tree, lazy deletion is faster.) 'keydest' is used to verify that
- /// a triangle is still the same as when it entered the splay tree; if it has
- /// been rotated (due to a circle event), it no longer represents a boundary
- /// edge and should be deleted.
- ///
- class SplayNode
- {
- public Otri keyedge; // Lprev of an edge on the front.
- public Vertex keydest; // Used to verify that splay node is still live.
- public SplayNode lchild, rchild; // Children in splay tree.
- }
-}
diff --git a/Triangle.NET/Triangle/Data/SweepEvent.cs b/Triangle.NET/Triangle/Data/SweepEvent.cs
deleted file mode 100644
index 17f37ef..0000000
--- a/Triangle.NET/Triangle/Data/SweepEvent.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
-// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
-//
-// -----------------------------------------------------------------------
-
-namespace TriangleNet.Data
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- ///
- /// A node in a heap used to store events for the sweepline Delaunay algorithm.
- ///
- ///
- /// Only used in the sweepline algorithm.
- ///
- /// Nodes do not point directly to their parents or children in the heap. Instead, each
- /// node knows its position in the heap, and can look up its parent and children in a
- /// separate array. To distinguish site events from circle events, all circle events are
- /// given an invalid (smaller than 'xmin') x-coordinate 'xkey'.
- ///
- class SweepEvent
- {
- public double xkey, ykey; // Coordinates of the event.
- public Vertex vertexEvent; // Vertex event.
- public Otri otriEvent; // Circle event.
- public int heapposition; // Marks this event's position in the heap.
- }
-}
diff --git a/Triangle.NET/Triangle/Data/Triangle.cs b/Triangle.NET/Triangle/Data/Triangle.cs
index 6d18a05..4143590 100644
--- a/Triangle.NET/Triangle/Data/Triangle.cs
+++ b/Triangle.NET/Triangle/Data/Triangle.cs
@@ -11,28 +11,24 @@ namespace TriangleNet.Data
using System.Collections.Generic;
using System.Linq;
using System.Text;
+ using TriangleNet.Geometry;
///
/// The triangle data structure.
///
///
- /// Each triangle contains three pointers to
- /// adjoining triangles, plus three pointers to vertices, plus three
- /// pointers to subsegments (declared below; these pointers are usually
- /// 'dummysub'). It may or may not also contain user-defined attributes
- /// and/or a floating-point "area constraint." It may also contain extra
- /// pointers for nodes, when the user asks for high-order elements.
- /// Because the size and structure of a 'triangle' is not decided until
- /// runtime, I haven't simply declared the type 'triangle' as a struct.
+ /// Each triangle contains three pointers to adjoining triangles, plus three
+ /// pointers to vertices, plus three pointers to subsegments (declared below;
+ /// these pointers are usually 'dummysub'). It may or may not also contain
+ /// user-defined attributes and/or a floating-point "area constraint".
///
- class Triangle
+ public class Triangle : ITriangle
{
- // Start at -1, so dummytri has that ID
- private static int hashSeed = -1;
- internal int Hash;
+ // Hash for dictionary. Will be set by mesh instance.
+ internal int hash;
// The ID is only used for mesh output.
- internal int ID;
+ internal int id;
internal Otri[] neighbors;
internal Vertex[] vertices;
@@ -43,9 +39,6 @@ namespace TriangleNet.Data
public Triangle(int numAttributes)
{
- this.Hash = hashSeed++;
- this.ID = this.Hash;
-
// Initialize the three adjoining triangles to be "outer space".
neighbors = new Otri[3];
neighbors[0].triangle = Mesh.dummytri;
@@ -54,15 +47,15 @@ namespace TriangleNet.Data
// Three NULL vertices.
vertices = new Vertex[3];
-
+
if (Behavior.UseSegments)
{
// Initialize the three adjoining subsegments to be the
// omnipresent subsegment.
subsegs = new Osub[3];
- subsegs[0].ss = Mesh.dummysub;
- subsegs[1].ss = Mesh.dummysub;
- subsegs[2].ss = Mesh.dummysub;
+ subsegs[0].seg = Mesh.dummysub;
+ subsegs[1].seg = Mesh.dummysub;
+ subsegs[2].seg = Mesh.dummysub;
}
if (numAttributes > 0)
@@ -76,29 +69,104 @@ namespace TriangleNet.Data
}
}
+
+ #region Public properties
+
///
- /// Reset the hash seed.
+ /// Gets the triangle id.
///
- /// The new has seed value.
- /// Reset value will usally 0, if a new triangulation starts,
- /// or the number of triangles, if refinement is done.
- internal static void ResetHashSeed(int value)
+ public int ID
{
- if (value < 0)
- {
- throw new ArgumentException("A hash seed must be non negative.");
- }
- hashSeed = value;
+ get { return this.id; }
}
+ ///
+ /// Gets the first corners vertex id.
+ ///
+ public int P0
+ {
+ get { return this.vertices[0] == null ? -1 : this.vertices[0].id; }
+ }
+
+ ///
+ /// Gets the seconds corners vertex id.
+ ///
+ public int P1
+ {
+ get { return this.vertices[1] == null ? -1 : this.vertices[1].id; }
+ }
+
+ ///
+ /// Gets the specified corners vertex id.
+ ///
+ public int this[int index]
+ {
+ get { return this.vertices[index] == null ? -1 : this.vertices[index].id; }
+ }
+
+ ///
+ /// Gets the third corners vertex id.
+ ///
+ public int P2
+ {
+ get { return this.vertices[2] == null ? -1 : this.vertices[2].id; }
+ }
+
+ public bool SupportsNeighbors
+ {
+ get { return true; }
+ }
+
+ ///
+ /// Gets the first neighbors id.
+ ///
+ public int N0
+ {
+ get { return this.neighbors[0].triangle.id; }
+ }
+
+ ///
+ /// Gets the second neighbors id.
+ ///
+ public int N1
+ {
+ get { return this.neighbors[1].triangle.id; }
+ }
+
+ ///
+ /// Gets the third neighbors id.
+ ///
+ public int N2
+ {
+ get { return this.neighbors[2].triangle.id; }
+ }
+
+ ///
+ /// Gets the triangle area constraint.
+ ///
+ public double Area
+ {
+ get { return this.area; }
+ }
+
+ ///
+ /// Gets the triangle attributes.
+ ///
+ public double[] Attributes
+ {
+ get { return this.attributes; }
+ }
+
+ #endregion
+
public override int GetHashCode()
{
- return this.Hash;
+ return this.hash;
}
public override string ToString()
{
- return String.Format("TID {0}", Hash);
+ return String.Format("TID {0}", hash);
}
}
}
diff --git a/Triangle.NET/Triangle/Data/Vertex.cs b/Triangle.NET/Triangle/Data/Vertex.cs
index 83223ba..c933fd8 100644
--- a/Triangle.NET/Triangle/Data/Vertex.cs
+++ b/Triangle.NET/Triangle/Data/Vertex.cs
@@ -11,43 +11,52 @@ namespace TriangleNet.Data
using System.Collections.Generic;
using System.Linq;
using System.Text;
-
+ using TriangleNet.Geometry;
///
/// The vertex data structure.
///
- ///
- /// Each vertex is actually an array of doubles. An integer boundary marker,
- /// and sometimes a to a triangle, is appended after the doubles.
- ///
- class Vertex : IComparable, IEquatable
+ public class Vertex : Point
{
- private static int hashSeed = 0;
- internal int Hash;
+ // Hash for dictionary. Will be set by mesh instance.
+ internal int hash;
// The ID is only used for mesh output.
- internal int ID;
+ internal int id;
- internal Point2 pt;
- internal int mark;
internal VertexType type;
internal Otri tri;
- internal double[] attributes;
public Vertex()
- : this(0)
+ : this(0, 0, 0)
{ }
- public Vertex(int numAttributes)
- {
- this.Hash = hashSeed++;
-
- pt = default(Point2);
+ public Vertex(double x, double y)
+ : this(x, y, 0)
+ { }
- if (numAttributes > 0)
- {
- attributes = new double[numAttributes];
- }
+ public Vertex(double x, double y, int mark)
+ : base(x, y, mark)
+ {
+ this.type = VertexType.InputVertex;
+ }
+
+ #region Public properties
+
+ ///
+ /// Gets the vertex id.
+ ///
+ public int ID
+ {
+ get { return this.id; }
+ }
+
+ ///
+ /// Gets the vertex type.
+ ///
+ public VertexType Type
+ {
+ get { return this.type; }
}
///
@@ -61,110 +70,23 @@ namespace TriangleNet.Data
{
if (i == 0)
{
- return pt.X;
+ return x;
}
if (i == 1)
{
- return pt.Y;
+ return y;
}
throw new ArgumentOutOfRangeException("Index must be 0 or 1.");
}
}
- ///
- /// Reset the hash seed.
- ///
- /// The new has seed value.
- /// Reset value will usally 0, if a new triangulation starts,
- /// or the number of points, if refinement is done.
- internal static void ResetHashSeed(int value)
- {
- if (value < 0)
- {
- throw new ArgumentException("A hash seed must be non negative.");
- }
- hashSeed = value;
- }
-
- #region Operator overloading / overriding Equals
-
- // Compare "Guidelines for Overriding Equals() and Operator =="
- // http://msdn.microsoft.com/en-us/library/ms173147.aspx
-
- public static bool operator ==(Vertex a, Vertex b)
- {
- // If both are null, or both are same instance, return true.
- if (Object.ReferenceEquals(a, b))
- {
- return true;
- }
-
- // If one is null, but not both, return false.
- if (((object)a == null) || ((object)b == null))
- {
- return false;
- }
-
- return a.Equals(b);
- }
-
- public static bool operator !=(Vertex a, Vertex b)
- {
- return !(a == b);
- }
-
- public override bool Equals(object obj)
- {
- // If parameter is null return false.
- if (obj == null)
- {
- return false;
- }
-
- Vertex v = obj as Vertex;
-
- if ((object)v == null)
- {
- return false;
- }
-
- return this.pt.Equals(v.pt);
- }
-
- public bool Equals(Vertex v)
- {
- // If vertex is null return false.
- if ((object)v == null)
- {
- return false;
- }
-
- // Return true if the fields match:
- return this.pt.Equals(v.pt);
- }
+ #endregion
public override int GetHashCode()
{
- return this.Hash;
- }
-
- #endregion
-
- public override string ToString()
- {
- return String.Format("[{0},{1}]", pt.X, pt.Y);
- }
-
- public int CompareTo(Vertex other)
- {
- if (pt.X == other.pt.X && pt.Y == other.pt.Y)
- {
- return 0;
- }
-
- return (pt.X < other.pt.X || (pt.X == other.pt.X && pt.Y < other.pt.Y)) ? -1 : 1;
+ return this.hash;
}
}
}
diff --git a/Triangle.NET/Triangle/Enums.cs b/Triangle.NET/Triangle/Enums.cs
index cef6836..da37e44 100644
--- a/Triangle.NET/Triangle/Enums.cs
+++ b/Triangle.NET/Triangle/Enums.cs
@@ -90,5 +90,5 @@ namespace TriangleNet
///
/// The type of the mesh vertex.
///
- enum VertexType { InputVertex, SegmentVertex, FreeVertex, DeadVertex, UndeadVertex };
+ public enum VertexType { InputVertex, SegmentVertex, FreeVertex, DeadVertex, UndeadVertex };
}
diff --git a/Triangle.NET/Triangle/Geometry/EdgeEnumerator.cs b/Triangle.NET/Triangle/Geometry/EdgeEnumerator.cs
new file mode 100644
index 0000000..581abaf
--- /dev/null
+++ b/Triangle.NET/Triangle/Geometry/EdgeEnumerator.cs
@@ -0,0 +1,99 @@
+// -----------------------------------------------------------------------
+//
+// TODO: Update copyright text.
+//
+// -----------------------------------------------------------------------
+
+namespace TriangleNet.Geometry
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using TriangleNet.Data;
+
+ ///
+ /// Enumerates the edges of a triangulation.
+ ///
+ public class EdgeEnumerator : IEnumerator
+ {
+ IEnumerator triangles;
+ Otri tri = default(Otri);
+ Otri neighbor = default(Otri);
+ Edge current;
+ Vertex p1, p2;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public EdgeEnumerator(Mesh mesh)
+ {
+ triangles = mesh.triangles.Values.GetEnumerator();
+ triangles.MoveNext();
+
+ tri.triangle = triangles.Current;
+ tri.orient = 0;
+ }
+
+ public Edge Current
+ {
+ get { return current; }
+ }
+
+ public void Dispose()
+ {
+ this.triangles.Dispose();
+ }
+
+ object System.Collections.IEnumerator.Current
+ {
+ get { return current; }
+ }
+
+ public bool MoveNext()
+ {
+ if (tri.triangle == null)
+ {
+ return false;
+ }
+
+ current = null;
+
+ while (current == null)
+ {
+ if (tri.orient == 3)
+ {
+ if (triangles.MoveNext())
+ {
+ tri.triangle = triangles.Current;
+ tri.orient = 0;
+ }
+ else
+ {
+ // Finally no more triangles
+ return false;
+ }
+ }
+
+ tri.Sym(ref neighbor);
+
+ if ((tri.triangle.id < neighbor.triangle.id) || (neighbor.triangle == Mesh.dummytri))
+ {
+ p1 = tri.Org();
+ p2 = tri.Dest();
+
+ current = new Edge(p1.id, p2.id);
+ }
+
+ tri.orient++;
+ }
+
+ return true;
+ }
+
+ public void Reset()
+ {
+ this.triangles.Reset();
+ }
+ }
+}
diff --git a/Triangle.NET/Triangle/Geometry/InputGeometry.cs b/Triangle.NET/Triangle/Geometry/InputGeometry.cs
index a503376..e306329 100644
--- a/Triangle.NET/Triangle/Geometry/InputGeometry.cs
+++ b/Triangle.NET/Triangle/Geometry/InputGeometry.cs
@@ -75,7 +75,7 @@ namespace TriangleNet.Geometry
///
public IEnumerable Points
{
- get { return null; }
+ get { return points; }
}
///
@@ -131,7 +131,7 @@ namespace TriangleNet.Geometry
/// Boundary marker.
public void AddPoint(double x, double y, int boundary)
{
- //points.Add(new Vertex(x, y, boundary));
+ points.Add(new Vertex(x, y, boundary));
bounds.Update(x, y);
}
@@ -176,7 +176,7 @@ namespace TriangleNet.Geometry
/// Segment marker.
public void AddSegment(int p0, int p1, int boundary)
{
- if (p0 == p1)
+ if (p0 == p1 || p0 < 0 || p1 < 0)
{
throw new NotSupportedException("Invalid endpoints.");
}
diff --git a/Triangle.NET/Triangle/IO/DataReader.cs b/Triangle.NET/Triangle/IO/DataReader.cs
index c153375..d58db40 100644
--- a/Triangle.NET/Triangle/IO/DataReader.cs
+++ b/Triangle.NET/Triangle/IO/DataReader.cs
@@ -14,6 +14,7 @@ namespace TriangleNet.IO
using System.Globalization;
using TriangleNet.Data;
using TriangleNet.Log;
+ using TriangleNet.Geometry;
///
/// TODO: Update summary.
@@ -47,9 +48,9 @@ namespace TriangleNet.IO
/// the corresponding pointer is adjusted to refer to a subsegment rather
/// than the next triangle of the stack.
///
- public static int Reconstruct(Mesh mesh, MeshData input)
+ public static int Reconstruct(Mesh mesh, InputGeometry input, ITriangle[] triangles)
{
- long hullsize = 0;
+ int hullsize = 0;
Otri tri = default(Otri);
Otri triangleleft = default(Otri);
@@ -66,18 +67,17 @@ namespace TriangleNet.IO
Vertex segmentorg, segmentdest;
int[] corner = new int[3];
int[] end = new int[2];
- bool segmentmarkers = false;
+ //bool segmentmarkers = false;
int boundmarker;
int aroundvertex;
bool notfound;
int i = 0;
- int elements = input.Triangles == null ? 0 : input.Triangles.Length;
- int attribs = input.TriangleAttributes == null ? 0 : input.TriangleAttributes.Length;
- int numberofsegments = input.Segments == null ? 0 : input.Segments.Length;
+ int elements = triangles == null ? 0 : triangles.Length;
+ int numberofsegments = input.segments.Count;
mesh.inelements = elements;
- mesh.eextras = attribs;
+ mesh.eextras = mesh.inelements > 0 ? triangles[0].Attributes.Length : 0;
// Create the triangles.
for (i = 0; i < mesh.inelements; i++)
@@ -90,7 +90,6 @@ namespace TriangleNet.IO
if (Behavior.Poly)
{
mesh.insegments = numberofsegments;
- segmentmarkers = input.SegmentMarkers != null;
// Create the subsegments.
for (i = 0; i < mesh.insegments; i++)
@@ -115,7 +114,7 @@ namespace TriangleNet.IO
}
i = 0;
- string debug = "";
+
// Read the triangles from the .ele file, and link
// together those that share an edge.
foreach (var item in mesh.triangles.Values)
@@ -125,7 +124,7 @@ namespace TriangleNet.IO
// Copy the triangle's three corners.
for (int j = 0; j < 3; j++)
{
- corner[j] = input.Triangles[i][j];
+ corner[j] = triangles[i][j];
if ((corner[j] < 0) || (corner[j] >= mesh.invertices))
{
SimpleLog.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()");
@@ -134,15 +133,12 @@ namespace TriangleNet.IO
}
// Read the triangle's attributes.
- for (int j = 0; j < mesh.eextras; j++)
- {
- tri.triangle.attributes[j] = input.TriangleAttributes[i][j];
- }
+ tri.triangle.attributes = triangles[i].Attributes;
// TODO
if (Behavior.VarArea)
{
- tri.triangle.area = input.TriangleAreas[i];
+ tri.triangle.area = triangles[i].Area;
}
// Set the triangle's vertices.
@@ -151,8 +147,6 @@ namespace TriangleNet.IO
tri.SetDest(mesh.vertices[corner[1]]);
tri.SetApex(mesh.vertices[corner[2]]);
- debug += String.Format("Checking element {0} [{1}, {2}, {3}]\n", i, corner[0], corner[1], corner[2]);
-
// Try linking the triangle to others that share these vertices.
for (tri.orient = 0; tri.orient < 3; tri.orient++)
{
@@ -168,35 +162,25 @@ namespace TriangleNet.IO
checktri = nexttri;
- debug += String.Format(" {0}: aroundvertex = {1}\n", tri.orient, aroundvertex);
if (checktri.triangle != Mesh.dummytri)
{
tdest = tri.Dest();
tapex = tri.Apex();
- debug += String.Format(" No dummy: tdest ({0}, {1}), tapex ({2}, {3})\n",
- tdest[0], tdest[1], tapex[0], tapex[1]);
// Look for other triangles that share an edge.
do
{
checkdest = checktri.Dest();
checkapex = checktri.Apex();
- debug += String.Format(" checktri.orient {0}\n", checktri.orient);
-
- debug += String.Format(" checkdest ({0}, {1}), checkapex ({2}, {3})\n",
- checkdest[0], checkdest[1], checkapex[0], checkapex[1]);
-
if (tapex == checkdest)
{
- debug += String.Format(" > tapex == checkdest\n");
// The two triangles share an edge; bond them together.
tri.Lprev(ref triangleleft);
triangleleft.Bond(ref checktri);
}
if (tdest == checkapex)
{
- debug += String.Format(" > tdest == checkapex\n");
// The two triangles share an edge; bond them together.
checktri.Lprev(ref checkleft);
tri.Bond(ref checkleft);
@@ -223,14 +207,11 @@ namespace TriangleNet.IO
i = 0;
foreach (var item in mesh.subsegs.Values)
{
- subseg.ss = item;
+ subseg.seg = item;
- end[0] = input.Segments[i][0];
- end[1] = input.Segments[i][1];
- if (segmentmarkers)
- {
- boundmarker = input.SegmentMarkers[i];
- }
+ end[0] = input.segments[i].P0;
+ end[1] = input.segments[i].P1;
+ boundmarker = input.segments[i].Boundary;
for (int j = 0; j < 2; j++)
{
@@ -241,22 +222,20 @@ namespace TriangleNet.IO
}
}
- debug += String.Format("Checking segment {0} [{1}, {2}]\n", i, end[0], end[1]);
// set the subsegment's vertices.
- subseg.ssorient = 0;
+ subseg.orient = 0;
segmentorg = mesh.vertices[end[0]];
segmentdest = mesh.vertices[end[1]];
subseg.SetOrg(segmentorg);
subseg.SetDest(segmentdest);
subseg.SetSegOrg(segmentorg);
subseg.SetSegDest(segmentdest);
- subseg.ss.boundary = boundmarker;
+ subseg.seg.boundary = boundmarker;
// Try linking the subsegment to triangles that share these vertices.
- for (subseg.ssorient = 0; subseg.ssorient < 2; subseg.ssorient++)
+ for (subseg.orient = 0; subseg.orient < 2; subseg.orient++)
{
// Take the number for the destination of subsegloop.
- aroundvertex = end[1 - subseg.ssorient];
- debug += String.Format(" {0}: aroundvertex = {1}\n", subseg.ssorient, aroundvertex);
+ aroundvertex = end[1 - subseg.orient];
int index = vertexarray[aroundvertex].Count - 1;
// Look for triangles having this vertex.
prevlink = vertexarray[aroundvertex][index];
@@ -275,12 +254,9 @@ namespace TriangleNet.IO
while (notfound && (checktri.triangle != Mesh.dummytri))
{
checkdest = checktri.Dest();
- debug += String.Format(" No dummy: shorg ({0}, {1}), checkdest ({2}, {3})\n",
- shorg[0], shorg[1], checkdest[0], checkdest[1]);
-
+
if (shorg == checkdest)
{
- debug +=" shorg == checkdest\n";
// We have a match. Remove this triangle from the list.
//prevlink = vertexarray[aroundvertex][index];
vertexarray[aroundvertex].Remove(prevlink);
@@ -290,7 +266,6 @@ namespace TriangleNet.IO
checktri.Sym(ref checkneighbor);
if (checkneighbor.triangle == Mesh.dummytri)
{
- debug +=" checkneighbor.tri == m->dummytri\n";
// The next line doesn't insert a subsegment (because there's
// already one there), but it sets the boundary markers of
// the existing subsegment and its vertices.
@@ -312,7 +287,6 @@ namespace TriangleNet.IO
}
}
- debug += "\nMark the remaining edges\n\n";
// Mark the remaining edges as not being attached to any subsegment.
// Also, count the (yet uncounted) boundary edges.
for (i = 0; i < mesh.vertices.Count; i++)
@@ -324,7 +298,6 @@ namespace TriangleNet.IO
while (checktri.triangle != Mesh.dummytri)
{
- debug += " checktri.triangle != Mesh.dummytri\n";
// Find the next triangle in the stack before this
// information gets overwritten.
index--;
@@ -336,16 +309,13 @@ namespace TriangleNet.IO
{
mesh.InsertSubseg(ref checktri, 1);
hullsize++;
- debug += "checkneighbor.triangle == Mesh.dummytri (hullsize = " + hullsize + ")\n";
}
checktri = nexttri;
}
}
- debug += "\nmesh.subsegs.Count = " + mesh.subsegs.Count;
-
- return (int)hullsize;
+ return hullsize;
}
#endregion
diff --git a/Triangle.NET/Triangle/IO/DataWriter.cs b/Triangle.NET/Triangle/IO/DataWriter.cs
index 6b28a7b..1d5dcca 100644
--- a/Triangle.NET/Triangle/IO/DataWriter.cs
+++ b/Triangle.NET/Triangle/IO/DataWriter.cs
@@ -12,286 +12,15 @@ namespace TriangleNet.IO
using System.Collections.Generic;
using System.Globalization;
using TriangleNet.Data;
+ using TriangleNet.Geometry;
///
/// Generates a mesh representaion using arrays.
///
public static class DataWriter
{
- static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
-
- static int verticesCount;
- static int elementsCount;
-
#region Library
- ///
- /// Number the vertices and write them to raw output data.
- ///
- ///
- ///
- public static void WriteNodes(Mesh mesh, MeshData data)
- {
- Vertex vertex;
- int outvertices = mesh.vertices.Count;
-
- if (Behavior.Jettison)
- {
- outvertices = mesh.vertices.Count - mesh.undeads;
- }
-
- verticesCount = outvertices;
-
- // Allocate memory for output vertices if necessary.
- data.Points = new double[outvertices][];
-
- // Allocate memory for output vertex attributes if necessary.
- if (mesh.nextras > 0)
- {
- data.PointAttributes = new double[outvertices][];
- }
- // Allocate memory for output vertex markers if necessary.
- if (Behavior.UseBoundaryMarkers)
- {
- data.PointMarkers = new int[outvertices];
- }
-
- int i = 0;
- foreach (var item in mesh.vertices.Values)
- {
- vertex = item;
-
- if (!Behavior.Jettison || vertex.type != VertexType.UndeadVertex)
- {
- // X and y coordinates.
- data.Points[i] = new double[] { vertex.pt.X, vertex.pt.Y };
-
- // Vertex attributes.
- if (data.PointAttributes != null)
- {
- data.PointAttributes[i] = vertex.attributes;
- }
-
- if (Behavior.UseBoundaryMarkers)
- {
- // Save the boundary marker.
- data.PointMarkers[i] = vertex.mark;
- }
-
- // Assign array index to vertex ID for later use.
- vertex.ID = i++;
- }
- }
- }
-
- ///
- /// Write the triangles to raw output data.
- ///
- ///
- ///
- public static void WriteElements(Mesh mesh, MeshData data)
- {
- Otri tri = default(Otri);
- Vertex p1, p2, p3;
-
- elementsCount = mesh.triangles.Count;
-
- // Allocate memory for output triangles if necessary.
- data.Triangles = new int[elementsCount][];
-
- // Allocate memory for output triangle attributes if necessary.
- if (mesh.eextras > 0)
- {
- data.TriangleAttributes = new double[mesh.triangles.Count][];
- }
-
- tri.orient = 0;
-
- int i = 0;
- foreach (var item in mesh.triangles.Values)
- {
- tri.triangle = item;
-
- p1 = tri.Org();
- p2 = tri.Dest();
- p3 = tri.Apex();
-
- // Triangle order is always 1 (no higher order elements supported)
- data.Triangles[i] = new int[] { p1.ID, p2.ID, p3.ID };
-
- if (data.TriangleAttributes != null)
- {
- data.TriangleAttributes[i] = tri.triangle.attributes;
- }
-
- // Update ID for later use
- item.ID = i++;
- }
- }
-
- ///
- /// Write the segments and holes to raw output data.
- ///
- ///
- ///
- public static void WritePoly(Mesh mesh, MeshData data)
- {
- Osub subseg = default(Osub);
- Vertex pt1, pt2;
- int n = mesh.subsegs.Count;
-
- // Allocate memory for output segments if necessary.
- data.Segments = new int[n][];
-
- // Allocate memory for output segment markers if necessary.
- if (Behavior.UseBoundaryMarkers)
- {
- data.SegmentMarkers = new int[n];
- }
-
- subseg.ssorient = 0;
-
- int i = 0;
- foreach (var item in mesh.subsegs.Values)
- {
- subseg.ss = item;
-
- pt1 = subseg.Org();
- pt2 = subseg.Dest();
-
- // Copy indices of the segment's two endpoints.
- data.Segments[i] = new int[] { pt1.ID, pt2.ID };
-
- // Copy the boundary marker.
- if (Behavior.UseBoundaryMarkers)
- {
- data.SegmentMarkers[i] = subseg.ss.boundary;
- }
-
- i++;
- }
-
- n = mesh.holes.Count;
-
- if (n > 0)
- {
- data.Holes = new double[n][];
-
- i = 0;
- foreach (var hole in mesh.holes)
- {
- data.Holes[i] = new double[] { hole.X, hole.Y };
- i++;
- }
- }
- }
-
- ///
- /// Write the edges to raw output data.
- ///
- ///
- ///
- public static void WriteEdges(Mesh mesh, MeshData data)
- {
- Otri tri = default(Otri), trisym = default(Otri);
- Osub checkmark = default(Osub);
- Vertex p1, p2;
-
- // Allocate memory for edges if necessary.
- data.Edges = new int[mesh.edges][];
-
- // Allocate memory for edge markers if necessary.
- if (Behavior.UseBoundaryMarkers)
- {
- data.EdgeMarkers = new int[mesh.edges];
- }
-
- int index = 0;
- // To loop over the set of edges, loop over all triangles, and look at
- // the three edges of each triangle. If there isn't another triangle
- // adjacent 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 pointer than its neighbor. This way, each edge is
- // considered only once.
- foreach (var item in mesh.triangles.Values)
- {
- tri.triangle = item;
-
- for (tri.orient = 0; tri.orient < 3; tri.orient++)
- {
- tri.Sym(ref trisym);
- if ((tri.triangle.ID < trisym.triangle.ID) || (trisym.triangle == Mesh.dummytri))
- {
- p1 = tri.Org();
- p2 = tri.Dest();
-
- data.Edges[index] = new int[] { p1.ID, p2.ID };
- if (Behavior.UseBoundaryMarkers)
- {
- // Edge number, indices of two endpoints, and a boundary marker.
- // If there's no subsegment, the boundary marker is zero.
- if (Behavior.UseSegments)
- {
- tri.SegPivot(ref checkmark);
- if (checkmark.ss == Mesh.dummysub)
- {
- data.EdgeMarkers[index] = 0;
- }
- else
- {
- data.EdgeMarkers[index] = checkmark.ss.boundary;
- }
- }
- else
- {
- data.EdgeMarkers[index] = (trisym.triangle == Mesh.dummytri ? 1 : 0);
- }
- }
- index++;
- }
- }
- }
- }
-
- ///
- /// Write the triangle neighbors to raw output data.
- ///
- ///
- ///
- /// WARNING: Be sure WriteElements has been called before,
- /// so the elements are numbered right!
- public static void WriteNeighbors(Mesh mesh, MeshData data)
- {
- Otri tri = default(Otri), trisym = default(Otri);
-
- // Allocate memory for neighbors if necessary.
- data.Neighbors = new int[mesh.triangles.Count][];
-
- Mesh.dummytri.ID = -1;
-
- int i = 0;
- foreach (var item in mesh.triangles.Values)
- {
- data.Neighbors[i] = new int[3];
-
- tri.triangle = item;
-
- tri.orient = 1;
- tri.Sym(ref trisym);
- data.Neighbors[i][0] = trisym.triangle.ID;
-
- tri.orient = 2;
- tri.Sym(ref trisym);
- data.Neighbors[i][1] = trisym.triangle.ID;
-
- tri.orient = 0;
- tri.Sym(ref trisym);
- data.Neighbors[i][2] = trisym.triangle.ID;
-
- i++;
- }
- }
-
///
/// Gets the Voronoi diagram as raw output data.
///
@@ -312,31 +41,31 @@ namespace TriangleNet.IO
Otri tri = default(Otri), trisym = default(Otri);
Vertex torg, tdest, tapex;
- Point2 circumcenter;
+ Point circumcenter;
double xi = 0, eta = 0;
int p1, p2;
int i = 0;
// Copy input points (actually not part of the voronoi diagram)
- data.InputPoints = new double[mesh.vertices.Count][];
+ data.InputPoints = new Vertex[mesh.vertices.Count];
foreach (var item in mesh.vertices.Values)
{
if (item.type != VertexType.UndeadVertex)
{
- data.InputPoints[i] = new double[] { item.pt.X, item.pt.Y };
+ data.InputPoints[i] = item;
i++;
}
}
// Allocate memory for Voronoi vertices.
- data.Points = new double[mesh.triangles.Count][];
+ data.Points = new Vertex[mesh.triangles.Count];
int index = 0;
tri.orient = 0;
-
+
i = 0;
foreach (var item in mesh.triangles.Values)
{
@@ -344,17 +73,17 @@ namespace TriangleNet.IO
torg = tri.Org();
tdest = tri.Dest();
tapex = tri.Apex();
- circumcenter = Primitives.FindCircumcenter(torg.pt, tdest.pt, tapex.pt, ref xi, ref eta, false);
+ circumcenter = Primitives.FindCircumcenter(torg, tdest, tapex, ref xi, ref eta, false);
// X and y coordinates.
- data.Points[i] = new double[] { circumcenter.X, circumcenter.Y };
+ data.Points[i] = new Point(circumcenter.x, circumcenter.y);
// Update element id
- tri.triangle.ID = i++;
+ tri.triangle.id = i++;
}
// Allocate memory for output Voronoi edges.
- data.Edges = new int[mesh.edges][];
+ data.Edges = new Edge[mesh.edges];
// Allocate memory for output Voronoi norms.
data.Directions = new double[mesh.edges][];
@@ -373,10 +102,10 @@ namespace TriangleNet.IO
for (tri.orient = 0; tri.orient < 3; tri.orient++)
{
tri.Sym(ref trisym);
- if ((tri.triangle.ID < trisym.triangle.ID) || (trisym.triangle == Mesh.dummytri))
+ if ((tri.triangle.id < trisym.triangle.id) || (trisym.triangle == Mesh.dummytri))
{
// Find the number of this triangle (and Voronoi vertex).
- p1 = tri.triangle.ID;
+ p1 = tri.triangle.id;
if (trisym.triangle == Mesh.dummytri)
{
@@ -384,16 +113,16 @@ namespace TriangleNet.IO
tdest = tri.Dest();
// Copy an infinite ray. Index of one endpoint, and -1.
- data.Edges[index] = new int[] { p1, -1};
+ data.Edges[index] = new Edge(p1, -1);
data.Directions[index] = new double[] { tdest[1] - torg[1], torg[0] - tdest[0] };
}
else
{
// Find the number of the adjacent triangle (and Voronoi vertex).
- p2 = trisym.triangle.ID;
+ p2 = trisym.triangle.id;
// Finite edge. Write indices of two endpoints.
- data.Edges[index] = new int[] { p1, p2 };
+ data.Edges[index] = new Edge(p1, p2);
data.Directions[index] = new double[] { 0, 0 };
}
diff --git a/Triangle.NET/Triangle/IO/DebugWriter.cs b/Triangle.NET/Triangle/IO/DebugWriter.cs
new file mode 100644
index 0000000..9b3bde5
--- /dev/null
+++ b/Triangle.NET/Triangle/IO/DebugWriter.cs
@@ -0,0 +1,164 @@
+// -----------------------------------------------------------------------
+//
+// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
+//
+// -----------------------------------------------------------------------
+
+namespace TriangleNet.IO
+{
+ using System;
+ using System.IO;
+ using System.Globalization;
+ using TriangleNet.Data;
+
+ ///
+ /// Writes a the current mesh into a text file.
+ ///
+ ///
+ /// File format:
+ ///
+ /// num_nodes
+ /// nid_1 nx ny mark
+ /// ...
+ /// nid_n nx ny mark
+ ///
+ /// num_segs
+ /// sid_1 p1 p2 mark
+ /// ...
+ /// sid_n p1 p2 mark
+ ///
+ /// num_tris
+ /// tid_1 p1 p2 p3 n1 n2 n3
+ /// ...
+ /// tid_n p1 p2 p3 n1 n2 n3
+ ///
+ class DebugWriter
+ {
+ static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
+
+ Mesh mesh;
+ int iteration;
+ string name;
+
+ public DebugWriter(Mesh mesh)
+ {
+ this.mesh = mesh;
+
+ this.iteration = 0;
+ this.name = "debug-{0}.mesh";
+ }
+
+ ///
+ /// Start a new session with given name.
+ ///
+ /// Name of the session (and output files).
+ public void NewSession(string name)
+ {
+ this.iteration = 0;
+ this.name = name + "-{0}.mesh";
+ }
+
+ ///
+ /// Write complete mesh to a .mesh file.
+ ///
+ public void Write()
+ {
+ Vertex p1, p2, p3;
+
+ string file = String.Format(name, iteration++);
+
+ using (StreamWriter writer = new StreamWriter(file))
+ {
+ // Number of vertices.
+ writer.WriteLine("{0}", mesh.vertices.Count);
+
+ foreach (var v in mesh.vertices.Values)
+ {
+ // Vertex number, x and y coordinates and marker.
+ writer.WriteLine("{0} {1} {2} {3}", v.hash, v.x.ToString(nfi), v.y.ToString(nfi), v.mark);
+ }
+
+ // Number of segments.
+ writer.WriteLine("{0}", mesh.subsegs.Count);
+
+ Osub subseg = default(Osub);
+ subseg.orient = 0;
+
+ foreach (var item in mesh.subsegs.Values)
+ {
+ if (item.hash <= 0)
+ {
+ continue;
+ }
+
+ subseg.seg = item;
+
+ p1 = subseg.Org();
+ p2 = subseg.Dest();
+
+ // Segment number, indices of its two endpoints, and marker.
+ writer.WriteLine("{0} {1} {2} {3}", subseg.seg.hash, p1.hash, p2.hash, subseg.seg.boundary);
+ }
+
+ Otri tri = default(Otri), trisym = default(Otri);
+ tri.orient = 0;
+
+ int n1, n2, n3, hash3;
+
+ // Number of triangles.
+ writer.WriteLine("{0}", mesh.triangles.Count);
+
+ foreach (var item in mesh.triangles.Values)
+ {
+ if (item.hash <= 0)
+ {
+ continue;
+ }
+
+ tri.triangle = item;
+
+ p1 = tri.Org();
+ p2 = tri.Dest();
+ p3 = tri.Apex();
+
+ if (p3 == null)
+ {
+ if (p1 == null || p2 == null)
+ {
+ continue;
+ }
+
+ hash3 = -1;
+ }
+ else
+ {
+ hash3 = p3.hash;
+ }
+
+ if (p1 == null || p2 == null)
+ {
+ continue;
+ }
+
+ // Triangle number, indices for three vertices.
+ writer.Write("{0} {1} {2} {3}", tri.triangle.hash, p1.hash, p2.hash, hash3);
+
+ tri.orient = 1;
+ tri.Sym(ref trisym);
+ n1 = trisym.triangle.hash;
+
+ tri.orient = 2;
+ tri.Sym(ref trisym);
+ n2 = trisym.triangle.hash;
+
+ tri.orient = 0;
+ tri.Sym(ref trisym);
+ n3 = trisym.triangle.hash;
+
+ // Neighboring triangle numbers.
+ writer.WriteLine(" {0} {1} {2}", n1, n2, n3);
+ }
+ }
+ }
+ }
+}
diff --git a/Triangle.NET/Triangle/IO/FileReader.cs b/Triangle.NET/Triangle/IO/FileReader.cs
index 4b8104c..18b7bc4 100644
--- a/Triangle.NET/Triangle/IO/FileReader.cs
+++ b/Triangle.NET/Triangle/IO/FileReader.cs
@@ -12,6 +12,8 @@ namespace TriangleNet.IO
using System.Globalization;
using TriangleNet.Data;
using TriangleNet.Log;
+ using TriangleNet.Geometry;
+ using System.Collections.Generic;
///
/// Helper for reading Triangle files.
@@ -26,7 +28,7 @@ namespace TriangleNet.IO
///
/// The file to read.
/// Will NOT read associated files by default.
- public static MeshData ReadFile(string filename)
+ public static InputGeometry ReadFile(string filename)
{
return ReadFile(filename, false);
}
@@ -36,7 +38,7 @@ namespace TriangleNet.IO
///
/// The file to read.
/// Read associated files (ele, area, neigh).
- public static MeshData ReadFile(string filename, bool readsupp)
+ public static InputGeometry ReadFile(string filename, bool readsupp)
{
string ext = Path.GetExtension(filename);
@@ -78,33 +80,36 @@ namespace TriangleNet.IO
return true;
}
- static void ReadVertex(MeshData data, int index, string[] line)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Number of point attributes
+ static void ReadVertex(InputGeometry data, int index, string[] line, int n)
{
- int n = data.PointAttributes == null ? 0 : data.PointAttributes.Length;
-
- data.Points[index] = new double[] {
- double.Parse(line[1], nfi),
- double.Parse(line[2], nfi) };
+ double x = double.Parse(line[1], nfi);
+ double y = double.Parse(line[2], nfi);
+ int mark = 0;
// Read the vertex attributes.
for (int j = 0; j < n; j++)
{
- data.PointAttributes[index] = new double[n];
-
if (line.Length > 3 + j)
{
- data.PointAttributes[index][j] = double.Parse(line[3 + j]);
+ // TODO:
+ //vertex.attributes[j] = double.Parse(line[3 + j]);
}
}
- if (data.PointMarkers != null)
+ // Read a vertex marker.
+ if (line.Length > 3 + n)
{
- // Read a vertex marker.
- if (line.Length > 3 + n)
- {
- data.PointMarkers[index] = int.Parse(line[3 + n]);
- }
+ mark = int.Parse(line[3 + n]);
}
+
+ data.AddPoint(x, y, mark);
}
///
@@ -112,7 +117,7 @@ namespace TriangleNet.IO
///
///
/// Will NOT read associated .ele by default.
- public static MeshData ReadNodeFile(string nodefilename)
+ public static InputGeometry ReadNodeFile(string nodefilename)
{
return ReadNodeFile(nodefilename, false);
}
@@ -122,9 +127,9 @@ namespace TriangleNet.IO
///
///
///
- public static MeshData ReadNodeFile(string nodefilename, bool readElements)
+ public static InputGeometry ReadNodeFile(string nodefilename, bool readElements)
{
- MeshData data = new MeshData();
+ InputGeometry data;
startIndex = 0;
@@ -165,21 +170,11 @@ namespace TriangleNet.IO
nodemarkers = int.Parse(line[3]);
}
+ data = new InputGeometry(invertices);
+
// Read the vertices.
if (invertices > 0)
{
- data.Points = new double[invertices][];
-
- if (attributes > 0)
- {
- data.PointAttributes = new double[invertices][];
- }
-
- if (nodemarkers > 0)
- {
- data.PointMarkers = new int[invertices];
- }
-
for (int i = 0; i < invertices; i++)
{
if (!TryReadLine(reader, out line))
@@ -197,7 +192,7 @@ namespace TriangleNet.IO
startIndex = int.Parse(line[0], nfi);
}
- ReadVertex(data, i, line);
+ ReadVertex(data, i, line, attributes);
}
}
}
@@ -208,7 +203,7 @@ namespace TriangleNet.IO
string elefile = Path.ChangeExtension(nodefilename, ".ele");
if (File.Exists(elefile))
{
- ReadEleFile(elefile, data, true);
+ ReadEleFile(elefile, true);
}
}
@@ -220,7 +215,7 @@ namespace TriangleNet.IO
///
///
/// Will NOT read associated .ele by default.
- public static MeshData ReadPolyFile(string polyfilename)
+ public static InputGeometry ReadPolyFile(string polyfilename)
{
return ReadPolyFile(polyfilename, false, false);
}
@@ -231,7 +226,7 @@ namespace TriangleNet.IO
///
/// If true, look for an associated .ele file.
/// Will NOT read associated .area by default.
- public static MeshData ReadPolyFile(string polyfilename, bool readElements)
+ public static InputGeometry ReadPolyFile(string polyfilename, bool readElements)
{
return ReadPolyFile(polyfilename, readElements, false);
}
@@ -242,10 +237,10 @@ namespace TriangleNet.IO
///
/// If true, look for an associated .ele file.
/// If true, look for an associated .area file.
- public static MeshData ReadPolyFile(string polyfilename, bool readElements, bool readArea)
+ public static InputGeometry ReadPolyFile(string polyfilename, bool readElements, bool readArea)
{
// Read poly file
- MeshData data;
+ InputGeometry data;
startIndex = 0;
@@ -284,19 +279,7 @@ namespace TriangleNet.IO
// Read the vertices.
if (invertices > 0)
{
- data = new MeshData();
-
- data.Points = new double[invertices][];
-
- if (attributes > 0)
- {
- data.PointAttributes = new double[invertices][];
- }
-
- if (nodemarkers > 0)
- {
- data.PointMarkers = new int[invertices];
- }
+ data = new InputGeometry(invertices);
for (int i = 0; i < invertices; i++)
{
@@ -316,7 +299,7 @@ namespace TriangleNet.IO
startIndex = int.Parse(line[0], nfi);
}
- ReadVertex(data, i, line);
+ ReadVertex(data, i, line, attributes);
}
}
else
@@ -325,7 +308,7 @@ namespace TriangleNet.IO
// the vertices should be read from a separate .node file.
string nodefile = Path.ChangeExtension(polyfilename, ".node");
data = ReadNodeFile(nodefile);
- invertices = data.Points.Length;
+ invertices = data.Count;
}
if (data.Points == null)
@@ -349,17 +332,7 @@ namespace TriangleNet.IO
segmentmarkers = int.Parse(line[1]);
}
- if (insegments > 0)
- {
- data.Segments = new int[insegments][];
- }
-
- if (segmentmarkers > 0)
- {
- data.SegmentMarkers = new int[insegments];
- }
-
- int end1, end2;
+ int end1, end2, mark;
// Read and insert the segments.
for (int i = 0; i < insegments; i++)
{
@@ -376,24 +349,18 @@ namespace TriangleNet.IO
// TODO: startIndex ok?
end1 = int.Parse(line[1]) - startIndex;
end2 = int.Parse(line[2]) - startIndex;
+ mark = 0;
- if (segmentmarkers > 0)
+ if (segmentmarkers > 0 && line.Length > 3)
{
- if (line.Length > 3)
- {
- data.SegmentMarkers[i] = int.Parse(line[3]);
- }
- else
- {
- data.SegmentMarkers[i] = 0;
- }
+ mark = int.Parse(line[3]);
}
if ((end1 < 0) || (end1 >= invertices))
{
if (Behavior.Verbose)
{
- SimpleLog.Instance.Warning("Invalid first endpoint of segment.",
+ SimpleLog.Instance.Warning("Invalid first endpoint of segment.",
"MeshReader.ReadPolyfile()");
}
}
@@ -401,13 +368,13 @@ namespace TriangleNet.IO
{
if (Behavior.Verbose)
{
- SimpleLog.Instance.Warning("Invalid second endpoint of segment.",
+ SimpleLog.Instance.Warning("Invalid second endpoint of segment.",
"MeshReader.ReadPolyfile()");
}
}
else
{
- data.Segments[i] = new int[] { end1, end2 };
+ data.AddSegment(end1, end2, mark);
}
}
@@ -422,8 +389,6 @@ namespace TriangleNet.IO
int holes = int.Parse(line[0]);
if (holes > 0)
{
- data.Holes = new double[holes][];
-
for (int i = 0; i < holes; i++)
{
if (!TryReadLine(reader, out line))
@@ -436,9 +401,8 @@ namespace TriangleNet.IO
throw new Exception("Invalid hole.");
}
- data.Holes[i] = new double[] {
- double.Parse(line[1], nfi),
- double.Parse(line[2], nfi) };
+ data.AddHole(double.Parse(line[1], nfi),
+ double.Parse(line[2], nfi));
}
}
@@ -449,8 +413,6 @@ namespace TriangleNet.IO
if (regions > 0)
{
- data.Regions = new double[regions][];
-
for (int i = 0; i < regions; i++)
{
if (!TryReadLine(reader, out line))
@@ -463,14 +425,14 @@ namespace TriangleNet.IO
throw new Exception("Invalid region.");
}
- data.Regions[i] = new double[] {
+ data.AddRegion(
// Region x and y
double.Parse(line[1]),
double.Parse(line[2]),
// Region attribute
double.Parse(line[3]),
// Region area constraint
- double.Parse(line[4]) };
+ double.Parse(line[4]));
}
}
}
@@ -482,20 +444,16 @@ namespace TriangleNet.IO
string elefile = Path.ChangeExtension(polyfilename, ".ele");
if (File.Exists(elefile))
{
- ReadEleFile(elefile, data, readArea);
+ ReadEleFile(elefile, readArea);
}
}
return data;
}
- public static MeshData ReadEleFile(string elefilename)
+ public static List ReadEleFile(string elefilename)
{
- MeshData data = new MeshData();
-
- ReadEleFile(elefilename, data, false);
-
- return data;
+ return ReadEleFile(elefilename, false);
}
///
@@ -504,10 +462,12 @@ namespace TriangleNet.IO
///
///
///
- private static void ReadEleFile(string elefilename, MeshData data, bool readArea)
+ private static List ReadEleFile(string elefilename, bool readArea)
{
int intriangles = 0, attributes = 0;
+ List triangles;
+
using (StreamReader reader = new StreamReader(elefilename))
{
// Read number of elements and number of attributes.
@@ -527,12 +487,9 @@ namespace TriangleNet.IO
attributes = int.Parse(line[2]);
}
- data.Triangles = new int[intriangles][];
+ triangles = new List(intriangles);
- if (attributes > 0)
- {
- data.TriangleAttributes = new double[intriangles][];
- }
+ InputTriangle tri;
// Read triangles.
for (int i = 0; i < intriangles; i++)
@@ -548,24 +505,26 @@ namespace TriangleNet.IO
}
// TODO: startIndex ok?
- data.Triangles[i] = new int[] {
+ tri = new InputTriangle(
int.Parse(line[1]) - startIndex,
int.Parse(line[2]) - startIndex,
- int.Parse(line[3]) - startIndex };
+ int.Parse(line[3]) - startIndex);
// Read triangle attributes
if (attributes > 0)
{
for (int j = 0; j < attributes; j++)
{
- data.TriangleAttributes[i] = new double[attributes];
+ tri.attributes = new double[attributes];
if (line.Length > 4 + j)
{
- data.TriangleAttributes[i][j] = double.Parse(line[4 + j]);
+ tri.attributes[j] = double.Parse(line[4 + j]);
}
}
}
+
+ triangles.Add(tri);
}
}
@@ -575,9 +534,11 @@ namespace TriangleNet.IO
string areafile = Path.ChangeExtension(elefilename, ".area");
if (File.Exists(areafile))
{
- ReadAreaFile(areafile, intriangles, data);
+ ReadAreaFile(areafile, intriangles);
}
}
+
+ return triangles;
}
///
@@ -586,8 +547,10 @@ namespace TriangleNet.IO
///
///
///
- private static void ReadAreaFile(string areafilename, int intriangles, MeshData data)
+ private static double[] ReadAreaFile(string areafilename, int intriangles)
{
+ double[] data = null;
+
using (StreamReader reader = new StreamReader(areafilename))
{
string[] line;
@@ -599,12 +562,12 @@ namespace TriangleNet.IO
if (int.Parse(line[0]) != intriangles)
{
- SimpleLog.Instance.Warning("Number of area constraints doesn't match number of triangles.",
+ SimpleLog.Instance.Warning("Number of area constraints doesn't match number of triangles.",
"ReadAreaFile()");
- return;
+ return null;
}
- data.TriangleAreas = new double[intriangles];
+ data = new double[intriangles];
// Read area constraints.
for (int i = 0; i < intriangles; i++)
@@ -619,15 +582,17 @@ namespace TriangleNet.IO
throw new Exception("Triangle has no nodes.");
}
- data.TriangleAreas[i] = double.Parse(line[1], nfi);
+ data[i] = double.Parse(line[1], nfi);
}
}
+
+ return data;
}
- public static MeshData ReadEdgeFile(string edgeFile)
+ public static List ReadEdgeFile(string edgeFile, int invertices)
{
// Read poly file
- MeshData data = new MeshData();
+ List data = null;
startIndex = 0;
@@ -653,15 +618,10 @@ namespace TriangleNet.IO
if (inedges > 0)
{
- data.Edges = new int[inedges][];
+ data = new List(inedges);
}
- if (edgemarkers > 0)
- {
- data.EdgeMarkers = new int[inedges];
- }
-
- int end1, end2;
+ int end1, end2, mark;
// Read and insert the segments.
for (int i = 0; i < inedges; i++)
{
@@ -678,41 +638,33 @@ namespace TriangleNet.IO
// TODO: startIndex ok?
end1 = int.Parse(line[1]) - startIndex;
end2 = int.Parse(line[2]) - startIndex;
+ mark = 0;
- if (edgemarkers > 0)
+ if (edgemarkers > 0 && line.Length > 3)
{
- if (line.Length > 3)
- {
- data.SegmentMarkers[i] = int.Parse(line[3]);
- }
- else
- {
- data.SegmentMarkers[i] = 0;
- }
+ mark = int.Parse(line[3]);
}
- data.Segments[i] = new int[] { end1, end2 };
-
- //if ((end1 < 0) || (end1 >= invertices))
- //{
- // if (Behavior.Verbose)
- // {
- // SimpleLogger.Instance.Warning("Invalid first endpoint of segment.",
- // "MeshReader.ReadPolyfile()");
- // }
- //}
- //else if ((end2 < 0) || (end2 >= invertices))
- //{
- // if (Behavior.Verbose)
- // {
- // SimpleLogger.Instance.Warning("Invalid second endpoint of segment.",
- // "MeshReader.ReadPolyfile()");
- // }
- //}
- //else
- //{
- // data.Segments[i] = new int[] { end1, end2 };
- //}
+ if ((end1 < 0) || (end1 >= invertices))
+ {
+ if (Behavior.Verbose)
+ {
+ SimpleLog.Instance.Warning("Invalid first endpoint of segment.",
+ "MeshReader.ReadPolyfile()");
+ }
+ }
+ else if ((end2 < 0) || (end2 >= invertices))
+ {
+ if (Behavior.Verbose)
+ {
+ SimpleLog.Instance.Warning("Invalid second endpoint of segment.",
+ "MeshReader.ReadPolyfile()");
+ }
+ }
+ else
+ {
+ data.Add(new Edge(end1, end2, mark));
+ }
}
}
diff --git a/Triangle.NET/Triangle/IO/FileWriter.cs b/Triangle.NET/Triangle/IO/FileWriter.cs
index 2d0a527..e2420ee 100644
--- a/Triangle.NET/Triangle/IO/FileWriter.cs
+++ b/Triangle.NET/Triangle/IO/FileWriter.cs
@@ -11,6 +11,7 @@ namespace TriangleNet.IO
using System.IO;
using System.Globalization;
using TriangleNet.Data;
+ using TriangleNet.Geometry;
///
/// TODO: Update summary.
@@ -67,7 +68,7 @@ namespace TriangleNet.IO
if (!Behavior.Jettison || vertex.type != VertexType.UndeadVertex)
{
// Vertex number, x and y coordinates.
- writer.Write("{0} {1} {2}", index, vertex.pt.X.ToString(nfi), vertex.pt.Y.ToString(nfi));
+ writer.Write("{0} {1} {2}", index, vertex.x.ToString(nfi), vertex.y.ToString(nfi));
// Write attributes.
for (int j = 0; j < mesh.nextras; j++)
@@ -84,7 +85,7 @@ namespace TriangleNet.IO
writer.WriteLine();
// Assign array index to vertex ID for later use.
- vertex.ID = index++;
+ vertex.id = index++;
}
}
}
@@ -118,7 +119,7 @@ namespace TriangleNet.IO
p3 = tri.Apex();
// Triangle number, indices for three vertices.
- writer.Write("{0} {1} {2} {3}", j, p1.ID, p2.ID, p3.ID);
+ writer.Write("{0} {1} {2} {3}", j, p1.id, p2.id, p3.id);
for (int i = 0; i < mesh.eextras; i++)
{
@@ -128,7 +129,7 @@ namespace TriangleNet.IO
writer.WriteLine();
// Number elements
- item.ID = j++;
+ item.id = j++;
}
}
}
@@ -177,12 +178,12 @@ namespace TriangleNet.IO
writer.WriteLine("{0} {1}", mesh.subsegs.Count,
Behavior.UseBoundaryMarkers ? "1" : "0");
- subseg.ssorient = 0;
+ subseg.orient = 0;
int j = 0;
foreach (var item in mesh.subsegs.Values)
{
- subseg.ss = item;
+ subseg.seg = item;
pt1 = subseg.Org();
pt2 = subseg.Dest();
@@ -190,11 +191,11 @@ namespace TriangleNet.IO
// Segment number, indices of its two endpoints, and possibly a marker.
if (Behavior.UseBoundaryMarkers)
{
- writer.WriteLine("{0} {1} {2} {3}", j, pt1.ID, pt2.ID, subseg.ss.boundary);
+ writer.WriteLine("{0} {1} {2} {3}", j, pt1.id, pt2.id, subseg.seg.boundary);
}
else
{
- writer.WriteLine("{0} {1} {2}", j, pt1.ID, pt2.ID);
+ writer.WriteLine("{0} {1} {2}", j, pt1.id, pt2.id);
}
j++;
@@ -214,8 +215,8 @@ namespace TriangleNet.IO
writer.WriteLine("{0}", mesh.regions.Count);
foreach (var region in mesh.regions)
{
- writer.WriteLine("{0} {1} {2} {3} {4}", j, region.pt.X.ToString(nfi),
- region.pt.Y.ToString(nfi), region.attribute.ToString(nfi),
+ writer.WriteLine("{0} {1} {2} {3} {4}", j, region.point.X.ToString(nfi),
+ region.point.Y.ToString(nfi), region.attribute.ToString(nfi),
region.area.ToString(nfi));
j++;
@@ -254,7 +255,7 @@ namespace TriangleNet.IO
for (tri.orient = 0; tri.orient < 3; tri.orient++)
{
tri.Sym(ref trisym);
- if ((tri.triangle.ID < trisym.triangle.ID) || (trisym.triangle == Mesh.dummytri))
+ if ((tri.triangle.id < trisym.triangle.id) || (trisym.triangle == Mesh.dummytri))
{
p1 = tri.Org();
p2 = tri.Dest();
@@ -267,26 +268,26 @@ namespace TriangleNet.IO
{
tri.SegPivot(ref checkmark);
- if (checkmark.ss == Mesh.dummysub)
+ if (checkmark.seg == Mesh.dummysub)
{
- writer.WriteLine("{0} {1} {2} {3}", index, p1.ID, p2.ID, 0);
+ writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id, 0);
}
else
{
- writer.WriteLine("{0} {1} {2} {3}", index, p1.ID, p2.ID,
- checkmark.ss.boundary);
+ writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
+ checkmark.seg.boundary);
}
}
else
{
- writer.WriteLine("{0} {1} {2} {3}", index, p1.ID, p2.ID,
+ writer.WriteLine("{0} {1} {2} {3}", index, p1.id, p2.id,
trisym.triangle == Mesh.dummytri ? "1" : "0");
}
}
else
{
// Edge number, indices of two endpoints.
- writer.WriteLine("{0} {1} {2}", index, p1.ID, p2.ID);
+ writer.WriteLine("{0} {1} {2}", index, p1.id, p2.id);
}
index++;
@@ -314,7 +315,7 @@ namespace TriangleNet.IO
// Number of triangles, three neighbors per triangle.
writer.WriteLine("{0} 3", mesh.triangles.Count);
- Mesh.dummytri.ID = -1;
+ Mesh.dummytri.id = -1;
foreach (var item in mesh.triangles.Values)
{
@@ -322,15 +323,15 @@ namespace TriangleNet.IO
tri.orient = 1;
tri.Sym(ref trisym);
- n1 = trisym.triangle.ID;
+ n1 = trisym.triangle.id;
tri.orient = 2;
tri.Sym(ref trisym);
- n2 = trisym.triangle.ID;
+ n2 = trisym.triangle.id;
tri.orient = 0;
tri.Sym(ref trisym);
- n3 = trisym.triangle.ID;
+ n3 = trisym.triangle.id;
// Triangle number, neighboring triangle numbers.
writer.WriteLine("{0} {1} {2} {3}", i++, n1, n2, n3);
@@ -357,7 +358,7 @@ namespace TriangleNet.IO
{
Otri tri = default(Otri), trisym = default(Otri);
Vertex torg, tdest, tapex;
- Point2 circumcenter;
+ Point circumcenter;
double xi = 0, eta = 0;
int p1, p2, index = 0;
@@ -374,10 +375,10 @@ namespace TriangleNet.IO
torg = tri.Org();
tdest = tri.Dest();
tapex = tri.Apex();
- circumcenter = Primitives.FindCircumcenter(torg.pt, tdest.pt, tapex.pt, ref xi, ref eta, false);
+ circumcenter = Primitives.FindCircumcenter(torg, tdest, tapex, ref xi, ref eta, false);
// X and y coordinates.
- writer.Write("{0} {1} {2}", index, circumcenter.X.ToString(nfi),
+ writer.Write("{0} {1} {2}", index, circumcenter.X.ToString(nfi),
circumcenter.Y.ToString(nfi));
for (int i = 0; i < mesh.nextras; i++)
@@ -390,7 +391,7 @@ namespace TriangleNet.IO
}
writer.WriteLine();
- tri.triangle.ID = index++;
+ tri.triangle.id = index++;
}
@@ -411,10 +412,10 @@ namespace TriangleNet.IO
for (tri.orient = 0; tri.orient < 3; tri.orient++)
{
tri.Sym(ref trisym);
- if ((tri.triangle.ID < trisym.triangle.ID) || (trisym.triangle == Mesh.dummytri))
+ if ((tri.triangle.id < trisym.triangle.id) || (trisym.triangle == Mesh.dummytri))
{
// Find the number of this triangle (and Voronoi vertex).
- p1 = tri.triangle.ID;
+ p1 = tri.triangle.id;
if (trisym.triangle == Mesh.dummytri)
{
@@ -431,7 +432,7 @@ namespace TriangleNet.IO
else
{
// Find the number of the adjacent triangle (and Voronoi vertex).
- p2 = trisym.triangle.ID;
+ p2 = trisym.triangle.id;
// Finite edge. Write indices of two endpoints.
writer.WriteLine("{0} {1} {2}", index, p1, p2);
}
@@ -480,7 +481,7 @@ namespace TriangleNet.IO
// The "0.0" is here because the OFF format uses 3D coordinates.
writer.WriteLine(" {0} {1} 0.0", p1[0].ToString(nfi), p1[1].ToString(nfi));
- p1.ID = index++;
+ p1.id = index++;
}
}
@@ -495,7 +496,7 @@ namespace TriangleNet.IO
p3 = tri.Apex();
// The "3" means a three-vertex polygon.
- writer.WriteLine(" 3 {0} {1} {2}", p1.ID, p2.ID, p3.ID);
+ writer.WriteLine(" 3 {0} {1} {2}", p1.id, p2.id, p3.id);
}
}
}
diff --git a/Triangle.NET/Triangle/IO/InputTriangle.cs b/Triangle.NET/Triangle/IO/InputTriangle.cs
new file mode 100644
index 0000000..dc23e8f
--- /dev/null
+++ b/Triangle.NET/Triangle/IO/InputTriangle.cs
@@ -0,0 +1,107 @@
+// -----------------------------------------------------------------------
+//
+// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
+// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
+//
+// -----------------------------------------------------------------------
+
+namespace TriangleNet.IO
+{
+ using System;
+ using TriangleNet.Geometry;
+
+ ///
+ /// Simple triangle class for input.
+ ///
+ public class InputTriangle : ITriangle
+ {
+ internal int[] vertices;
+ internal double[] attributes;
+ internal double area;
+
+ public InputTriangle(int p0, int p1, int p2)
+ {
+ this.vertices = new int[] { p0, p1, p2 };
+ }
+
+ #region Public properties
+
+ ///
+ /// Gets the triangle id.
+ ///
+ public int ID
+ {
+ get { return 0; }
+ }
+
+ ///
+ /// Gets the first corners vertex id.
+ ///
+ public int P0
+ {
+ get { return this.vertices[0]; }
+ }
+
+ ///
+ /// Gets the seconds corners vertex id.
+ ///
+ public int P1
+ {
+ get { return this.vertices[1]; }
+ }
+
+ ///
+ /// Gets the third corners vertex id.
+ ///
+ public int P2
+ {
+ get { return this.vertices[2]; }
+ }
+
+ ///
+ /// Gets the specified corners vertex id.
+ ///
+ public int this[int index]
+ {
+ get { return this.vertices[index]; }
+ }
+
+ public bool SupportsNeighbors
+ {
+ get { return false; }
+ }
+
+ public int N0
+ {
+ get { return -1; }
+ }
+
+ public int N1
+ {
+ get { return -1; }
+ }
+
+ public int N2
+ {
+ get { return -1; }
+ }
+
+ ///
+ /// Gets the triangle area constraint.
+ ///
+ public double Area
+ {
+ get { return -1; }
+ }
+
+ ///
+ /// Gets the triangle attributes.
+ ///
+ public double[] Attributes
+ {
+ get { return null; }
+ }
+
+ #endregion
+ }
+}
diff --git a/Triangle.NET/Triangle/IO/MeshData.cs b/Triangle.NET/Triangle/IO/MeshData.cs
deleted file mode 100644
index 7508a79..0000000
--- a/Triangle.NET/Triangle/IO/MeshData.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
-// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/index.html
-//
-// -----------------------------------------------------------------------
-
-namespace TriangleNet.IO
-{
- ///
- /// Stores the mesh data in- and output.
- ///
- public class MeshData
- {
- public double[][] Points; // In / out
- public double[][] PointAttributes; // In / out
- public int[] PointMarkers; // In / out
-
- public int[][] Triangles; // In / out
- public double[][] TriangleAttributes; // In / out
- public double[] TriangleAreas; // In only
- public int[][] Neighbors; // Out only
-
- public int[][] Segments; // In / out
- public int[] SegmentMarkers; // In / out
-
- public double[][] Holes; // In / pointer to array copied out
- public double[][] Regions; // In / pointer to array copied out
-
- public int[][] Edges; // Out only
- public int[] EdgeMarkers; // Out only
- }
-}
diff --git a/Triangle.NET/Triangle/IO/VoronoiData.cs b/Triangle.NET/Triangle/IO/VoronoiData.cs
index 905d6ba..41dc354 100644
--- a/Triangle.NET/Triangle/IO/VoronoiData.cs
+++ b/Triangle.NET/Triangle/IO/VoronoiData.cs
@@ -7,16 +7,18 @@
namespace TriangleNet.IO
{
+ using TriangleNet.Geometry;
+
///
/// Stores the voronoi data (output only).
///
public class VoronoiData
{
- public double[][] InputPoints;
- public double[][] Points;
- public int[][] Edges;
+ public Point[] InputPoints;
+ public Point[] Points;
+ public Edge[] Edges;
// Stores the direction for infinite voronoi edges
public double[][] Directions;
}
-}
+}
\ No newline at end of file
diff --git a/Triangle.NET/Triangle/Log/SimpleLog.cs b/Triangle.NET/Triangle/Log/SimpleLog.cs
index 2ee2269..1f13403 100644
--- a/Triangle.NET/Triangle/Log/SimpleLog.cs
+++ b/Triangle.NET/Triangle/Log/SimpleLog.cs
@@ -12,7 +12,7 @@ namespace TriangleNet.Log
using System.Text;
///
- /// A simple logger, which logs messages to a List.
+ /// A simple logger, which logs messages to a List.
///
/// Using singleton pattern as proposed by Jon Skeet.
/// http://csharpindepth.com/Articles/General/Singleton.aspx
diff --git a/Triangle.NET/Triangle/Mesh.cs b/Triangle.NET/Triangle/Mesh.cs
index 8bdbf4c..74563fd 100644
--- a/Triangle.NET/Triangle/Mesh.cs
+++ b/Triangle.NET/Triangle/Mesh.cs
@@ -15,6 +15,8 @@ namespace TriangleNet
using TriangleNet.IO;
using TriangleNet.Algorithm;
using TriangleNet.Smoothing;
+ using TriangleNet.Geometry;
+ using TriangleNet.Tools;
///
/// Mesh data structure.
@@ -28,36 +30,41 @@ namespace TriangleNet
Quality quality;
Sampler sampler;
- // Variable that maintains the stack of recently flipped triangles.
- List flipstackers;
- FlipStacker lastflip;
+ // Stack that maintains a list of recently flipped triangles.
+ Stack flipstack;
+ //FlipStacker lastflip;
+
+ // TODO: Check if custom hashmap implementation could be faster.
// Using hashsets for memory management should quite fast.
internal Dictionary triangles;
- internal Dictionary subsegs;
+ internal Dictionary subsegs;
internal Dictionary vertices;
- // TODO: Check if custom hashmap implementation could be faster.
+ // Hash seeds (should belong to mesh instance)
+ internal int hash_vtx = 0;
+ internal int hash_seg = 0;
+ internal int hash_tri = 0;
- internal List holes;
- internal List regions;
+ internal List holes;
+ internal List regions;
internal List viri;
// Other variables.
- internal double xmin, xmax, ymin, ymax; // x and y bounds.
- internal int invertices; // Number of input vertices.
- internal int inelements; // Number of input triangles.
- internal int insegments; // Number of input segments.
- internal int undeads; // Number of input vertices that don't appear in the mesh.
- internal int edges; // Number of output edges.
- internal int mesh_dim; // Dimension (ought to be 2).
- internal int nextras; // Number of attributes per vertex.
- internal int eextras; // Number of attributes per triangle.
- internal int hullsize; // Number of edges in convex hull.
- internal int steinerleft; // Number of Steiner points not yet used.
- internal bool checksegments; // Are there segments in the triangulation yet?
- internal bool checkquality; // Has quality triangulation begun yet?
+ internal BoundingBox bounds; // x and y bounds.
+ internal int invertices; // Number of input vertices.
+ internal int inelements; // Number of input triangles.
+ internal int insegments; // Number of input segments.
+ internal int undeads; // Number of input vertices that don't appear in the mesh.
+ internal int edges; // Number of output edges.
+ internal int mesh_dim; // Dimension (ought to be 2).
+ internal int nextras; // Number of attributes per vertex.
+ internal int eextras; // Number of attributes per triangle.
+ internal int hullsize; // Number of edges in convex hull.
+ internal int steinerleft; // Number of Steiner points not yet used.
+ internal bool checksegments; // Are there segments in the triangulation yet?
+ internal bool checkquality; // Has quality triangulation begun yet?
// Triangular bounding box vertices.
internal Vertex infvertex1, infvertex2, infvertex3;
@@ -68,21 +75,88 @@ namespace TriangleNet
// The omnipresent subsegment. Referenced by any triangle or
// subsegment that isn't really connected to a subsegment at
// that location.
- internal static Subseg dummysub;
+ internal static Segment dummysub;
// Pointer to a recently visited triangle. Improves point location if
// proximate vertices are inserted sequentially.
internal Otri recenttri;
- static FlipStacker dummyflip;
+ //static FlipStacker dummyflip;
#endregion
+ #region Public properties
+
+ ///
+ /// Gets the mesh bounding box.
+ ///
+ public BoundingBox Bounds
+ {
+ get { return this.bounds; }
+ }
+
+ ///
+ /// Gets the mesh vertices.
+ ///
+ public IEnumerable Vertices
+ {
+ get { return this.vertices.Values; }
+ }
+
+ ///
+ /// Gets the mesh holes.
+ ///
+ public IList Holes
+ {
+ get { return this.holes; }
+ }
+
+ ///
+ /// Gets the mesh triangles.
+ ///
+ public IEnumerable Triangles
+ {
+ get { return this.triangles.Values; }
+ }
+
+ ///
+ /// Gets the mesh segments.
+ ///
+ public IEnumerable Segments
+ {
+ get { return this.subsegs.Values; }
+ }
+
///
/// Gets the number of input vertices.
///
public int NumberOfInputPoints { get { return invertices; } }
+ ///
+ /// Gets the number of mesh vertices.
+ ///
+ public int NumberOfVertices { get { return this.vertices.Count; } }
+
+ ///
+ /// Gets the number of mesh triangles.
+ ///
+ public int NumberOfTriangles { get { return this.triangles.Count; } }
+
+ ///
+ /// Gets the number of mesh segments.
+ ///
+ public int NumberOfSegments { get { return this.subsegs.Count; } }
+
+ ///
+ /// Gets the number of mesh edges.
+ ///
+ public int NumberOfEdges { get { return this.edges; } }
+
+ #endregion
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
public Mesh()
{
logger = SimpleLog.Instance;
@@ -91,13 +165,13 @@ namespace TriangleNet
vertices = new Dictionary();
triangles = new Dictionary();
- subsegs = new Dictionary();
+ subsegs = new Dictionary();
viri = new List();
- flipstackers = new List();
+ flipstack = new Stack();
- holes = new List();
- regions = new List();
+ holes = new List();
+ regions = new List();
quality = new Quality(this);
@@ -107,6 +181,7 @@ namespace TriangleNet
if (dummytri == null)
{
+ // Initialize static dummy triangle and subseg.
DummyInit();
}
}
@@ -116,7 +191,7 @@ namespace TriangleNet
///
public void Load(string inputfile)
{
- MeshData input = FileReader.ReadFile(inputfile, true);
+ InputGeometry input = FileReader.ReadFile(inputfile, true);
this.Load(input);
}
@@ -124,9 +199,11 @@ namespace TriangleNet
///
/// Reconstructs a mesh from raw input data.
///
- public void Load(MeshData input)
+ public void Load(InputGeometry input)
{
- if (input.Triangles == null)
+ throw new NotImplementedException("Load");
+
+ if (input == null)// TODO: if (input.Triangles == null)
{
throw new ArgumentException("The input data contains no triangles.");
}
@@ -139,15 +216,15 @@ namespace TriangleNet
Behavior.Poly = true;
}
- if (input.EdgeMarkers != null)
- {
- Behavior.UseBoundaryMarkers = true;
- }
+ //if (input.EdgeMarkers != null)
+ //{
+ // Behavior.UseBoundaryMarkers = true;
+ //}
- if (input.TriangleAreas != null)
- {
- Behavior.VarArea = true;
- }
+ //if (input.TriangleAreas != null)
+ //{
+ // Behavior.VarArea = true;
+ //}
if (!Behavior.Poly)
{
@@ -163,7 +240,7 @@ namespace TriangleNet
TransferNodes(input);
// Read and reconstruct a mesh.
- hullsize = DataReader.Reconstruct(this, input);
+ hullsize = DataReader.Reconstruct(this, input, null);
}
///
@@ -172,7 +249,7 @@ namespace TriangleNet
///
public void Triangulate(string inputFile)
{
- MeshData input = FileReader.ReadFile(inputFile);
+ InputGeometry input = FileReader.ReadFile(inputFile);
this.Triangulate(input);
}
@@ -181,19 +258,19 @@ namespace TriangleNet
/// Triangulate given input data.
///
///
- public void Triangulate(MeshData input)
+ public void Triangulate(InputGeometry input)
{
ResetData();
- if (input.Segments != null)
+ if (input.HasSegments)
{
Behavior.Poly = true;
}
- if (input.EdgeMarkers != null)
- {
- Behavior.UseBoundaryMarkers = true;
- }
+ //if (input.EdgeMarkers != null)
+ //{
+ // Behavior.UseBoundaryMarkers = true;
+ //}
if (!Behavior.Poly)
{
@@ -213,7 +290,7 @@ namespace TriangleNet
hullsize = Delaunay(); // Triangulate the vertices.
// Ensure that no vertex can be mistaken for a triangular bounding
- // box vertex in insertvertex().
+ // box vertex in insertvertex().
infvertex1 = null;
infvertex2 = null;
infvertex3 = null;
@@ -229,24 +306,20 @@ namespace TriangleNet
if (Behavior.Poly && (triangles.Count > 0))
{
- if (input.Holes != null)
+ // Copy holes
+ foreach (var item in input.holes)
{
- // Copy holes
- for (int i = 0; i < input.Holes.Length; i++)
- {
- holes.Add(new Point2(input.Holes[i][0], input.Holes[i][1]));
- }
+ holes.Add(item);
}
- if (input.Regions != null)
+ // Copy regions
+ foreach (var item in input.regions)
{
- // Copy regions
- for (int i = 0; i < input.Regions.Length; i++)
- {
- regions.Add(new Region(input.Regions[i]));
- }
+ regions.Add(item);
}
+ //dummytri.neighbors[2].triangle = dummytri;
+
// Carve out holes and concavities.
Carver c = new Carver(this);
c.CarveHoles();
@@ -283,8 +356,8 @@ namespace TriangleNet
foreach (var t in this.triangles.Values)
{
- tmp = (t.vertices[2].pt.X - t.vertices[0].pt.X) * (t.vertices[1].pt.Y - t.vertices[0].pt.Y) -
- (t.vertices[1].pt.X - t.vertices[0].pt.X) * (t.vertices[2].pt.Y - t.vertices[0].pt.Y);
+ tmp = (t.vertices[2].x - t.vertices[0].x) * (t.vertices[1].y - t.vertices[0].y) -
+ (t.vertices[1].x - t.vertices[0].x) * (t.vertices[2].y - t.vertices[0].y);
tmp = Math.Abs(tmp) / 2.0;
@@ -378,6 +451,24 @@ namespace TriangleNet
//smoother.Smooth();
}
+ ///
+ /// Renumber vertex and triangle id's.
+ ///
+ public void Renumber()
+ {
+ int id = 0;
+ foreach (var item in this.vertices.Values)
+ {
+ item.id = id++;
+ }
+
+ id = 0;
+ foreach (var item in this.triangles.Values)
+ {
+ item.id = id++;
+ }
+ }
+
///
/// Check mesh consistency and (constrained) Delaunay property.
///
@@ -387,63 +478,6 @@ namespace TriangleNet
quality.CheckDelaunay();
}
- ///
- /// Returns the raw mesh data.
- ///
- /// Mesh data.
- public MeshData GetMeshData()
- {
- return GetMeshData(true, true, true);
- }
-
- ///
- /// Returns the raw mesh data.
- ///
- /// Write elements to output.
- /// Write edges to output.
- /// Write neighbour information to output.
- /// Mesh data.
- public MeshData GetMeshData(bool writeElements, bool writeEdges, bool writeNeighbors)
- {
- MeshData output = new MeshData();
-
- if (Behavior.UseSegments)
- {
- //output.NumberOfSegments = subsegs.Count;
- }
- else
- {
- //output.NumberOfSegments = (int)hullsize;
- }
-
- // Numbers the vertices too.
- DataWriter.WriteNodes(this, output);
-
- if (writeElements)
- {
- DataWriter.WriteElements(this, output);
- }
-
- // The -c switch (convex switch) causes a PSLG to be written
- // even if none was read.
- if (Behavior.Poly || Behavior.Convex)
- {
- DataWriter.WritePoly(this, output);
- }
-
- if (writeEdges)
- {
- DataWriter.WriteEdges(this, output);
- }
-
- if (writeElements && writeNeighbors)
- {
- DataWriter.WriteNeighbors(this, output);
- }
-
- return output;
- }
-
#region Options
///
@@ -590,7 +624,7 @@ namespace TriangleNet
/// Form a Delaunay triangulation.
///
/// The number of points on the hull.
- int Delaunay()
+ private int Delaunay()
{
int hulledges = 0;
@@ -612,22 +646,15 @@ namespace TriangleNet
hulledges = alg.Triangulate(this);
}
- if (triangles.Count == 0)
- {
- // The input vertices were all collinear,
- // so there are no triangles.
- return 0;
- }
-
- return hulledges;
+ // The input vertices may all be collinear, so there are
+ // no triangles.
+ return (triangles.Count == 0) ? 0 : hulledges;
}
///
/// Reset all the mesh data. This method will also wipe
/// out all mesh data.
///
- /// The number of input points. Used to initialize
- /// memory for the mesh data.
private void ResetData()
{
vertices.Clear();
@@ -637,23 +664,19 @@ namespace TriangleNet
holes.Clear();
regions.Clear();
- Triangle.ResetHashSeed(0);
- Vertex.ResetHashSeed(0);
- Subseg.ResetHashSeed(0);
+ this.hash_vtx = 0;
+ this.hash_seg = 0;
+ this.hash_tri = 0;
viri.Clear();
- flipstackers.Clear();
+ flipstack.Clear();
hullsize = 0;
- xmin = 0;
- xmax = 0;
- ymin = 0;
- ymax = 0;
edges = 0;
- sampler.Reset();
-
Reset();
+
+ sampler.Reset();
}
///
@@ -680,7 +703,7 @@ namespace TriangleNet
///
/// The triangle that fills "outer space," called 'dummytri', is pointed to
/// by every triangle and subsegment on a boundary (be it outer or inner) of
- /// the triangulation. Also, 'dummytri' points to one of the triangles on
+ /// the triangulation. Also, 'dummytri' points to one of the triangles on
/// the convex hull (until the holes and concavities are carved), making it
/// possible to find a starting triangle for point location.
//
@@ -689,9 +712,9 @@ namespace TriangleNet
/// to point to.
//
/// 'dummytri' and 'dummysub' are generally required to fulfill only a few
- /// invariants: their vertices must remain NULL and 'dummytri' must always
+ /// invariants: their vertices must remain NULL and 'dummytri' must always
/// be bonded (at offset zero) to some triangle on the convex hull of the
- /// mesh, via a boundary edge. Otherwise, the connections of 'dummytri' and
+ /// mesh, via a boundary edge. Otherwise, the connections of 'dummytri' and
/// 'dummysub' may change willy-nilly. This makes it possible to avoid
/// writing a good deal of special-case code (in the edge flip, for example)
/// for dealing with the boundary of the mesh, places where no subsegment is
@@ -703,8 +726,10 @@ namespace TriangleNet
{
// Set up 'dummytri', the 'triangle' that occupies "outer space."
dummytri = new Triangle(0);
+ dummytri.hash = -1;
+ dummytri.id = -1;
- // Initialize the three adjoining triangles to be "outer space." These
+ // Initialize the three adjoining triangles to be "outer space." These
// will eventually be changed by various bonding operations, but their
// values don't really matter, as long as they can legally be
// dereferenced.
@@ -717,41 +742,34 @@ namespace TriangleNet
// Set up 'dummysub', the omnipresent subsegment pointed to by any
// triangle side or subsegment end that isn't attached to a real
// subsegment.
- dummysub = new Subseg();
+ dummysub = new Segment();
+ dummysub.hash = -1;
// Initialize the two adjoining subsegments to be the omnipresent
- // subsegment. These will eventually be changed by various bonding
+ // subsegment. These will eventually be changed by various bonding
// operations, but their values don't really matter, as long as they
// can legally be dereferenced.
- dummysub.subsegs[0].ss = dummysub;
- dummysub.subsegs[1].ss = dummysub;
+ dummysub.subsegs[0].seg = dummysub;
+ dummysub.subsegs[1].seg = dummysub;
// Initialize the three adjoining subsegments of 'dummytri' to be
// the omnipresent subsegment.
- dummytri.subsegs[0].ss = dummysub;
- dummytri.subsegs[1].ss = dummysub;
- dummytri.subsegs[2].ss = dummysub;
+ dummytri.subsegs[0].seg = dummysub;
+ dummytri.subsegs[1].seg = dummysub;
+ dummytri.subsegs[2].seg = dummysub;
}
-
- dummyflip = new FlipStacker();
}
///
/// Read the vertices from memory.
///
/// The input data.
- private void TransferNodes(MeshData data)
+ private void TransferNodes(InputGeometry data)
{
- Vertex vertex;
- double x, y;
- int attribs;
+ List points = data.points;
- double[][] points = data.Points;
- attribs = data.PointAttributes == null ? 0 : data.PointAttributes.Length;
-
- this.invertices = data.Points.Length;
+ this.invertices = points.Count;
this.mesh_dim = 2;
- this.nextras = attribs;
if (this.invertices < 3)
{
@@ -759,45 +777,20 @@ namespace TriangleNet
throw new Exception("Input must have at least three input vertices.");
}
- // Read the vertices.
- for (int i = 0; i < this.invertices; i++)
+ this.nextras = 0; // TODO: points[0].Attributes == null ? 0 : points[0].Attributes.Length;
+
+ foreach (Vertex vertex in points)
{
- vertex = new Vertex(nextras);
- vertex.type = VertexType.InputVertex;
- vertex.mark = 0;
- vertex.ID = vertex.Hash;
+ // TODO: Set vertex attributes.
+ //vertex.attribs = points[i].Attributes;
- // Read the vertex coordinates.
- x = vertex.pt.X = points[i][0];
- y = vertex.pt.Y = points[i][1];
+ vertex.hash = this.hash_vtx++;
+ vertex.id = vertex.hash;
- // Read the vertex attributes.
- for (int j = 0; j < attribs; j++)
- {
- //vertexloop.pt.attribs[j] = pointattriblist[i][j];
- }
- if (data.PointMarkers != null)
- {
- // Read a vertex marker.
- vertex.mark = data.PointMarkers[i];
- }
-
- this.vertices.Add(vertex.Hash, vertex);
-
- // Determine the smallest and largest x and y coordinates.
- if (i == 0)
- {
- this.xmin = this.xmax = x;
- this.ymin = this.ymax = y;
- }
- else
- {
- this.xmin = (x < this.xmin) ? x : this.xmin;
- this.xmax = (x > this.xmax) ? x : this.xmax;
- this.ymin = (y < this.ymin) ? y : this.ymin;
- this.ymax = (y > this.ymax) ? y : this.ymax;
- }
+ this.vertices.Add(vertex.hash, vertex);
}
+
+ this.bounds = data.Bounds;
}
#endregion
@@ -810,12 +803,14 @@ namespace TriangleNet
/// Reference to the new triangle.
internal void MakeTriangle(ref Otri newotri)
{
- Triangle t = new Triangle(eextras);
+ Triangle tri = new Triangle(eextras);
+ tri.hash = this.hash_tri++;
+ tri.id = tri.hash;
- newotri.triangle = t;
+ newotri.triangle = tri;
newotri.orient = 0;
- triangles.Add(t.Hash, t);
+ triangles.Add(tri.hash, tri);
}
///
@@ -824,12 +819,13 @@ namespace TriangleNet
/// Reference to the new subseg.
internal void MakeSubseg(ref Osub newsubseg)
{
- Subseg s = new Subseg();
+ Segment seg = new Segment();
+ seg.hash = this.hash_seg++;
- newsubseg.ss = s;
- newsubseg.ssorient = 0;
+ newsubseg.seg = seg;
+ newsubseg.orient = 0;
- subsegs.Add(s.Hash, s);
+ subsegs.Add(seg.hash, seg);
}
#endregion
@@ -839,47 +835,53 @@ namespace TriangleNet
/// Insert a vertex into a Delaunay triangulation, performing flips as necessary
/// to maintain the Delaunay property.
///
+ /// The point to be inserted.
+ /// The triangle to start the search.
+ /// Segment to split.
+ /// Check for creation of encroached subsegments.
+ /// Check for creation of bad quality triangles.
+ /// If a duplicate vertex or violated segment does not prevent the
+ /// vertex from being inserted, the return value will be ENCROACHINGVERTEX if
+ /// the vertex encroaches upon a subsegment (and checking is enabled), or
+ /// SUCCESSFULVERTEX otherwise. In either case, 'searchtri' is set to a handle
+ /// whose origin is the newly inserted vertex.
///
- /// The point 'newvertex' is located. If 'searchtri.tri' is not NULL,
+ /// The point 'newvertex' is located. If 'searchtri.triangle' is not NULL,
/// the search for the containing triangle begins from 'searchtri'. If
- /// 'searchtri.tri' is NULL, a full point location procedure is called.
+ /// 'searchtri.triangle' is NULL, a full point location procedure is called.
/// If 'insertvertex' is found inside a triangle, the triangle is split into
/// three; if 'insertvertex' lies on an edge, the edge is split in two,
- /// thereby splitting the two adjacent triangles into four. Edge flips are
- /// used to restore the Delaunay property. If 'insertvertex' lies on an
+ /// thereby splitting the two adjacent triangles into four. Edge flips are
+ /// used to restore the Delaunay property. If 'insertvertex' lies on an
/// existing vertex, no action is taken, and the value DUPLICATEVERTEX is
- /// returned. On return, 'searchtri' is set to a handle whose origin is the
+ /// returned. On return, 'searchtri' is set to a handle whose origin is the
/// existing vertex.
///
/// InsertVertex() does not use flip() for reasons of speed; some
/// information can be reused from edge flip to edge flip, like the
/// locations of subsegments.
- ///
- /// The point to be inserted.
- /// The triangle to start the search.
- /// Normally, the parameter 'splitseg' is set to NULL,
- /// implying that no subsegment should be split. In this case, if 'insertvertex'
+ ///
+ /// Param 'splitseg': Normally, the parameter 'splitseg' is set to NULL,
+ /// implying that no subsegment should be split. In this case, if 'insertvertex'
/// is found to lie on a segment, no action is taken, and the value VIOLATINGVERTEX
/// is returned. On return, 'searchtri' is set to a handle whose primary edge is the
/// violated subsegment.
+ /// If the calling routine wishes to split a subsegment by inserting a vertex in it,
+ /// the parameter 'splitseg' should be that subsegment. In this case, 'searchtri'
+ /// MUST be the triangle handle reached by pivoting from that subsegment; no point
+ /// location is done.
///
- /// If the calling routine wishes to split a subsegment
- /// by inserting a vertex in it, the parameter 'splitseg' should be that subsegment.
- /// In this case, 'searchtri' MUST be the triangle handle reached by pivoting
- /// from that subsegment; no point location is done.
- /// Flags that indicate whether or not there should
+ /// Param 'segmentflaws': Flags that indicate whether or not there should
/// be checks for the creation of encroached subsegments. If a newly inserted
/// vertex encroaches upon subsegments, these subsegments are added to the list
- /// of subsegments to be split if 'segmentflaws' is set.
- /// Flags that indicate whether or not there should be
+ /// of subsegments to be split if 'segmentflaws' is set.
+ ///
+ /// Param 'triflaws': Flags that indicate whether or not there should be
/// checks for the creation of bad quality triangles. If bad triangles are
- /// created, these are added to the queue if 'triflaws' is set.
- /// If a duplicate vertex or violated segment does not prevent the
- /// vertex from being inserted, the return value will be ENCROACHINGVERTEX if
- /// the vertex encroaches upon a subsegment (and checking is enabled), or
- /// SUCCESSFULVERTEX otherwise. In either case, 'searchtri' is set to a handle
- /// whose origin is the newly inserted vertex.
- internal InsertVertexResult InsertVertex(Vertex newvertex, ref Otri searchtri, ref Osub splitseg, bool segmentflaws, bool triflaws)
+ /// created, these are added to the queue if 'triflaws' is set.
+ ///
+ internal InsertVertexResult InsertVertex(Vertex newvertex, ref Otri searchtri,
+ ref Osub splitseg, bool segmentflaws, bool triflaws)
{
Otri horiz = default(Otri);
Otri top = default(Otri);
@@ -897,7 +899,7 @@ namespace TriangleNet
Osub rightsubseg = default(Osub);
Osub newsubseg = default(Osub);
BadSubseg encroached;
- FlipStacker newflip;
+ //FlipStacker newflip;
Vertex first;
Vertex leftvertex, rightvertex, botvertex, topvertex, farvertex;
Vertex segmentorg, segmentdest;
@@ -910,7 +912,7 @@ namespace TriangleNet
bool enq;
int i;
- if (splitseg.ss == null)
+ if (splitseg.seg == null)
{
// Find the location of the vertex to be inserted. Check if a good
// starting triangle has already been provided by the caller.
@@ -921,13 +923,13 @@ namespace TriangleNet
horiz.orient = 0;
horiz.SymSelf();
// Search for a triangle containing 'newvertex'.
- intersect = Locate(newvertex.pt, ref horiz);
+ intersect = Locate(newvertex, ref horiz);
}
else
{
// Start searching from the triangle provided by the caller.
searchtri.Copy(ref horiz);
- intersect = PreciseLocate(newvertex.pt, ref horiz, true);
+ intersect = PreciseLocate(newvertex, ref horiz, true);
}
}
else
@@ -949,11 +951,11 @@ namespace TriangleNet
if ((intersect == LocateResult.OnEdge) || (intersect == LocateResult.Outside))
{
// The vertex falls on an edge or boundary.
- if (checksegments && (splitseg.ss == null))
+ if (checksegments && (splitseg.seg == null))
{
// Check whether the vertex falls on a subsegment.
horiz.SegPivot(ref brokensubseg);
- if (brokensubseg.ss != dummysub)
+ if (brokensubseg.seg != dummysub)
{
// The vertex falls on a subsegment, and hence will not be inserted.
if (segmentflaws)
@@ -1053,7 +1055,7 @@ namespace TriangleNet
{
botright.SegPivot(ref botrsubseg);
- if (botrsubseg.ss != dummysub)
+ if (botrsubseg.seg != dummysub)
{
botright.SegDissolve();
newbotright.SegBond(ref botrsubseg);
@@ -1062,7 +1064,7 @@ namespace TriangleNet
if (mirrorflag)
{
topright.SegPivot(ref toprsubseg);
- if (toprsubseg.ss != dummysub)
+ if (toprsubseg.seg != dummysub)
{
topright.SegDissolve();
newtopright.SegBond(ref toprsubseg);
@@ -1085,7 +1087,7 @@ namespace TriangleNet
newtopright.Bond(ref newbotright);
}
- if (splitseg.ss != null)
+ if (splitseg.seg != null)
{
// Split the subsegment into two.
splitseg.SetDest(newvertex);
@@ -1093,7 +1095,7 @@ namespace TriangleNet
segmentdest = splitseg.SegDest();
splitseg.SymSelf();
splitseg.Pivot(ref rightsubseg);
- InsertSubseg(ref newbotright, splitseg.ss.boundary);
+ InsertSubseg(ref newbotright, splitseg.seg.boundary);
newbotright.SegPivot(ref newsubseg);
newsubseg.SetSegOrg(segmentorg);
newsubseg.SetSegDest(segmentdest);
@@ -1105,22 +1107,16 @@ namespace TriangleNet
// Transfer the subsegment's boundary marker to the vertex if required.
if (newvertex.mark == 0)
{
- newvertex.mark = splitseg.ss.boundary;
+ newvertex.mark = splitseg.seg.boundary;
}
}
if (checkquality)
{
- //poolrestart(&m.flipstackers); TODO
- flipstackers.Clear();
+ flipstack.Clear();
- lastflip = new FlipStacker();
- lastflip.flippedtri = horiz;
- lastflip.prevflip = dummyflip;
-
- flipstackers.Add(lastflip); // TODO: Could be ok???
-
- //throw new Exception("insertvertex: what to do here??");
+ flipstack.Push(default(Otri)); // Dummy flip (see UndoVertex)
+ flipstack.Push(horiz);
}
// Position 'horiz' on the first edge to check for
@@ -1166,17 +1162,17 @@ namespace TriangleNet
}
// There may be subsegments that need to be bonded
- // to the new triangles.
+ // to the new triangles.
if (checksegments)
{
botleft.SegPivot(ref botlsubseg);
- if (botlsubseg.ss != dummysub)
+ if (botlsubseg.seg != dummysub)
{
botleft.SegDissolve();
newbotleft.SegBond(ref botlsubseg);
}
botright.SegPivot(ref botrsubseg);
- if (botrsubseg.ss != dummysub)
+ if (botrsubseg.seg != dummysub)
{
botright.SegDissolve();
newbotright.SegBond(ref botrsubseg);
@@ -1196,24 +1192,17 @@ namespace TriangleNet
if (checkquality)
{
- // poolrestart(&m->flipstackers); TODO
- flipstackers.Clear();
-
- lastflip = new FlipStacker();
- lastflip.flippedtri = horiz;
- lastflip.prevflip = null;
-
- flipstackers.Add(lastflip);
+ flipstack.Clear();
+ flipstack.Push(horiz);
}
}
// The insertion is successful by default, unless an encroached
// subsegment is found.
success = InsertVertexResult.Successful;
- // Circle around the newly inserted vertex, checking each edge opposite
- // it for the Delaunay property. Non-Delaunay edges are flipped.
- // 'horiz' is always the edge being checked. 'first' marks where to
- // stop circling.
+ // Circle around the newly inserted vertex, checking each edge opposite it
+ // for the Delaunay property. Non-Delaunay edges are flipped. 'horiz' is
+ // always the edge being checked. 'first' marks where to stop circling.
first = horiz.Org();
rightvertex = first;
leftvertex = horiz.Dest();
@@ -1227,7 +1216,7 @@ namespace TriangleNet
{
// Check for a subsegment, which cannot be flipped.
horiz.SegPivot(ref checksubseg);
- if (checksubseg.ss != dummysub)
+ if (checksubseg.seg != dummysub)
{
// The edge is a subsegment and cannot be flipped.
doflip = false;
@@ -1258,17 +1247,17 @@ namespace TriangleNet
farvertex = top.Apex();
// In the incremental Delaunay triangulation algorithm, any of
// 'leftvertex', 'rightvertex', and 'farvertex' could be vertices
- // of the triangular bounding box. These vertices must be
+ // of the triangular bounding box. These vertices must be
// treated as if they are infinitely distant, even though their
// "coordinates" are not.
if ((leftvertex == infvertex1) || (leftvertex == infvertex2) ||
(leftvertex == infvertex3))
{
- // 'leftvertex' is infinitely distant. Check the convexity of
- // the boundary of the triangulation. 'farvertex' might be
+ // 'leftvertex' is infinitely distant. Check the convexity of
+ // the boundary of the triangulation. 'farvertex' might be
// infinite as well, but trust me, this same condition should
// be applied.
- doflip = Primitives.CounterClockwise(newvertex.pt, rightvertex.pt, farvertex.pt) > 0.0;
+ doflip = Primitives.CounterClockwise(newvertex, rightvertex, farvertex) > 0.0;
}
else if ((rightvertex == infvertex1) ||
(rightvertex == infvertex2) ||
@@ -1278,7 +1267,7 @@ namespace TriangleNet
// the boundary of the triangulation. 'farvertex' might be
// infinite as well, but trust me, this same condition should
// be applied.
- doflip = Primitives.CounterClockwise(farvertex.pt, leftvertex.pt, newvertex.pt) > 0.0;
+ doflip = Primitives.CounterClockwise(farvertex, leftvertex, newvertex) > 0.0;
}
else if ((farvertex == infvertex1) ||
(farvertex == infvertex2) ||
@@ -1291,7 +1280,7 @@ namespace TriangleNet
else
{
// Test whether the edge is locally Delaunay.
- doflip = Primitives.InCircle(leftvertex.pt, newvertex.pt, rightvertex.pt, farvertex.pt) > 0.0;
+ doflip = Primitives.InCircle(leftvertex, newvertex, rightvertex, farvertex) > 0.0;
}
if (doflip)
{
@@ -1318,7 +1307,7 @@ namespace TriangleNet
botleft.SegPivot(ref botlsubseg);
botright.SegPivot(ref botrsubseg);
topright.SegPivot(ref toprsubseg);
- if (toplsubseg.ss == dummysub)
+ if (toplsubseg.seg == dummysub)
{
topright.SegDissolve();
}
@@ -1326,7 +1315,7 @@ namespace TriangleNet
{
topright.SegBond(ref toplsubseg);
}
- if (botlsubseg.ss == dummysub)
+ if (botlsubseg.seg == dummysub)
{
topleft.SegDissolve();
}
@@ -1334,7 +1323,7 @@ namespace TriangleNet
{
topleft.SegBond(ref botlsubseg);
}
- if (botrsubseg.ss == dummysub)
+ if (botrsubseg.seg == dummysub)
{
botleft.SegDissolve();
}
@@ -1342,7 +1331,7 @@ namespace TriangleNet
{
botleft.SegBond(ref botrsubseg);
}
- if (toprsubseg.ss == dummysub)
+ if (toprsubseg.seg == dummysub)
{
botright.SegDissolve();
}
@@ -1387,17 +1376,11 @@ namespace TriangleNet
if (checkquality)
{
- newflip = new FlipStacker();
- newflip.flippedtri = horiz;
- newflip.prevflip = lastflip;
- lastflip = newflip;
-
- flipstackers.Add(newflip);
+ flipstack.Push(horiz);
}
- // On the next iterations, consider the two edges that were
- // exposed (this is, are now visible to the newly inserted
- // vertex) by the edge flip.
+ // On the next iterations, consider the two edges that were exposed (this
+ // is, are now visible to the newly inserted vertex) by the edge flip.
horiz.LprevSelf();
leftvertex = farvertex;
}
@@ -1416,11 +1399,11 @@ namespace TriangleNet
horiz.LnextSelf();
horiz.Sym(ref testtri);
// Check for finishing a complete revolution about the new vertex, or
- // falling outside of the triangulation. The latter will happen
- // when a vertex is inserted at a boundary.
+ // falling outside of the triangulation. The latter will happen when
+ // a vertex is inserted at a boundary.
if ((leftvertex == first) || (testtri.triangle == dummytri))
{
- // We're done. Return a triangle whose origin is the new vertex.
+ // We're done. Return a triangle whose origin is the new vertex.
horiz.Lnext(ref searchtri);
horiz.Lnext(ref recenttri);
return success;
@@ -1460,7 +1443,7 @@ namespace TriangleNet
}
// Check if there's already a subsegment here.
tri.SegPivot(ref newsubseg);
- if (newsubseg.ss == dummysub)
+ if (newsubseg.seg == dummysub)
{
// Make new subsegment and initialize its vertices.
MakeSubseg(ref newsubseg);
@@ -1469,20 +1452,19 @@ namespace TriangleNet
newsubseg.SetSegOrg(tridest);
newsubseg.SetSegDest(triorg);
// Bond new subsegment to the two triangles it is sandwiched between.
- // Note that the facing triangle 'oppotri' might be equal to
- // 'dummytri' (outer space), but the new subsegment is bonded to it
- // all the same.
+ // Note that the facing triangle 'oppotri' might be equal to 'dummytri'
+ // (outer space), but the new subsegment is bonded to it all the same.
tri.SegBond(ref newsubseg);
tri.Sym(ref oppotri);
newsubseg.SymSelf();
oppotri.SegBond(ref newsubseg);
- newsubseg.ss.boundary = subsegmark;
+ newsubseg.seg.boundary = subsegmark;
}
else
{
- if (newsubseg.ss.boundary == 0)
+ if (newsubseg.seg.boundary == 0)
{
- newsubseg.ss.boundary = subsegmark;
+ newsubseg.seg.boundary = subsegmark;
}
}
}
@@ -1491,11 +1473,11 @@ namespace TriangleNet
/// Transform two triangles to two different triangles by flipping an edge
/// counterclockwise within a quadrilateral.
///
- ///
+ /// Handle to the edge that will be flipped.
/// Imagine the original triangles, abc and bad, oriented so that the
/// shared edge ab lies in a horizontal plane, with the vertex b on the left
- /// and the vertex a on the right. The vertex c lies below the edge, and
- /// the vertex d lies above the edge. The 'flipedge' handle holds the edge
+ /// and the vertex a on the right. The vertex c lies below the edge, and
+ /// the vertex d lies above the edge. The 'flipedge' handle holds the edge
/// ab of triangle abc, and is directed left, from vertex a to vertex b.
///
/// The triangles abc and bad are deleted and replaced by the triangles cdb
@@ -1547,6 +1529,26 @@ namespace TriangleNet
botvertex = flipedge.Apex();
flipedge.Sym(ref top);
+ // SELF CHECK
+
+ //if (top.triangle == dummytri)
+ //{
+ // logger.Error("Attempt to flip on boundary.", "Mesh.Flip()");
+ // flipedge.LnextSelf();
+ // return;
+ //}
+
+ //if (checksegments)
+ //{
+ // flipedge.SegPivot(ref toplsubseg);
+ // if (toplsubseg.ss != dummysub)
+ // {
+ // logger.Error("Attempt to flip a segment.", "Mesh.Flip()");
+ // flipedge.LnextSelf();
+ // return;
+ // }
+ //}
+
farvertex = top.Apex();
// Identify the casing of the quadrilateral.
@@ -1571,7 +1573,8 @@ namespace TriangleNet
botleft.SegPivot(ref botlsubseg);
botright.SegPivot(ref botrsubseg);
topright.SegPivot(ref toprsubseg);
- if (toplsubseg.ss == Mesh.dummysub)
+
+ if (toplsubseg.seg == Mesh.dummysub)
{
topright.SegDissolve();
}
@@ -1579,7 +1582,8 @@ namespace TriangleNet
{
topright.SegBond(ref toplsubseg);
}
- if (botlsubseg.ss == Mesh.dummysub)
+
+ if (botlsubseg.seg == Mesh.dummysub)
{
topleft.SegDissolve();
}
@@ -1587,7 +1591,8 @@ namespace TriangleNet
{
topleft.SegBond(ref botlsubseg);
}
- if (botrsubseg.ss == Mesh.dummysub)
+
+ if (botrsubseg.seg == Mesh.dummysub)
{
botleft.SegDissolve();
}
@@ -1595,7 +1600,8 @@ namespace TriangleNet
{
botleft.SegBond(ref botrsubseg);
}
- if (toprsubseg.ss == Mesh.dummysub)
+
+ if (toprsubseg.seg == Mesh.dummysub)
{
botright.SegDissolve();
}
@@ -1616,35 +1622,17 @@ namespace TriangleNet
///
/// Transform two triangles to two different triangles by flipping an edge
- /// clockwise within a quadrilateral. Reverses the flip() operation so that
+ /// clockwise within a quadrilateral. Reverses the flip() operation so that
/// the data structures representing the triangles are back where they were
/// before the flip().
///
///
///
- /// Imagine the original triangles, abc and bad, oriented so that the
- /// shared edge ab lies in a horizontal plane, with the vertex b on the left
- /// and the vertex a on the right. The vertex c lies below the edge, and
- /// the vertex d lies above the edge. The 'flipedge' handle holds the edge
- /// ab of triangle abc, and is directed left, from vertex a to vertex b.
- ///
- /// The triangles abc and bad are deleted and replaced by the triangles cdb
- /// and dca. The triangles that represent abc and bad are NOT deallocated;
- /// they are reused for cdb and dca, respectively. Hence, any handles that
- /// may have held the original triangles are still valid, although not
- /// directed as they were before.
+ /// See above Flip() remarks for more information.
///
/// Upon completion of this routine, the 'flipedge' handle holds the edge
/// cd of triangle cdb, and is directed up, from vertex c to vertex d.
/// (Hence, the two triangles have rotated clockwise.)
- ///
- /// WARNING: This transformation is geometrically valid only if the
- /// quadrilateral adbc is convex. Furthermore, this transformation is
- /// valid only if there is not a subsegment between the triangles abc and
- /// bad. This routine does not check either of these preconditions, and
- /// it is the responsibility of the calling routine to ensure that they are
- /// met. If they are not, the streets shall be filled with wailing and
- /// gnashing of teeth.
///
internal void Unflip(ref Otri flipedge)
{
@@ -1688,7 +1676,7 @@ namespace TriangleNet
botleft.SegPivot(ref botlsubseg);
botright.SegPivot(ref botrsubseg);
topright.SegPivot(ref toprsubseg);
- if (toplsubseg.ss == Mesh.dummysub)
+ if (toplsubseg.seg == Mesh.dummysub)
{
botleft.SegDissolve();
}
@@ -1696,7 +1684,7 @@ namespace TriangleNet
{
botleft.SegBond(ref toplsubseg);
}
- if (botlsubseg.ss == Mesh.dummysub)
+ if (botlsubseg.seg == Mesh.dummysub)
{
botright.SegDissolve();
}
@@ -1704,7 +1692,7 @@ namespace TriangleNet
{
botright.SegBond(ref botlsubseg);
}
- if (botrsubseg.ss == Mesh.dummysub)
+ if (botrsubseg.seg == Mesh.dummysub)
{
topright.SegDissolve();
}
@@ -1712,7 +1700,7 @@ namespace TriangleNet
{
topright.SegBond(ref botrsubseg);
}
- if (toprsubseg.ss == Mesh.dummysub)
+ if (toprsubseg.seg == Mesh.dummysub)
{
topleft.SegDissolve();
}
@@ -1744,14 +1732,14 @@ namespace TriangleNet
/// A flag that determines whether the new triangles should
/// be tested for quality, and enqueued if they are bad.
///
- // This is a conceptually difficult routine. The starting assumption is
- // that we have a polygon with n sides. n - 1 of these sides are currently
- // represented as edges in the mesh. One side, called the "base", need not
+ // This is a conceptually difficult routine. The starting assumption is
+ // that we have a polygon with n sides. n - 1 of these sides are currently
+ // represented as edges in the mesh. One side, called the "base", need not
// be.
//
// Inside the polygon is a structure I call a "fan", consisting of n - 1
// triangles that share a common origin. For each of these triangles, the
- // edge opposite the origin is one of the sides of the polygon. The
+ // edge opposite the origin is one of the sides of the polygon. The
// primary edge of each triangle is the edge directed from the origin to
// the destination; note that this is not the same edge that is a side of
// the polygon. 'firstedge' is the primary edge of the first triangle.
@@ -1803,8 +1791,8 @@ namespace TriangleNet
Vertex leftbasevertex, rightbasevertex;
Vertex testvertex;
Vertex bestvertex;
- int bestnumber;
- int i;
+
+ int bestnumber = 1;
// Identify the base vertices.
leftbasevertex = lastedge.Apex();
@@ -1814,13 +1802,13 @@ namespace TriangleNet
firstedge.Onext(ref besttri);
bestvertex = besttri.Dest();
besttri.Copy(ref testtri);
- bestnumber = 1;
- for (i = 2; i <= edgecount - 2; i++)
+
+ for (int i = 2; i <= edgecount - 2; i++)
{
testtri.OnextSelf();
testvertex = testtri.Dest();
// Is this a better vertex?
- if (Primitives.InCircle(leftbasevertex.pt, rightbasevertex.pt, bestvertex.pt, testvertex.pt) > 0.0)
+ if (Primitives.InCircle(leftbasevertex, rightbasevertex, bestvertex, testvertex) > 0.0)
{
testtri.Copy(ref besttri);
bestvertex = testvertex;
@@ -1864,12 +1852,12 @@ namespace TriangleNet
/// triangulation remains Delaunay.
///
///
- /// The origin of 'deltri' is deleted. The union of the triangles adjacent
- /// to this vertex is a polygon, for which the Delaunay triangulation is
- /// found. Two triangles are removed from the mesh.
+ /// The origin of 'deltri' is deleted. The union of the triangles
+ /// adjacent to this vertex is a polygon, for which the Delaunay triangulation
+ /// is found. Two triangles are removed from the mesh.
///
- /// Only interior vertices that do not lie on segments or boundaries may be
- /// deleted.
+ /// Only interior vertices that do not lie on segments or boundaries
+ /// may be deleted.
///
internal void DeleteVertex(ref Otri deltri)
{
@@ -1914,12 +1902,12 @@ namespace TriangleNet
deltri.Bond(ref leftcasing);
deltriright.Bond(ref rightcasing);
lefttri.SegPivot(ref leftsubseg);
- if (leftsubseg.ss != Mesh.dummysub)
+ if (leftsubseg.seg != Mesh.dummysub)
{
deltri.SegBond(ref leftsubseg);
}
righttri.SegPivot(ref rightsubseg);
- if (rightsubseg.ss != Mesh.dummysub)
+ if (rightsubseg.seg != Mesh.dummysub)
{
deltriright.SegBond(ref rightsubseg);
}
@@ -1948,7 +1936,8 @@ namespace TriangleNet
///
internal void UndoVertex()
{
- Otri fliptri = default(Otri);
+ Otri fliptri;
+
Otri botleft = default(Otri), botright = default(Otri), topright = default(Otri);
Otri botlcasing = default(Otri), botrcasing = default(Otri), toprcasing = default(Otri);
Otri gluetri = default(Otri);
@@ -1957,16 +1946,16 @@ namespace TriangleNet
// Walk through the list of transformations (flips and a vertex insertion)
// in the reverse of the order in which they were done, and undo them.
- while (lastflip != null)
+ while (flipstack.Count > 0)
{
// Find a triangle involved in the last unreversed transformation.
- fliptri = lastflip.flippedtri;
+ fliptri = flipstack.Pop();
// We are reversing one of three transformations: a trisection of one
// triangle into three (by inserting a vertex in the triangle), a
// bisection of two triangles into four (by inserting a vertex in an
// edge), or an edge flip.
- if (lastflip.prevflip == null)
+ if (flipstack.Count == 0)
{
// Restore a triangle that was split into three triangles,
// so it is again one triangle.
@@ -1992,7 +1981,7 @@ namespace TriangleNet
TriangleDealloc(botleft.triangle);
TriangleDealloc(botright.triangle);
}
- else if (lastflip.prevflip == dummyflip)
+ else if (flipstack.Peek().triangle == null) // Dummy flip
{
// Restore two triangles that were split into four triangles,
// so they are again two triangles.
@@ -2026,17 +2015,13 @@ namespace TriangleNet
TriangleDealloc(topright.triangle);
}
- // This is the end of the list, sneakily encoded.
- lastflip.prevflip = null;
+ flipstack.Clear();
}
else
{
// Undo an edge flip.
Unflip(ref fliptri);
}
-
- // Go on and process the next transformation.
- lastflip = lastflip.prevflip;
}
}
@@ -2050,12 +2035,12 @@ namespace TriangleNet
///
///
/// Traverses all the triangles, and provides each corner of each triangle
- /// with a pointer to that triangle. Of course, pointers will be
- /// overwritten by other pointers because (almost) each vertex is a corner
- /// of several triangles, but in the end every vertex will point to some
- /// triangle that contains it.
+ /// with a pointer to that triangle. Of course, pointers will be overwritten
+ /// by other pointers because (almost) each vertex is a corner of several
+ /// triangles, but in the end every vertex will point to some triangle
+ /// that contains it.
///
- void MakeVertexMap()
+ private void MakeVertexMap()
{
Otri tri = default(Otri);
Vertex triorg;
@@ -2081,24 +2066,24 @@ namespace TriangleNet
/// will stop if it tries to walk through a subsegment, and will return OUTSIDE.
/// Location information.
///
- /// Begins its search from 'searchtri'. It is important that 'searchtri'
+ /// Begins its search from 'searchtri'. It is important that 'searchtri'
/// be a handle with the property that 'searchpoint' is strictly to the left
/// of the edge denoted by 'searchtri', or is collinear with that edge and
- /// does not intersect that edge. (In particular, 'searchpoint' should not
+ /// does not intersect that edge. (In particular, 'searchpoint' should not
/// be the origin or destination of that edge.)
///
/// These conditions are imposed because preciselocate() is normally used in
/// one of two situations:
///
/// (1) To try to find the location to insert a new point. Normally, we
- /// know an edge that the point is strictly to the left of. In the
+ /// know an edge that the point is strictly to the left of. In the
/// incremental Delaunay algorithm, that edge is a bounding box edge.
/// In Ruppert's Delaunay refinement algorithm for quality meshing,
/// that edge is the shortest edge of the triangle whose circumcenter
/// is being inserted.
///
/// (2) To try to find an existing point. In this case, any edge on the
- /// convex hull is a good starting edge. You must screen out the
+ /// convex hull is a good starting edge. You must screen out the
/// possibility that the vertex sought is an endpoint of the starting
/// edge before you call preciselocate().
///
@@ -2106,31 +2091,31 @@ namespace TriangleNet
///
/// This implementation differs from that given by Guibas and Stolfi. It
/// walks from triangle to triangle, crossing an edge only if 'searchpoint'
- /// is on the other side of the line containing that edge. After entering
+ /// is on the other side of the line containing that edge. After entering
/// a triangle, there are two edges by which one can leave that triangle.
/// If both edges are valid ('searchpoint' is on the other side of both
/// edges), one of the two is chosen by drawing a line perpendicular to
/// the entry edge (whose endpoints are 'forg' and 'fdest') passing through
- /// 'fapex'. Depending on which side of this perpendicular 'searchpoint'
+ /// 'fapex'. Depending on which side of this perpendicular 'searchpoint'
/// falls on, an exit edge is chosen.
///
/// This implementation is empirically faster than the Guibas and Stolfi
/// point location routine (which I originally used), which tends to spiral
/// in toward its target.
///
- /// Returns ONVERTEX if the point lies on an existing vertex. 'searchtri'
+ /// Returns ONVERTEX if the point lies on an existing vertex. 'searchtri'
/// is a handle whose origin is the existing vertex.
///
- /// Returns ONEDGE if the point lies on a mesh edge. 'searchtri' is a
+ /// Returns ONEDGE if the point lies on a mesh edge. 'searchtri' is a
/// handle whose primary edge is the edge on which the point lies.
///
/// Returns INTRIANGLE if the point lies strictly within a triangle.
/// 'searchtri' is a handle on the triangle that contains the point.
///
- /// Returns OUTSIDE if the point lies outside the mesh. 'searchtri' is a
+ /// Returns OUTSIDE if the point lies outside the mesh. 'searchtri' is a
/// handle whose primary edge the point is to the right of. This might
/// occur when the circumcenter of a triangle falls just slightly outside
- /// the mesh due to floating-point roundoff error. It also occurs when
+ /// the mesh due to floating-point roundoff error. It also occurs when
/// seeking a hole or region point that a foolish user has placed outside
/// the mesh.
///
@@ -2138,7 +2123,7 @@ namespace TriangleNet
/// not generally work after the holes and concavities have been carved.
/// However, it can still be used to find the circumcenter of a triangle, as
/// long as the search is begun from the triangle in question.
- internal LocateResult PreciseLocate(Point2 searchpoint, ref Otri searchtri,
+ internal LocateResult PreciseLocate(Point searchpoint, ref Otri searchtri,
bool stopatsubsegment)
{
Otri backtracktri = default(Otri);
@@ -2154,17 +2139,17 @@ namespace TriangleNet
while (true)
{
// Check whether the apex is the point we seek.
- if ((fapex.pt.X == searchpoint.X) && (fapex.pt.Y == searchpoint.Y))
+ if ((fapex.x == searchpoint.X) && (fapex.y == searchpoint.Y))
{
searchtri.LprevSelf();
return LocateResult.OnVertex;
}
// Does the point lie on the other side of the line defined by the
// triangle edge opposite the triangle's destination?
- destorient = Primitives.CounterClockwise(forg.pt, fapex.pt, searchpoint);
+ destorient = Primitives.CounterClockwise(forg, fapex, searchpoint);
// Does the point lie on the other side of the line defined by the
// triangle edge opposite the triangle's origin?
- orgorient = Primitives.CounterClockwise(fapex.pt, fdest.pt, searchpoint);
+ orgorient = Primitives.CounterClockwise(fapex, fdest, searchpoint);
if (destorient > 0.0)
{
if (orgorient > 0.0)
@@ -2174,8 +2159,8 @@ namespace TriangleNet
// a line perpendicular to the line (forg, fdest) and passing
// through 'fapex', and determining which side of this line
// 'searchpoint' falls on.
- moveleft = (fapex.pt.X - searchpoint.X) * (fdest.pt.X - forg.pt.X) +
- (fapex.pt.Y - searchpoint.Y) * (fdest.pt.Y - forg.pt.Y) > 0.0;
+ moveleft = (fapex.x - searchpoint.X) * (fdest.x - forg.x) +
+ (fapex.y - searchpoint.Y) * (fdest.y - forg.y) > 0.0;
}
else
{
@@ -2206,7 +2191,7 @@ namespace TriangleNet
}
}
- // Move to another triangle. Leave a trace 'backtracktri' in case
+ // Move to another triangle. Leave a trace 'backtracktri' in case
// floating-point roundoff or some such bogey causes us to walk
// off a boundary of the triangulation.
if (moveleft)
@@ -2225,7 +2210,7 @@ namespace TriangleNet
{
// Check for walking through a subsegment.
backtracktri.SegPivot(ref checkedge);
- if (checkedge.ss != dummysub)
+ if (checkedge.seg != dummysub)
{
// Go back to the last triangle.
backtracktri.Copy(ref searchtri);
@@ -2253,8 +2238,8 @@ namespace TriangleNet
///
/// Searching begins from one of: the input 'searchtri', a recently
/// encountered triangle 'recenttri', or from a triangle chosen from a
- /// random sample. The choice is made by determining which triangle's
- /// origin is closest to the point we are searching for. Normally,
+ /// random sample. The choice is made by determining which triangle's
+ /// origin is closest to the point we are searching for. Normally,
/// 'searchtri' should be a handle on the convex hull of the triangulation.
///
/// Details on the random sampling method can be found in the Mucke, Saias,
@@ -2262,39 +2247,37 @@ namespace TriangleNet
///
/// On completion, 'searchtri' is a triangle that contains 'searchpoint'.
///
- /// Returns ONVERTEX if the point lies on an existing vertex. 'searchtri'
+ /// Returns ONVERTEX if the point lies on an existing vertex. 'searchtri'
/// is a handle whose origin is the existing vertex.
///
- /// Returns ONEDGE if the point lies on a mesh edge. 'searchtri' is a
+ /// Returns ONEDGE if the point lies on a mesh edge. 'searchtri' is a
/// handle whose primary edge is the edge on which the point lies.
///
/// Returns INTRIANGLE if the point lies strictly within a triangle.
/// 'searchtri' is a handle on the triangle that contains the point.
///
- /// Returns OUTSIDE if the point lies outside the mesh. 'searchtri' is a
+ /// Returns OUTSIDE if the point lies outside the mesh. 'searchtri' is a
/// handle whose primary edge the point is to the right of. This might
/// occur when the circumcenter of a triangle falls just slightly outside
- /// the mesh due to floating-point roundoff error. It also occurs when
+ /// the mesh due to floating-point roundoff error. It also occurs when
/// seeking a hole or region point that a foolish user has placed outside
/// the mesh.
///
/// WARNING: This routine is designed for convex triangulations, and will
/// not generally work after the holes and concavities have been carved.
///
- internal LocateResult Locate(Point2 searchpoint, ref Otri searchtri)
+ internal LocateResult Locate(Point searchpoint, ref Otri searchtri)
{
Otri sampletri = default(Otri);
Vertex torg, tdest;
double searchdist, dist;
double ahead;
- //long samplesperblock, totalsamplesleft, samplesleft;
- //long population, totalpopulation;
// Record the distance from the suggested starting triangle to the
// point we seek.
torg = searchtri.Org();
- searchdist = (searchpoint.X - torg.pt.X) * (searchpoint.X - torg.pt.X) +
- (searchpoint.Y - torg.pt.Y) * (searchpoint.Y - torg.pt.Y);
+ searchdist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
+ (searchpoint.Y - torg.y) * (searchpoint.Y - torg.y);
// If a recently encountered triangle has been recorded and has not been
// deallocated, test it as a good starting point.
@@ -2303,13 +2286,13 @@ namespace TriangleNet
if (!Otri.IsDead(recenttri.triangle))
{
torg = recenttri.Org();
- if ((torg.pt.X == searchpoint.X) && (torg.pt.Y == searchpoint.Y))
+ if ((torg.x == searchpoint.X) && (torg.y == searchpoint.Y))
{
recenttri.Copy(ref searchtri);
return LocateResult.OnVertex;
}
- dist = (searchpoint.X - torg.pt.X) * (searchpoint.X - torg.pt.X) +
- (searchpoint.Y - torg.pt.Y) * (searchpoint.Y - torg.pt.Y);
+ dist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
+ (searchpoint.Y - torg.y) * (searchpoint.Y - torg.y);
if (dist < searchdist)
{
recenttri.Copy(ref searchtri);
@@ -2328,8 +2311,8 @@ namespace TriangleNet
if (!Otri.IsDead(sampletri.triangle))
{
torg = sampletri.Org();
- dist = (searchpoint.X - torg.pt.X) * (searchpoint.X - torg.pt.X) +
- (searchpoint.Y - torg.pt.Y) * (searchpoint.Y - torg.pt.Y);
+ dist = (searchpoint.X - torg.x) * (searchpoint.X - torg.x) +
+ (searchpoint.Y - torg.y) * (searchpoint.Y - torg.y);
if (dist < searchdist)
{
sampletri.Copy(ref searchtri);
@@ -2342,17 +2325,17 @@ namespace TriangleNet
torg = searchtri.Org();
tdest = searchtri.Dest();
// Check the starting triangle's vertices.
- if ((torg.pt.X == searchpoint.X) && (torg.pt.Y == searchpoint.Y))
+ if ((torg.x == searchpoint.X) && (torg.y == searchpoint.Y))
{
return LocateResult.OnVertex;
}
- if ((tdest.pt.X == searchpoint.X) && (tdest.pt.Y == searchpoint.Y))
+ if ((tdest.x == searchpoint.X) && (tdest.y == searchpoint.Y))
{
searchtri.LnextSelf();
return LocateResult.OnVertex;
}
// Orient 'searchtri' to fit the preconditions of calling preciselocate().
- ahead = Primitives.CounterClockwise(torg.pt, tdest.pt, searchpoint);
+ ahead = Primitives.CounterClockwise(torg, tdest, searchpoint);
if (ahead < 0.0)
{
// Turn around so that 'searchpoint' is to the left of the
@@ -2362,8 +2345,8 @@ namespace TriangleNet
else if (ahead == 0.0)
{
// Check if 'searchpoint' is between 'torg' and 'tdest'.
- if (((torg.pt.X < searchpoint.X) == (searchpoint.X < tdest.pt.X)) &&
- ((torg.pt.Y < searchpoint.Y) == (searchpoint.Y < tdest.pt.Y)))
+ if (((torg.x < searchpoint.X) == (searchpoint.X < tdest.x)) &&
+ ((torg.y < searchpoint.Y) == (searchpoint.Y < tdest.y)))
{
return LocateResult.OnEdge;
}
@@ -2391,7 +2374,7 @@ namespace TriangleNet
/// is used to find the direction to move in to get from one point to
/// another.
///
- FindDirectionResult FindDirection(ref Otri searchtri, Vertex searchpoint)
+ private FindDirectionResult FindDirection(ref Otri searchtri, Vertex searchpoint)
{
Otri checktri = default(Otri);
Vertex startvertex;
@@ -2403,10 +2386,10 @@ namespace TriangleNet
rightvertex = searchtri.Dest();
leftvertex = searchtri.Apex();
// Is 'searchpoint' to the left?
- leftccw = Primitives.CounterClockwise(searchpoint.pt, startvertex.pt, leftvertex.pt);
+ leftccw = Primitives.CounterClockwise(searchpoint, startvertex, leftvertex);
leftflag = leftccw > 0.0;
// Is 'searchpoint' to the right?
- rightccw = Primitives.CounterClockwise(startvertex.pt, searchpoint.pt, rightvertex.pt);
+ rightccw = Primitives.CounterClockwise(startvertex, searchpoint, rightvertex);
rightflag = rightccw > 0.0;
if (leftflag && rightflag)
{
@@ -2433,7 +2416,7 @@ namespace TriangleNet
}
leftvertex = searchtri.Apex();
rightccw = leftccw;
- leftccw = Primitives.CounterClockwise(searchpoint.pt, startvertex.pt, leftvertex.pt);
+ leftccw = Primitives.CounterClockwise(searchpoint, startvertex, leftvertex);
leftflag = leftccw > 0.0;
}
while (rightflag)
@@ -2447,7 +2430,7 @@ namespace TriangleNet
}
rightvertex = searchtri.Dest();
leftccw = rightccw;
- rightccw = Primitives.CounterClockwise(startvertex.pt, searchpoint.pt, rightvertex.pt);
+ rightccw = Primitives.CounterClockwise(startvertex, searchpoint, rightvertex);
rightflag = rightccw > 0.0;
}
if (leftccw == 0.0)
@@ -2480,7 +2463,7 @@ namespace TriangleNet
/// On completion, splittri is a handle having the newly inserted
/// intersection point as its origin, and endpoint1 as its destination.
///
- void SegmentIntersection(ref Otri splittri, ref Osub splitsubseg, Vertex endpoint2)
+ private void SegmentIntersection(ref Otri splittri, ref Osub splitsubseg, Vertex endpoint2)
{
Osub opposubseg = default(Osub);
Vertex endpoint1;
@@ -2499,30 +2482,28 @@ namespace TriangleNet
torg = splittri.Org();
tdest = splittri.Dest();
// Segment intersection formulae; see the Antonio reference.
- tx = tdest.pt.X - torg.pt.X;
- ty = tdest.pt.Y - torg.pt.Y;
- ex = endpoint2.pt.X - endpoint1.pt.X;
- ey = endpoint2.pt.Y - endpoint1.pt.Y;
- etx = torg.pt.X - endpoint2.pt.X;
- ety = torg.pt.Y - endpoint2.pt.Y;
+ tx = tdest.x - torg.x;
+ ty = tdest.y - torg.y;
+ ex = endpoint2.x - endpoint1.x;
+ ey = endpoint2.y - endpoint1.y;
+ etx = torg.x - endpoint2.x;
+ ety = torg.y - endpoint2.y;
denom = ty * ex - tx * ey;
if (denom == 0.0)
{
- logger.Error("Attempt to find intersection of parallel segments.",
+ logger.Error("Attempt to find intersection of parallel segments.",
"Mesh.SegmentIntersection()");
throw new Exception("Attempt to find intersection of parallel segments.");
}
split = (ey * etx - ex * ety) / denom;
// Create the new vertex.
- newvertex = new Vertex(nextras); //(vertex) poolalloc(&m.vertices);
- vertices.Add(newvertex.Hash, newvertex);
- // Interpolate its coordinate and attributes.
- //for (i = 0; i < 2 + nextras; i++) {
- newvertex.pt.X = torg.pt.X + split * (tdest.pt.X - torg.pt.X);
- newvertex.pt.Y = torg.pt.Y + split * (tdest.pt.Y - torg.pt.Y);
-
- newvertex.mark = splitsubseg.ss.boundary;
- newvertex.type = VertexType.InputVertex;
+ newvertex = new Vertex(torg.x + split * (tdest.x - torg.x),
+ torg.y + split * (tdest.y - torg.y), splitsubseg.seg.boundary);
+ newvertex.hash = this.hash_vtx++;
+ newvertex.id = newvertex.hash;
+ // TODO: nextras //(vertex) poolalloc(&m.vertices);
+ // Interpolate its attributes.
+ vertices.Add(newvertex.hash, newvertex);
// Insert the intersection vertex. This should always succeed.
success = InsertVertex(newvertex, ref splittri, ref splitsubseg, false, false);
@@ -2547,23 +2528,23 @@ namespace TriangleNet
{
splitsubseg.SetSegOrg(newvertex);
splitsubseg.NextSelf();
- } while (splitsubseg.ss != Mesh.dummysub);
+ } while (splitsubseg.seg != Mesh.dummysub);
do
{
opposubseg.SetSegOrg(newvertex);
opposubseg.NextSelf();
- } while (opposubseg.ss != Mesh.dummysub);
+ } while (opposubseg.seg != Mesh.dummysub);
// Inserting the vertex may have caused edge flips. We wish to rediscover
// the edge connecting endpoint1 to the new intersection vertex.
collinear = FindDirection(ref splittri, endpoint1);
rightvertex = splittri.Dest();
leftvertex = splittri.Apex();
- if ((leftvertex.pt.X == endpoint1.pt.X) && (leftvertex.pt.Y == endpoint1.pt.Y))
+ if ((leftvertex.x == endpoint1.x) && (leftvertex.y == endpoint1.y))
{
splittri.OnextSelf();
}
- else if ((rightvertex.pt.X != endpoint1.pt.X) || (rightvertex.pt.Y != endpoint1.pt.Y))
+ else if ((rightvertex.x != endpoint1.x) || (rightvertex.y != endpoint1.y))
{
logger.Error("Topological inconsistency after splitting a segment.", "Mesh.SegmentIntersection()");
throw new Exception("Topological inconsistency after splitting a segment.");
@@ -2579,8 +2560,8 @@ namespace TriangleNet
///
///
///
- /// Returns one if the entire segment is successfully inserted, and zero
- /// if the job must be finished by conformingedge() or constrainededge().
+ /// Returns true if the entire segment is successfully inserted, and false
+ /// if the job must be finished by ConstrainedEdge().
///
/// If the first triangle on the path has the second endpoint as its
/// destination or apex, a subsegment is inserted and the job is done.
@@ -2594,7 +2575,7 @@ namespace TriangleNet
/// then there is a segment that intersects the segment being inserted.
/// Their intersection vertex is inserted, splitting the subsegment.
///
- bool ScoutSegment(ref Otri searchtri, Vertex endpoint2, int newmark)
+ private bool ScoutSegment(ref Otri searchtri, Vertex endpoint2, int newmark)
{
Otri crosstri = default(Otri);
Osub crosssubseg = default(Osub);
@@ -2604,11 +2585,11 @@ namespace TriangleNet
collinear = FindDirection(ref searchtri, endpoint2);
rightvertex = searchtri.Dest();
leftvertex = searchtri.Apex();
- if (((leftvertex.pt.X == endpoint2.pt.X) && (leftvertex.pt.Y == endpoint2.pt.Y)) ||
- ((rightvertex.pt.X == endpoint2.pt.X) && (rightvertex.pt.Y == endpoint2.pt.Y)))
+ if (((leftvertex.x == endpoint2.x) && (leftvertex.y == endpoint2.y)) ||
+ ((rightvertex.x == endpoint2.x) && (rightvertex.y == endpoint2.y)))
{
// The segment is already an edge in the mesh.
- if ((leftvertex.pt.X == endpoint2.pt.X) && (leftvertex.pt.Y == endpoint2.pt.Y))
+ if ((leftvertex.x == endpoint2.x) && (leftvertex.y == endpoint2.y))
{
searchtri.LprevSelf();
}
@@ -2639,7 +2620,7 @@ namespace TriangleNet
searchtri.Lnext(ref crosstri);
crosstri.SegPivot(ref crosssubseg);
// Check for a crossing segment.
- if (crosssubseg.ss == Mesh.dummysub)
+ if (crosssubseg.seg == Mesh.dummysub)
{
return false;
}
@@ -2655,121 +2636,26 @@ namespace TriangleNet
}
}
- /*
- ///
- /// Force a segment into a conforming Delaunay triangulation by inserting a
- /// vertex at its midpoint, and recursively forcing in the two half-segments
- /// if necessary.
- ///
- ///
- ///
- ///
- ///
- /// Generates a sequence of subsegments connecting 'endpoint1' to
- /// 'endpoint2'. 'newmark' is the boundary marker of the segment, assigned
- /// to each new splitting vertex and subsegment.
- ///
- /// Note that conformingedge() does not always maintain the conforming
- /// Delaunay property. Once inserted, segments are locked into place;
- /// vertices inserted later (to force other segments in) may render these
- /// fixed segments non-Delaunay. The conforming Delaunay property will be
- /// restored by enforcequality() by splitting encroached subsegments.
- ///
- void ConformingEdge(Vertex endpoint1, Vertex endpoint2, int newmark)
- {
- Otri searchtri1 = default(Otri), searchtri2 = default(Otri);
- Osub brokensubseg = default(Osub);
- Vertex newvertex;
- Vertex midvertex1, midvertex2;
- InsertVertexResult success;
- int i;
-
- // Create a new vertex to insert in the middle of the segment.
- //newvertex = (vertex) poolalloc(&m.vertices);
- newvertex = new Vertex(nextras);
- vertices.Add(newvertex.Hash, newvertex);
-
- // Interpolate coordinates and attributes.
- for (i = 0; i < 2 + nextras; i++)
- {
- //newvertex.pt[i] = 0.5 * (endpoint1.pt[i] + endpoint2.pt[i]);
- }
- newvertex.mark = newmark;
- newvertex.type = VertexType.SegmentVertex;
- // No known triangle to search from.
- searchtri1.triangle = Mesh.dummytri;
- // Attempt to insert the new vertex.
- Osub tmp = default(Osub);
- success = InsertVertex(newvertex, ref searchtri1, ref tmp, false, false);
- if (success == InsertVertexResult.Duplicate)
- {
- // Segment intersects existing vertex. Use the vertex that's already there.
- VertexDealloc(newvertex);
- newvertex = searchtri1.Org();
- }
- else
- {
- if (success == InsertVertexResult.Violating)
- {
- // Two segments intersect. By fluke, we've landed right on another segment. Split it.
- searchtri1.SegPivot(ref brokensubseg);
- success = InsertVertex(newvertex, ref searchtri1, ref brokensubseg, false, false);
- if (success != InsertVertexResult.Successful)
- {
- logger.Error("Failure to split a segment.", "Mesh.ConformingEdge()");
- throw new Exception("Failure to split a segment.");
- }
- }
- // The vertex has been inserted successfully.
- if (steinerleft > 0)
- {
- steinerleft--;
- }
- }
- searchtri1.Copy(ref searchtri2);
- // 'searchtri1' and 'searchtri2' are fastened at their origins to
- // 'newvertex', and will be directed toward 'endpoint1' and 'endpoint2'
- // respectively. First, we must get 'searchtri2' out of the way so it
- // won't be invalidated during the insertion of the first half of the
- // segment.
- FindDirection(ref searchtri2, endpoint2);
- if (!ScoutSegment(ref searchtri1, endpoint1, newmark))
- {
- // The origin of searchtri1 may have changed if a collision with an
- // intervening vertex on the segment occurred.
- midvertex1 = searchtri1.Org();
- ConformingEdge(midvertex1, endpoint1, newmark);
- }
- if (!ScoutSegment(ref searchtri2, endpoint2, newmark))
- {
- // The origin of searchtri2 may have changed if a collision with an
- // intervening vertex on the segment occurred.
- midvertex2 = searchtri2.Org();
- ConformingEdge(midvertex2, endpoint2, newmark);
- }
- }
- * */
-
///
/// Enforce the Delaunay condition at an edge, fanning out recursively from
/// an existing vertex. Pay special attention to stacking inverted triangles.
///
///
- /// indicates whether or not fixuptri is to the left of
- /// the segment being inserted. (Imagine that the segment is pointing up from
+ /// Indicates whether or not fixuptri is to the left of
+ /// the segment being inserted. (Imagine that the segment is pointing up from
/// endpoint1 to endpoint2.)
///
/// This is a support routine for inserting segments into a constrained
/// Delaunay triangulation.
///
/// The origin of fixuptri is treated as if it has just been inserted, and
- /// the local Delaunay condition needs to be enforced. It is only enforced
+ /// the local Delaunay condition needs to be enforced. It is only enforced
/// in one sector, however, that being the angular range defined by
/// fixuptri.
///
/// This routine also needs to make decisions regarding the "stacking" of
- /// triangles. (Read the description of constrainededge() below before
- /// reading on here, so you understand the algorithm.) If the position of
+ /// triangles. (Read the description of ConstrainedEdge() below before
+ /// reading on here, so you understand the algorithm.) If the position of
/// the new vertex (the origin of fixuptri) indicates that the vertex before
/// it on the polygon is a reflex vertex, then "stack" the triangle by
/// doing nothing. (fixuptri is an inverted triangle, which is how stacked
@@ -2777,7 +2663,7 @@ namespace TriangleNet
///
/// Otherwise, check whether the vertex before that was a reflex vertex.
/// If so, perform an edge flip, thereby eliminating an inverted triangle
- /// (popping it off the stack). The edge flip may result in the creation
+ /// (popping it off the stack). The edge flip may result in the creation
/// of a new inverted triangle, depending on whether or not the new vertex
/// is visible to the vertex three edges behind on the polygon.
///
@@ -2785,7 +2671,7 @@ namespace TriangleNet
/// vertices, fixuptri and fartri, the triangle opposite it, are not
/// inverted; hence, ensure that the edge between them is locally Delaunay.
///
- void DelaunayFixup(ref Otri fixuptri, bool leftside)
+ private void DelaunayFixup(ref Otri fixuptri, bool leftside)
{
Otri neartri = default(Otri);
Otri fartri = default(Otri);
@@ -2800,7 +2686,7 @@ namespace TriangleNet
return;
}
neartri.SegPivot(ref faredge);
- if (faredge.ss != Mesh.dummysub)
+ if (faredge.seg != Mesh.dummysub)
{
return;
}
@@ -2812,7 +2698,7 @@ namespace TriangleNet
// Check whether the previous polygon vertex is a reflex vertex.
if (leftside)
{
- if (Primitives.CounterClockwise(nearvertex.pt, leftvertex.pt, farvertex.pt) <= 0.0)
+ if (Primitives.CounterClockwise(nearvertex, leftvertex, farvertex) <= 0.0)
{
// leftvertex is a reflex vertex too. Nothing can
// be done until a convex section is found.
@@ -2821,20 +2707,20 @@ namespace TriangleNet
}
else
{
- if (Primitives.CounterClockwise(farvertex.pt, rightvertex.pt, nearvertex.pt) <= 0.0)
+ if (Primitives.CounterClockwise(farvertex, rightvertex, nearvertex) <= 0.0)
{
// rightvertex is a reflex vertex too. Nothing can
// be done until a convex section is found.
return;
}
}
- if (Primitives.CounterClockwise(rightvertex.pt, leftvertex.pt, farvertex.pt) > 0.0)
+ if (Primitives.CounterClockwise(rightvertex, leftvertex, farvertex) > 0.0)
{
// fartri is not an inverted triangle, and farvertex is not a reflex
// vertex. As there are no reflex vertices, fixuptri isn't an
// inverted triangle, either. Hence, test the edge between the
// triangles to ensure it is locally Delaunay.
- if (Primitives.InCircle(leftvertex.pt, farvertex.pt, rightvertex.pt, nearvertex.pt) <= 0.0)
+ if (Primitives.InCircle(leftvertex, farvertex, rightvertex, nearvertex) <= 0.0)
{
return;
}
@@ -2862,23 +2748,23 @@ namespace TriangleNet
/// boundary marker of the segment.
///
/// To insert a segment, every triangle whose interior intersects the
- /// segment is deleted. The union of these deleted triangles is a polygon
+ /// segment is deleted. The union of these deleted triangles is a polygon
/// (which is not necessarily monotone, but is close enough), which is
- /// divided into two polygons by the new segment. This routine's task is
+ /// divided into two polygons by the new segment. This routine's task is
/// to generate the Delaunay triangulation of these two polygons.
///
/// You might think of this routine's behavior as a two-step process. The
/// first step is to walk from endpoint1 to endpoint2, flipping each edge
/// encountered. This step creates a fan of edges connected to endpoint1,
- /// including the desired edge to endpoint2. The second step enforces the
+ /// including the desired edge to endpoint2. The second step enforces the
/// Delaunay condition on each side of the segment in an incremental manner:
/// proceeding along the polygon from endpoint1 to endpoint2 (this is done
/// independently on each side of the segment), each vertex is "enforced"
/// as if it had just been inserted, but affecting only the previous
- /// vertices. The result is the same as if the vertices had been inserted
+ /// vertices. The result is the same as if the vertices had been inserted
/// in the order they appear on the polygon, so the result is Delaunay.
///
- /// In truth, constrainededge() interleaves these two steps. The procedure
+ /// In truth, ConstrainedEdge() interleaves these two steps. The procedure
/// walks from endpoint1 to endpoint2, and each time an edge is encountered
/// and flipped, the newly exposed vertex (at the far end of the flipped
/// edge) is "enforced" upon the previously flipped edges, usually affecting
@@ -2888,21 +2774,21 @@ namespace TriangleNet
/// The algorithm is complicated by the need to handle polygons that are not
/// convex. Although the polygon is not necessarily monotone, it can be
/// triangulated in a manner similar to the stack-based algorithms for
- /// monotone polygons. For each reflex vertex (local concavity) of the
+ /// monotone polygons. For each reflex vertex (local concavity) of the
/// polygon, there will be an inverted triangle formed by one of the edge
- /// flips. (An inverted triangle is one with negative area - that is, its
+ /// flips. (An inverted triangle is one with negative area - that is, its
/// vertices are arranged in clockwise order - and is best thought of as a
/// wrinkle in the fabric of the mesh.) Each inverted triangle can be
/// thought of as a reflex vertex pushed on the stack, waiting to be fixed
/// later.
///
/// A reflex vertex is popped from the stack when a vertex is inserted that
- /// is visible to the reflex vertex. (However, if the vertex behind the
+ /// is visible to the reflex vertex. (However, if the vertex behind the
/// reflex vertex is not visible to the reflex vertex, a new inverted
- /// triangle will take its place on the stack.) These details are handled
- /// by the delaunayfixup() routine above.
+ /// triangle will take its place on the stack.) These details are handled
+ /// by the DelaunayFixup() routine above.
///
- void ConstrainedEdge(ref Otri starttri, Vertex endpoint2, int newmark)
+ private void ConstrainedEdge(ref Otri starttri, Vertex endpoint2, int newmark)
{
Otri fixuptri = default(Otri), fixuptri2 = default(Otri);
Osub crosssubseg = default(Osub);
@@ -2923,8 +2809,8 @@ namespace TriangleNet
{
farvertex = fixuptri.Org();
// 'farvertex' is the extreme point of the polygon we are "digging"
- // to get from endpoint1 to endpoint2.
- if ((farvertex.pt.X == endpoint2.pt.X) && (farvertex.pt.Y == endpoint2.pt.Y))
+ // to get from endpoint1 to endpoint2.
+ if ((farvertex.x == endpoint2.x) && (farvertex.y == endpoint2.y))
{
fixuptri.Oprev(ref fixuptri2);
// Enforce the Delaunay condition around endpoint2.
@@ -2934,10 +2820,9 @@ namespace TriangleNet
}
else
{
- // Check whether farvertex is to the left or right of the segment
- // being inserted, to decide which edge of fixuptri to dig
- // through next.
- area = Primitives.CounterClockwise(endpoint1.pt, endpoint2.pt, farvertex.pt);
+ // Check whether farvertex is to the left or right of the segment being
+ // inserted, to decide which edge of fixuptri to dig through next.
+ area = Primitives.CounterClockwise(endpoint1, endpoint2, farvertex);
if (area == 0.0)
{
// We've collided with a vertex between endpoint1 and endpoint2.
@@ -2951,7 +2836,8 @@ namespace TriangleNet
else
{
if (area > 0.0)
- { // farvertex is to the left of the segment.
+ {
+ // farvertex is to the left of the segment.
fixuptri.Oprev(ref fixuptri2);
// Enforce the Delaunay condition around farvertex, on the
// left side of the segment only.
@@ -2962,7 +2848,8 @@ namespace TriangleNet
fixuptri.LprevSelf();
}
else
- { // farvertex is to the right of the segment.
+ {
+ // farvertex is to the right of the segment.
DelaunayFixup(ref fixuptri, false);
// Flip the edge that crosses the segment. After the edge is
// flipped, one of its endpoints is the fan vertex, and the
@@ -2971,7 +2858,7 @@ namespace TriangleNet
}
// Check for two intersecting segments.
fixuptri.SegPivot(ref crosssubseg);
- if (crosssubseg.ss == Mesh.dummysub)
+ if (crosssubseg.seg == Mesh.dummysub)
{
Flip(ref fixuptri); // May create inverted triangle at left.
}
@@ -3006,7 +2893,7 @@ namespace TriangleNet
///
///
///
- void InsertSegment(Vertex endpoint1, Vertex endpoint2, int newmark)
+ private void InsertSegment(Vertex endpoint1, Vertex endpoint2, int newmark)
{
Otri searchtri1 = default(Otri), searchtri2 = default(Otri);
Vertex checkvertex = null;
@@ -3025,7 +2912,7 @@ namespace TriangleNet
searchtri1.orient = 0;
searchtri1.SymSelf();
// Search for the segment's first endpoint by point location.
- if (Locate(endpoint1.pt, ref searchtri1) != LocateResult.OnVertex)
+ if (Locate(endpoint1, ref searchtri1) != LocateResult.OnVertex)
{
logger.Error("Unable to locate PSLG vertex in triangulation.", "Mesh.InsertSegment().1");
throw new Exception("Unable to locate PSLG vertex in triangulation.");
@@ -3059,7 +2946,7 @@ namespace TriangleNet
searchtri2.orient = 0;
searchtri2.SymSelf();
// Search for the segment's second endpoint by point location.
- if (Locate(endpoint2.pt, ref searchtri2) != LocateResult.OnVertex)
+ if (Locate(endpoint2, ref searchtri2) != LocateResult.OnVertex)
{
logger.Error("Unable to locate PSLG vertex in triangulation.", "Mesh.InsertSegment().2");
throw new Exception("Unable to locate PSLG vertex in triangulation.");
@@ -3078,13 +2965,6 @@ namespace TriangleNet
// vertex on the segment occurred.
endpoint2 = searchtri2.Org();
- //if (Behavior.SplitSeg)
- //{
- // // Insert vertices to force the segment into the triangulation.
- // ConformingEdge(endpoint1, endpoint2, newmark);
- //}
- //else
-
// Insert the segment directly into the triangulation.
ConstrainedEdge(ref searchtri1, endpoint2, newmark);
}
@@ -3092,7 +2972,7 @@ namespace TriangleNet
///
/// Cover the convex hull of a triangulation with subsegments.
///
- void MarkHull()
+ private void MarkHull()
{
Otri hulltri = default(Otri);
Otri nexttri = default(Otri);
@@ -3127,19 +3007,16 @@ namespace TriangleNet
///
///
///
- void FormSkeleton(MeshData data)
+ private void FormSkeleton(InputGeometry input)
{
Vertex endpoint1, endpoint2;
- bool segmentmarkers;
int end1, end2;
int boundmarker;
- int numberofsegments = data.Segments == null ? 0 : data.Segments.Length;
+
+ this.insegments = 0;
if (Behavior.Poly)
{
- insegments = numberofsegments;
- segmentmarkers = data.SegmentMarkers != null;
-
// If the input vertices are collinear, there is no triangulation,
// so don't try to insert segments.
if (triangles.Count == 0)
@@ -3149,21 +3026,21 @@ namespace TriangleNet
// If segments are to be inserted, compute a mapping
// from vertices to triangles.
- if (insegments > 0)
+ if (input.HasSegments)
{
MakeVertexMap();
}
boundmarker = 0;
+
// Read and insert the segments.
- for (int i = 0; i < insegments; i++)
+ foreach (var seg in input.segments)
{
- end1 = data.Segments[i][0];
- end2 = data.Segments[i][1];
- if (segmentmarkers)
- {
- boundmarker = data.SegmentMarkers[i];
- }
+ this.insegments++;
+
+ end1 = seg.P0;
+ end2 = seg.P1;
+ boundmarker = seg.Boundary;
if ((end1 < 0) || (end1 >= invertices))
{
@@ -3185,9 +3062,9 @@ namespace TriangleNet
// It should be. The ID gets appropriately set in TransferNodes().
// Find the vertices numbered 'end1' and 'end2'.
- endpoint1 = vertices[end1]; // getvertex(end1);
- endpoint2 = vertices[end2]; // getvertex(end2);
- if ((endpoint1.pt.X == endpoint2.pt.X) && (endpoint1.pt.Y == endpoint2.pt.Y))
+ endpoint1 = vertices[end1];
+ endpoint2 = vertices[end2];
+ if ((endpoint1.x == endpoint2.x) && (endpoint1.y == endpoint2.y))
{
if (Behavior.Verbose)
{
@@ -3201,10 +3078,6 @@ namespace TriangleNet
}
}
}
- else
- {
- insegments = 0;
- }
if (Behavior.Convex || !Behavior.Poly)
{
@@ -3223,10 +3096,10 @@ namespace TriangleNet
///
internal void TriangleDealloc(Triangle dyingtriangle)
{
- // Mark the triangle as dead. This makes it possible to detect dead
+ // 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.Remove(dyingtriangle.hash);
}
///
@@ -3235,22 +3108,22 @@ namespace TriangleNet
///
internal void VertexDealloc(Vertex dyingvertex)
{
- // Mark the vertex as dead. This makes it possible to detect dead
+ // Mark the vertex as dead. This makes it possible to detect dead
// vertices when traversing the list of all vertices.
dyingvertex.type = VertexType.DeadVertex;
- vertices.Remove(dyingvertex.Hash);
+ vertices.Remove(dyingvertex.hash);
}
///
/// Deallocate space for a subsegment, marking it dead.
///
///
- internal void SubsegDealloc(Subseg dyingsubseg)
+ internal void SubsegDealloc(Segment dyingsubseg)
{
- // Mark the subsegment as dead. This makes it possible to detect dead
+ // Mark the subsegment as dead. This makes it possible to detect dead
// subsegments when traversing the list of all subsegments.
Osub.Kill(dyingsubseg);
- subsegs.Remove(dyingsubseg.Hash);
+ subsegs.Remove(dyingsubseg.hash);
}
#endregion
diff --git a/Triangle.NET/Triangle/NewLocation.cs b/Triangle.NET/Triangle/NewLocation.cs
index 0967532..c4cf09f 100644
--- a/Triangle.NET/Triangle/NewLocation.cs
+++ b/Triangle.NET/Triangle/NewLocation.cs
@@ -9,6 +9,8 @@ namespace TriangleNet
{
using System;
using TriangleNet.Data;
+ using TriangleNet.Geometry;
+ using TriangleNet.Tools;
///
/// Find new Steiner Point locations.
@@ -78,12 +80,12 @@ namespace TriangleNet
double shortestEdgeDist = 0, middleEdgeDist = 0, longestEdgeDist = 0;
// keeps the vertices according to the angle incident to that vertex in a triangle
- Point2 smallestAngleCorner, middleAngleCorner, largestAngleCorner;
+ Point smallestAngleCorner, middleAngleCorner, largestAngleCorner;
// keeps the type of orientation if the triangle
int orientation = 0;
// keeps the coordinates of circumcenter of itself and neighbor triangle circumcenter
- Point2 myCircumcenter = default(Point2), neighborCircumcenter = default(Point2);
+ Point myCircumcenter = default(Point), neighborCircumcenter = default(Point);
// keeps if bad triangle is almost good or not
int almostGood = 0;
@@ -132,17 +134,17 @@ namespace TriangleNet
Statistic.CircumcenterCount++;
// Compute the circumcenter of the triangle.
- xdo = tdest.pt.X - torg.pt.X;
- ydo = tdest.pt.Y - torg.pt.Y;
- xao = tapex.pt.X - torg.pt.X;
- yao = tapex.pt.Y - torg.pt.Y;
- xda = tapex.pt.X - tdest.pt.X;
- yda = tapex.pt.Y - tdest.pt.Y;
+ xdo = tdest.x - torg.x;
+ ydo = tdest.y - torg.y;
+ xao = tapex.x - torg.x;
+ yao = tapex.y - torg.y;
+ xda = tapex.x - tdest.x;
+ yda = tapex.y - tdest.y;
// keeps the square of the distances
dodist = xdo * xdo + ydo * ydo;
aodist = xao * xao + yao * yao;
- dadist = (tdest.pt.X - tapex.pt.X) * (tdest.pt.X - tapex.pt.X) +
- (tdest.pt.Y - tapex.pt.Y) * (tdest.pt.Y - tapex.pt.Y);
+ dadist = (tdest.x - tapex.x) * (tdest.x - tapex.x) +
+ (tdest.y - tapex.y) * (tdest.y - tapex.y);
// checking if the user wanted exact arithmetic or not
if (Behavior.NoExact)
{
@@ -153,7 +155,7 @@ namespace TriangleNet
// Use the counterclockwise() routine to ensure a positive (and
// reasonably accurate) result, avoiding any possibility of
// division by zero.
- denominator = 0.5 / Primitives.CounterClockwise(tdest.pt, tapex.pt, torg.pt);
+ denominator = 0.5 / Primitives.CounterClockwise(tdest, tapex, torg);
// Don't count the above as an orientation test.
Statistic.CounterClockwiseCount--;
}
@@ -162,8 +164,8 @@ namespace TriangleNet
dy = (xdo * aodist - xao * dodist) * denominator;
// for debugging and for keeping circumcenter to use later
// coordinate value of the circumcenter
- myCircumcenter.X = torg.pt.X + dx;
- myCircumcenter.Y = torg.pt.Y + dy;
+ myCircumcenter.x = torg.x + dx;
+ myCircumcenter.y = torg.y + dy;
delotri = badotri; // save for later
///////////////// FINDING THE ORIENTATION OF TRIANGLE //////////////////
@@ -197,9 +199,9 @@ namespace TriangleNet
middleEdgeDist = dadist;
longestEdgeDist = dodist;
- smallestAngleCorner = tdest.pt;
- middleAngleCorner = torg.pt;
- largestAngleCorner = tapex.pt;
+ smallestAngleCorner = tdest;
+ middleAngleCorner = torg;
+ largestAngleCorner = tapex;
break;
case 132: // assign necessary information
@@ -213,9 +215,9 @@ namespace TriangleNet
middleEdgeDist = dodist;
longestEdgeDist = dadist;
- smallestAngleCorner = tdest.pt;
- middleAngleCorner = tapex.pt;
- largestAngleCorner = torg.pt;
+ smallestAngleCorner = tdest;
+ middleAngleCorner = tapex;
+ largestAngleCorner = torg;
break;
case 213: // assign necessary information
@@ -229,9 +231,9 @@ namespace TriangleNet
middleEdgeDist = aodist;
longestEdgeDist = dodist;
- smallestAngleCorner = torg.pt;
- middleAngleCorner = tdest.pt;
- largestAngleCorner = tapex.pt;
+ smallestAngleCorner = torg;
+ middleAngleCorner = tdest;
+ largestAngleCorner = tapex;
break;
case 231: // assign necessary information
/// smallest angle corner: org
@@ -244,9 +246,9 @@ namespace TriangleNet
middleEdgeDist = dodist;
longestEdgeDist = aodist;
- smallestAngleCorner = torg.pt;
- middleAngleCorner = tapex.pt;
- largestAngleCorner = tdest.pt;
+ smallestAngleCorner = torg;
+ middleAngleCorner = tapex;
+ largestAngleCorner = tdest;
break;
case 312: // assign necessary information
/// smallest angle corner: apex
@@ -259,9 +261,9 @@ namespace TriangleNet
middleEdgeDist = aodist;
longestEdgeDist = dadist;
- smallestAngleCorner = tapex.pt;
- middleAngleCorner = tdest.pt;
- largestAngleCorner = torg.pt;
+ smallestAngleCorner = tapex;
+ middleAngleCorner = tdest;
+ largestAngleCorner = torg;
break;
case 321: // assign necessary information
default: // TODO: is this safe?
@@ -275,9 +277,9 @@ namespace TriangleNet
middleEdgeDist = dadist;
longestEdgeDist = aodist;
- smallestAngleCorner = tapex.pt;
- middleAngleCorner = torg.pt;
- largestAngleCorner = tdest.pt;
+ smallestAngleCorner = tapex;
+ middleAngleCorner = torg;
+ largestAngleCorner = tdest;
break;
}// end of switch
@@ -375,10 +377,10 @@ namespace TriangleNet
{
Statistic.RelocationCount++;
- dx = newloc[0] - torg.pt.X;
- dy = newloc[1] - torg.pt.Y;
- origin_x = torg.pt.X; // keep for later use
- origin_y = torg.pt.Y;
+ dx = newloc[0] - torg.x;
+ dy = newloc[1] - torg.y;
+ origin_x = torg.x; // keep for later use
+ origin_y = torg.y;
switch (relocated)
{
case 1:
@@ -407,24 +409,24 @@ namespace TriangleNet
/// compute two possible centers of the petal ///
// finding the center
// first find the middle point of smallest edge
- xMidOfShortestEdge = (middleAngleCorner.X + largestAngleCorner.X) / 2.0;
- yMidOfShortestEdge = (middleAngleCorner.Y + largestAngleCorner.Y) / 2.0;
+ xMidOfShortestEdge = (middleAngleCorner.x + largestAngleCorner.x) / 2.0;
+ yMidOfShortestEdge = (middleAngleCorner.y + largestAngleCorner.y) / 2.0;
// two possible centers
- xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.Y -
- largestAngleCorner.Y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.X -
- middleAngleCorner.X) / Math.Sqrt(shortestEdgeDist);
+ xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
+ largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
+ yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
+ middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
- xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.Y -
- largestAngleCorner.Y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.X -
- middleAngleCorner.X) / Math.Sqrt(shortestEdgeDist);
+ xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
+ largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
+ yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
+ middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
// find the correct circle since there will be two possible circles
// calculate the distance to smallest angle corner
- dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.X) * (xPetalCtr_1 - smallestAngleCorner.X);
- dycenter1 = (yPetalCtr_1 - smallestAngleCorner.Y) * (yPetalCtr_1 - smallestAngleCorner.Y);
- dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.X) * (xPetalCtr_2 - smallestAngleCorner.X);
- dycenter2 = (yPetalCtr_2 - smallestAngleCorner.Y) * (yPetalCtr_2 - smallestAngleCorner.Y);
+ dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.x) * (xPetalCtr_1 - smallestAngleCorner.x);
+ dycenter1 = (yPetalCtr_1 - smallestAngleCorner.y) * (yPetalCtr_1 - smallestAngleCorner.y);
+ dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.x) * (xPetalCtr_2 - smallestAngleCorner.x);
+ dycenter2 = (yPetalCtr_2 - smallestAngleCorner.y) * (yPetalCtr_2 - smallestAngleCorner.y);
// whichever is closer to smallest angle corner, it must be the center
if (dxcenter1 + dycenter1 <= dxcenter2 + dycenter2)
@@ -437,8 +439,8 @@ namespace TriangleNet
}
/// find the third point of the neighbor triangle ///
- neighborNotFound = GetNeighborsVertex(m, badotri, middleAngleCorner.X, middleAngleCorner.Y,
- smallestAngleCorner.X, smallestAngleCorner.Y, ref thirdPoint, ref neighborotri);
+ neighborNotFound = GetNeighborsVertex(m, badotri, middleAngleCorner.x, middleAngleCorner.y,
+ smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
/// find the circumcenter of the neighbor triangle ///
dxFirstSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
dyFirstSuggestion = dy;
@@ -449,26 +451,26 @@ namespace TriangleNet
neighborvertex_2 = neighborotri.Dest();
neighborvertex_3 = neighborotri.Apex();
// now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1.pt, neighborvertex_2.pt, neighborvertex_3.pt, ref xi_tmp, ref eta_tmp, false);
+ neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3, ref xi_tmp, ref eta_tmp, false);
/// compute petal and Voronoi edge intersection ///
// in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (middleAngleCorner.Y - smallestAngleCorner.Y);//(-y, x)
- vector_y = smallestAngleCorner.X - middleAngleCorner.X;
- vector_x = myCircumcenter.X + vector_x;
- vector_y = myCircumcenter.Y + vector_y;
+ vector_x = (middleAngleCorner.y - smallestAngleCorner.y);//(-y, x)
+ vector_y = smallestAngleCorner.x - middleAngleCorner.x;
+ vector_x = myCircumcenter.x + vector_x;
+ vector_y = myCircumcenter.y + vector_y;
// by intersecting bisectors you will end up with the one you want to walk on
// then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.X, myCircumcenter.Y, vector_x, vector_y,
+ CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
xPetalCtr, yPetalCtr, petalRadius, ref p);
/// choose the correct intersection point ///
// calculate middle point of the longest edge(bisector)
- xMidOfLongestEdge = (middleAngleCorner.X + smallestAngleCorner.X) / 2.0;
- yMidOfLongestEdge = (middleAngleCorner.Y + smallestAngleCorner.Y) / 2.0;
+ xMidOfLongestEdge = (middleAngleCorner.x + smallestAngleCorner.x) / 2.0;
+ yMidOfLongestEdge = (middleAngleCorner.y + smallestAngleCorner.y) / 2.0;
// we need to find correct intersection point, since line intersects circle twice
isCorrect = ChooseCorrectPoint(xMidOfLongestEdge, yMidOfLongestEdge, p[3], p[4],
- myCircumcenter.X, myCircumcenter.Y, isObtuse);
+ myCircumcenter.x, myCircumcenter.y, isObtuse);
// make sure which point is the correct one to be considered
if (isCorrect)
{
@@ -482,8 +484,8 @@ namespace TriangleNet
}
/// check if there is a Voronoi vertex between before intersection ///
// check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.X, myCircumcenter.Y,
- neighborCircumcenter.X, neighborCircumcenter.Y, ref voronoiOrInter);
+ PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
+ neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
/// determine the point to be suggested ///
if (p[0] > 0.0)
@@ -492,7 +494,7 @@ namespace TriangleNet
// if it returns 1.0 this means we have a voronoi vertex within feasible region
if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
{
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, neighborCircumcenter.X, neighborCircumcenter.Y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
{
// go back to circumcenter
dxFirstSuggestion = dx;
@@ -502,30 +504,30 @@ namespace TriangleNet
else
{ // we are not creating a bad triangle
// neighbor's circumcenter is suggested
- dxFirstSuggestion = voronoiOrInter[2] - torg.pt.X;
- dyFirstSuggestion = voronoiOrInter[3] - torg.pt.Y;
+ dxFirstSuggestion = voronoiOrInter[2] - torg.x;
+ dyFirstSuggestion = voronoiOrInter[3] - torg.y;
}
}
else
{ // there is no voronoi vertex between intersection point and circumcenter
- if (IsBadTriangleAngle(largestAngleCorner.X, largestAngleCorner.Y, middleAngleCorner.X, middleAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, inter_x, inter_y))
{
// if it is inside feasible region, then insert v2
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.X) * (inter_x - myCircumcenter.X) +
- (inter_y - myCircumcenter.Y) * (inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
+ (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - inter_x;
- ay = myCircumcenter.Y - inter_y;
+ ax = myCircumcenter.x - inter_x;
+ ay = myCircumcenter.y - inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
{
// go back to circumcenter
dxFirstSuggestion = dx;
@@ -535,26 +537,26 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxFirstSuggestion = inter_x - torg.pt.X;
- dyFirstSuggestion = inter_y - torg.pt.Y;
+ dxFirstSuggestion = inter_x - torg.x;
+ dyFirstSuggestion = inter_y - torg.y;
}
}
else
{
// intersection point is suggested
- dxFirstSuggestion = inter_x - torg.pt.X;
- dyFirstSuggestion = inter_y - torg.pt.Y;
+ dxFirstSuggestion = inter_x - torg.x;
+ dyFirstSuggestion = inter_y - torg.y;
}
}
/// if it is an acute triangle, check if it is a good enough location ///
// for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.X - myCircumcenter.X) * (smallestAngleCorner.X - myCircumcenter.X) +
- (smallestAngleCorner.Y - myCircumcenter.Y) * (smallestAngleCorner.Y - myCircumcenter.Y) >
- lengthConst * ((smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y))))
+ if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
+ (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
+ lengthConst * ((smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y))))
{
// use circumcenter
dxFirstSuggestion = dx;
@@ -566,8 +568,8 @@ namespace TriangleNet
/// DO THE SAME THING FOR THE OTHER DIRECTION ///
/// find the third point of the neighbor triangle ///
- neighborNotFound = GetNeighborsVertex(m, badotri, largestAngleCorner.X, largestAngleCorner.Y,
- smallestAngleCorner.X, smallestAngleCorner.Y, ref thirdPoint, ref neighborotri);
+ neighborNotFound = GetNeighborsVertex(m, badotri, largestAngleCorner.x, largestAngleCorner.y,
+ smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
/// find the circumcenter of the neighbor triangle ///
dxSecondSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
dySecondSuggestion = dy;
@@ -578,29 +580,29 @@ namespace TriangleNet
neighborvertex_2 = neighborotri.Dest();
neighborvertex_3 = neighborotri.Apex();
// now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1.pt, neighborvertex_2.pt, neighborvertex_3.pt, ref xi_tmp, ref eta_tmp, false);
+ neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3, ref xi_tmp, ref eta_tmp, false);
/// compute petal and Voronoi edge intersection ///
// in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (largestAngleCorner.Y - smallestAngleCorner.Y);//(-y, x)
- vector_y = smallestAngleCorner.X - largestAngleCorner.X;
- vector_x = myCircumcenter.X + vector_x;
- vector_y = myCircumcenter.Y + vector_y;
+ vector_x = (largestAngleCorner.y - smallestAngleCorner.y);//(-y, x)
+ vector_y = smallestAngleCorner.x - largestAngleCorner.x;
+ vector_x = myCircumcenter.x + vector_x;
+ vector_y = myCircumcenter.y + vector_y;
// by intersecting bisectors you will end up with the one you want to walk on
// then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.X, myCircumcenter.Y, vector_x, vector_y,
+ CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
xPetalCtr, yPetalCtr, petalRadius, ref p);
/// choose the correct intersection point ///
// calcuwedgeslate middle point of the longest edge(bisector)
- xMidOfMiddleEdge = (largestAngleCorner.X + smallestAngleCorner.X) / 2.0;
- yMidOfMiddleEdge = (largestAngleCorner.Y + smallestAngleCorner.Y) / 2.0;
+ xMidOfMiddleEdge = (largestAngleCorner.x + smallestAngleCorner.x) / 2.0;
+ yMidOfMiddleEdge = (largestAngleCorner.y + smallestAngleCorner.y) / 2.0;
// we need to find correct intersection point, since line intersects circle twice
// this direction is always ACUTE
isCorrect = ChooseCorrectPoint(xMidOfMiddleEdge, yMidOfMiddleEdge, p[3], p[4],
- myCircumcenter.X, myCircumcenter.Y, false/*(isObtuse+1)%2*/);
+ myCircumcenter.x, myCircumcenter.y, false/*(isObtuse+1)%2*/);
// make sure which point is the correct one to be considered
if (isCorrect)
{
@@ -615,8 +617,8 @@ namespace TriangleNet
/// check if there is a Voronoi vertex between before intersection ///
// check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.X, myCircumcenter.Y,
- neighborCircumcenter.X, neighborCircumcenter.Y, ref voronoiOrInter);
+ PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
+ neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
/// determine the point to be suggested ///
if (p[0] > 0.0)
@@ -625,7 +627,7 @@ namespace TriangleNet
// if it returns 1.0 this means we have a voronoi vertex within feasible region
if (Math.Abs(voronoiOrInter[0] - 1.0) <= EPS)
{
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, neighborCircumcenter.X, neighborCircumcenter.Y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
{
// go back to circumcenter
dxSecondSuggestion = dx;
@@ -635,31 +637,31 @@ namespace TriangleNet
else
{ // we are not creating a bad triangle
// neighbor's circumcenter is suggested
- dxSecondSuggestion = voronoiOrInter[2] - torg.pt.X;
- dySecondSuggestion = voronoiOrInter[3] - torg.pt.Y;
+ dxSecondSuggestion = voronoiOrInter[2] - torg.x;
+ dySecondSuggestion = voronoiOrInter[3] - torg.y;
}
}
else
{ // there is no voronoi vertex between intersection point and circumcenter
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
{
// if it is inside feasible region, then insert v2
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.X) * (inter_x - myCircumcenter.X) +
- (inter_y - myCircumcenter.Y) * (inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
+ (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - inter_x;
- ay = myCircumcenter.Y - inter_y;
+ ax = myCircumcenter.x - inter_x;
+ ay = myCircumcenter.y - inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
{
// go back to circumcenter
dxSecondSuggestion = dx;
@@ -669,26 +671,26 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxSecondSuggestion = inter_x - torg.pt.X;
- dySecondSuggestion = inter_y - torg.pt.Y;
+ dxSecondSuggestion = inter_x - torg.x;
+ dySecondSuggestion = inter_y - torg.y;
}
}
else
{
// intersection point is suggested
- dxSecondSuggestion = inter_x - torg.pt.X;
- dySecondSuggestion = inter_y - torg.pt.Y;
+ dxSecondSuggestion = inter_x - torg.x;
+ dySecondSuggestion = inter_y - torg.y;
}
}
/// if it is an acute triangle, check if it is a good enough location ///
// for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.X - myCircumcenter.X) * (smallestAngleCorner.X - myCircumcenter.X) +
- (smallestAngleCorner.Y - myCircumcenter.Y) * (smallestAngleCorner.Y - myCircumcenter.Y) >
- lengthConst * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))))
+ if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
+ (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
+ lengthConst * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))))
{
// use circumcenter
dxSecondSuggestion = dx;
@@ -704,14 +706,14 @@ namespace TriangleNet
}
else
{ // acute : consider other direction
- if (justAcute * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))) >
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)))
+ if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -728,13 +730,13 @@ namespace TriangleNet
if (relocated <= 0)
{
- circumcenter.pt.X = torg.pt.X + dx;
- circumcenter.pt.Y = torg.pt.Y + dy;
+ circumcenter.x = torg.x + dx;
+ circumcenter.y = torg.y + dy;
}
else
{
- circumcenter.pt.X = origin_x + dx;
- circumcenter.pt.Y = origin_y + dy;
+ circumcenter.x = origin_x + dx;
+ circumcenter.y = origin_y + dy;
}
xi = (yao * dx - xao * dy) * (2.0 * denominator);
@@ -774,12 +776,12 @@ namespace TriangleNet
double shortestEdgeDist = 0, middleEdgeDist = 0, longestEdgeDist = 0;
// keeps the vertices according to the angle incident to that vertex in a triangle
- Point2 smallestAngleCorner, middleAngleCorner, largestAngleCorner;
+ Point smallestAngleCorner, middleAngleCorner, largestAngleCorner;
// keeps the type of orientation if the triangle
int orientation = 0;
// keeps the coordinates of circumcenter of itself and neighbor triangle circumcenter
- Point2 myCircumcenter, neighborCircumcenter;
+ Point myCircumcenter, neighborCircumcenter;
// keeps if bad triangle is almost good or not
int almostGood = 0;
@@ -841,17 +843,17 @@ namespace TriangleNet
Statistic.CircumcenterCount++;
// Compute the circumcenter of the triangle.
- xdo = tdest.pt.X - torg.pt.X;
- ydo = tdest.pt.Y - torg.pt.Y;
- xao = tapex.pt.X - torg.pt.X;
- yao = tapex.pt.Y - torg.pt.Y;
- xda = tapex.pt.X - tdest.pt.X;
- yda = tapex.pt.Y - tdest.pt.Y;
+ xdo = tdest.x - torg.x;
+ ydo = tdest.y - torg.y;
+ xao = tapex.x - torg.x;
+ yao = tapex.y - torg.y;
+ xda = tapex.x - tdest.x;
+ yda = tapex.y - tdest.y;
// keeps the square of the distances
dodist = xdo * xdo + ydo * ydo;
aodist = xao * xao + yao * yao;
- dadist = (tdest.pt.X - tapex.pt.X) * (tdest.pt.X - tapex.pt.X) +
- (tdest.pt.Y - tapex.pt.Y) * (tdest.pt.Y - tapex.pt.Y);
+ dadist = (tdest.x - tapex.x) * (tdest.x - tapex.x) +
+ (tdest.y - tapex.y) * (tdest.y - tapex.y);
// checking if the user wanted exact arithmetic or not
if (Behavior.NoExact)
{
@@ -862,7 +864,7 @@ namespace TriangleNet
// Use the counterclockwise() routine to ensure a positive (and
// reasonably accurate) result, avoiding any possibility of
// division by zero.
- denominator = 0.5 / Primitives.CounterClockwise(tdest.pt, tapex.pt, torg.pt);
+ denominator = 0.5 / Primitives.CounterClockwise(tdest, tapex, torg);
// Don't count the above as an orientation test.
Statistic.CounterClockwiseCount--;
}
@@ -871,8 +873,7 @@ namespace TriangleNet
dy = (xdo * aodist - xao * dodist) * denominator;
// for debugging and for keeping circumcenter to use later
// coordinate value of the circumcenter
- myCircumcenter.X = torg.pt.X + dx;
- myCircumcenter.Y = torg.pt.Y + dy;
+ myCircumcenter = new Point(torg.x + dx, torg.y + dy);
delotri = badotri; // save for later
///////////////// FINDING THE ORIENTATION OF TRIANGLE //////////////////
@@ -906,9 +907,9 @@ namespace TriangleNet
middleEdgeDist = dadist;
longestEdgeDist = dodist;
- smallestAngleCorner = tdest.pt;
- middleAngleCorner = torg.pt;
- largestAngleCorner = tapex.pt;
+ smallestAngleCorner = tdest;
+ middleAngleCorner = torg;
+ largestAngleCorner = tapex;
break;
case 132: // assign necessary information
@@ -922,9 +923,9 @@ namespace TriangleNet
middleEdgeDist = dodist;
longestEdgeDist = dadist;
- smallestAngleCorner = tdest.pt;
- middleAngleCorner = tapex.pt;
- largestAngleCorner = torg.pt;
+ smallestAngleCorner = tdest;
+ middleAngleCorner = tapex;
+ largestAngleCorner = torg;
break;
case 213: // assign necessary information
@@ -938,9 +939,9 @@ namespace TriangleNet
middleEdgeDist = aodist;
longestEdgeDist = dodist;
- smallestAngleCorner = torg.pt;
- middleAngleCorner = tdest.pt;
- largestAngleCorner = tapex.pt;
+ smallestAngleCorner = torg;
+ middleAngleCorner = tdest;
+ largestAngleCorner = tapex;
break;
case 231: // assign necessary information
/// smallest angle corner: org
@@ -953,9 +954,9 @@ namespace TriangleNet
middleEdgeDist = dodist;
longestEdgeDist = aodist;
- smallestAngleCorner = torg.pt;
- middleAngleCorner = tapex.pt;
- largestAngleCorner = tdest.pt;
+ smallestAngleCorner = torg;
+ middleAngleCorner = tapex;
+ largestAngleCorner = tdest;
break;
case 312: // assign necessary information
/// smallest angle corner: apex
@@ -968,9 +969,9 @@ namespace TriangleNet
middleEdgeDist = aodist;
longestEdgeDist = dadist;
- smallestAngleCorner = tapex.pt;
- middleAngleCorner = tdest.pt;
- largestAngleCorner = torg.pt;
+ smallestAngleCorner = tapex;
+ middleAngleCorner = tdest;
+ largestAngleCorner = torg;
break;
case 321: // assign necessary information
default: // TODO: is this safe?
@@ -984,9 +985,9 @@ namespace TriangleNet
middleEdgeDist = dadist;
longestEdgeDist = aodist;
- smallestAngleCorner = tapex.pt;
- middleAngleCorner = torg.pt;
- largestAngleCorner = tdest.pt;
+ smallestAngleCorner = tapex;
+ middleAngleCorner = torg;
+ largestAngleCorner = tdest;
break;
}// end of switch
@@ -1084,10 +1085,10 @@ namespace TriangleNet
{
Statistic.RelocationCount++;
- dx = newloc[0] - torg.pt.X;
- dy = newloc[1] - torg.pt.Y;
- origin_x = torg.pt.X; // keep for later use
- origin_y = torg.pt.Y;
+ dx = newloc[0] - torg.x;
+ dy = newloc[1] - torg.y;
+ origin_x = torg.x; // keep for later use
+ origin_y = torg.y;
switch (relocated)
{
case 1:
@@ -1125,24 +1126,24 @@ namespace TriangleNet
/// compute two possible centers of the petal ///
// finding the center
// first find the middle point of smallest edge
- xMidOfShortestEdge = (middleAngleCorner.X + largestAngleCorner.X) / 2.0;
- yMidOfShortestEdge = (middleAngleCorner.Y + largestAngleCorner.Y) / 2.0;
+ xMidOfShortestEdge = (middleAngleCorner.x + largestAngleCorner.x) / 2.0;
+ yMidOfShortestEdge = (middleAngleCorner.y + largestAngleCorner.y) / 2.0;
// two possible centers
- xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.Y -
- largestAngleCorner.Y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.X -
- middleAngleCorner.X) / Math.Sqrt(shortestEdgeDist);
+ xPetalCtr_1 = xMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
+ largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
+ yPetalCtr_1 = yMidOfShortestEdge + Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
+ middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
- xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.Y -
- largestAngleCorner.Y) / Math.Sqrt(shortestEdgeDist);
- yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.X -
- middleAngleCorner.X) / Math.Sqrt(shortestEdgeDist);
+ xPetalCtr_2 = xMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (middleAngleCorner.y -
+ largestAngleCorner.y) / Math.Sqrt(shortestEdgeDist);
+ yPetalCtr_2 = yMidOfShortestEdge - Math.Sqrt(petalRadius * petalRadius - (shortestEdgeDist / 4)) * (largestAngleCorner.x -
+ middleAngleCorner.x) / Math.Sqrt(shortestEdgeDist);
// find the correct circle since there will be two possible circles
// calculate the distance to smallest angle corner
- dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.X) * (xPetalCtr_1 - smallestAngleCorner.X);
- dycenter1 = (yPetalCtr_1 - smallestAngleCorner.Y) * (yPetalCtr_1 - smallestAngleCorner.Y);
- dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.X) * (xPetalCtr_2 - smallestAngleCorner.X);
- dycenter2 = (yPetalCtr_2 - smallestAngleCorner.Y) * (yPetalCtr_2 - smallestAngleCorner.Y);
+ dxcenter1 = (xPetalCtr_1 - smallestAngleCorner.x) * (xPetalCtr_1 - smallestAngleCorner.x);
+ dycenter1 = (yPetalCtr_1 - smallestAngleCorner.y) * (yPetalCtr_1 - smallestAngleCorner.y);
+ dxcenter2 = (xPetalCtr_2 - smallestAngleCorner.x) * (xPetalCtr_2 - smallestAngleCorner.x);
+ dycenter2 = (yPetalCtr_2 - smallestAngleCorner.y) * (yPetalCtr_2 - smallestAngleCorner.y);
// whichever is closer to smallest angle corner, it must be the center
if (dxcenter1 + dycenter1 <= dxcenter2 + dycenter2)
@@ -1154,8 +1155,8 @@ namespace TriangleNet
xPetalCtr = xPetalCtr_2; yPetalCtr = yPetalCtr_2;
}
/// find the third point of the neighbor triangle ///
- neighborNotFound_first = GetNeighborsVertex(m, badotri, middleAngleCorner.X, middleAngleCorner.Y,
- smallestAngleCorner.X, smallestAngleCorner.Y, ref thirdPoint, ref neighborotri);
+ neighborNotFound_first = GetNeighborsVertex(m, badotri, middleAngleCorner.x, middleAngleCorner.y,
+ smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
/// find the circumcenter of the neighbor triangle ///
dxFirstSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
dyFirstSuggestion = dy;
@@ -1179,7 +1180,7 @@ namespace TriangleNet
y_2 = petal_bisector_x * Math.Sin(alpha) + petal_bisector_y * Math.Cos(alpha) + yPetalCtr - xPetalCtr * Math.Sin(alpha) - yPetalCtr * Math.Cos(alpha);
// we need to find correct intersection point, since there are two possibilities
// weather it is obtuse/acute the one closer to the minimum angle corner is the first direction
- isCorrect = ChooseCorrectPoint(x_2, y_2, middleAngleCorner.X, middleAngleCorner.Y, x_1, y_1, true);
+ isCorrect = ChooseCorrectPoint(x_2, y_2, middleAngleCorner.x, middleAngleCorner.y, x_1, y_1, true);
// make sure which point is the correct one to be considered
if (isCorrect)
{
@@ -1197,29 +1198,29 @@ namespace TriangleNet
}
/// choose the correct intersection point ///
// calculate middle point of the longest edge(bisector)
- xMidOfLongestEdge = (middleAngleCorner.X + smallestAngleCorner.X) / 2.0;
- yMidOfLongestEdge = (middleAngleCorner.Y + smallestAngleCorner.Y) / 2.0;
+ xMidOfLongestEdge = (middleAngleCorner.x + smallestAngleCorner.x) / 2.0;
+ yMidOfLongestEdge = (middleAngleCorner.y + smallestAngleCorner.y) / 2.0;
// if there is a neighbor triangle
if (!neighborNotFound_first)
{
- neighborvertex_1=neighborotri.Org();
- neighborvertex_2=neighborotri.Dest();
- neighborvertex_3=neighborotri.Apex();
+ neighborvertex_1 = neighborotri.Org();
+ neighborvertex_2 = neighborotri.Dest();
+ neighborvertex_3 = neighborotri.Apex();
// now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1.pt, neighborvertex_2.pt, neighborvertex_3.pt, ref xi_tmp, ref eta_tmp, false);
+ neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3, ref xi_tmp, ref eta_tmp, false);
/// compute petal and Voronoi edge intersection ///
// in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (middleAngleCorner.Y - smallestAngleCorner.Y);//(-y, x)
- vector_y = smallestAngleCorner.X - middleAngleCorner.X;
- vector_x = myCircumcenter.X + vector_x;
- vector_y = myCircumcenter.Y + vector_y;
+ vector_x = (middleAngleCorner.y - smallestAngleCorner.y);//(-y, x)
+ vector_y = smallestAngleCorner.x - middleAngleCorner.x;
+ vector_x = myCircumcenter.x + vector_x;
+ vector_y = myCircumcenter.y + vector_y;
// by intersecting bisectors you will end up with the one you want to walk on
// then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.X, myCircumcenter.Y, vector_x, vector_y,
+ CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
xPetalCtr, yPetalCtr, petalRadius, ref p);
// we need to find correct intersection point, since line intersects circle twice
isCorrect = ChooseCorrectPoint(xMidOfLongestEdge, yMidOfLongestEdge, p[3], p[4],
- myCircumcenter.X, myCircumcenter.Y, isObtuse);
+ myCircumcenter.x, myCircumcenter.y, isObtuse);
// make sure which point is the correct one to be considered
if (isCorrect)
{
@@ -1233,16 +1234,16 @@ namespace TriangleNet
}
//----------------------hale new first direction: for slab calculation---------------//
// calculate the intersection of angle lines and Voronoi
- linepnt1_x = middleAngleCorner.X;
- linepnt1_y = middleAngleCorner.Y;
+ linepnt1_x = middleAngleCorner.x;
+ linepnt1_y = middleAngleCorner.y;
// vector from middleAngleCorner to largestAngleCorner
- line_vector_x = largestAngleCorner.X - middleAngleCorner.X;
- line_vector_y = largestAngleCorner.Y - middleAngleCorner.Y;
+ line_vector_x = largestAngleCorner.x - middleAngleCorner.x;
+ line_vector_y = largestAngleCorner.y - middleAngleCorner.y;
// rotate the vector around middleAngleCorner in cw by maxangle degrees
linepnt2_x = petal_slab_inter_x_first;
linepnt2_y = petal_slab_inter_y_first;
// now calculate the intersection of two lines
- LineLineIntersection(myCircumcenter.X, myCircumcenter.Y, vector_x, vector_y, linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y, ref line_p);
+ LineLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y, linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y, ref line_p);
// check if there is a suitable intersection
if (line_p[0] > 0.0)
{
@@ -1253,14 +1254,14 @@ namespace TriangleNet
{
// for debugging (to make sure)
//printf("1) No intersection between two lines!!!\n");
- //printf("(%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f)\n",myCircumcenter.X,myCircumcenter.Y,vector_x,vector_y,linepnt1_x,linepnt1_y,linepnt2_x,linepnt2_y);
+ //printf("(%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f)\n",myCircumcenter.x,myCircumcenter.y,vector_x,vector_y,linepnt1_x,linepnt1_y,linepnt2_x,linepnt2_y);
}
//---------------------------------------------------------------------//
/// check if there is a Voronoi vertex between before intersection ///
// check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.X, myCircumcenter.Y,
- neighborCircumcenter.X, neighborCircumcenter.Y, ref voronoiOrInter);
+ PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
+ neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
/// determine the point to be suggested ///
if (p[0] > 0.0)
@@ -1271,46 +1272,46 @@ namespace TriangleNet
{
//-----------------hale new continues 1------------------//
// now check if the line intersection is between cc and voronoi
- PointBetweenPoints(voronoiOrInter[2], voronoiOrInter[3], myCircumcenter.X, myCircumcenter.Y, line_inter_x, line_inter_y, ref line_result);
+ PointBetweenPoints(voronoiOrInter[2], voronoiOrInter[3], myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
{
// check if we can go further by picking the slab line and petal intersection
// calculate the distance to the smallest angle corner
// check if we create a bad triangle or not
- if (((smallestAngleCorner.X - petal_slab_inter_x_first) * (smallestAngleCorner.X - petal_slab_inter_x_first) +
- (smallestAngleCorner.Y - petal_slab_inter_y_first) * (smallestAngleCorner.Y - petal_slab_inter_y_first) >
- lengthConst * ((smallestAngleCorner.X - line_inter_x) *
- (smallestAngleCorner.X - line_inter_x) +
- (smallestAngleCorner.Y - line_inter_y) *
- (smallestAngleCorner.Y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, petal_slab_inter_x_first, petal_slab_inter_y_first))
+ if (((smallestAngleCorner.x - petal_slab_inter_x_first) * (smallestAngleCorner.x - petal_slab_inter_x_first) +
+ (smallestAngleCorner.y - petal_slab_inter_y_first) * (smallestAngleCorner.y - petal_slab_inter_y_first) >
+ lengthConst * ((smallestAngleCorner.x - line_inter_x) *
+ (smallestAngleCorner.x - line_inter_x) +
+ (smallestAngleCorner.y - line_inter_y) *
+ (smallestAngleCorner.y - line_inter_y)))
+ && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_first, petal_slab_inter_y_first))
&& MinDistanceToNeighbor(m, petal_slab_inter_x_first, petal_slab_inter_y_first, ref neighborotri) > MinDistanceToNeighbor(m, line_inter_x, line_inter_y, ref neighborotri))
{
//
/// check the neighbor's vertices also, which one if better
//slab and petal intersection is advised
- dxFirstSuggestion = petal_slab_inter_x_first - torg.pt.X;
- dyFirstSuggestion = petal_slab_inter_y_first - torg.pt.Y;
+ dxFirstSuggestion = petal_slab_inter_x_first - torg.x;
+ dyFirstSuggestion = petal_slab_inter_y_first - torg.y;
}
else
{ // slab intersection point is further away
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
{
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.X) * (line_inter_x - myCircumcenter.X) +
- (line_inter_y - myCircumcenter.Y) * (line_inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
+ (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - line_inter_x;
- ay = myCircumcenter.Y - line_inter_y;
+ ax = myCircumcenter.x - line_inter_x;
+ ay = myCircumcenter.y - line_inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
{
// go back to circumcenter
dxFirstSuggestion = dx;
@@ -1321,8 +1322,8 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxFirstSuggestion = line_inter_x - torg.pt.X;
- dyFirstSuggestion = line_inter_y - torg.pt.Y;
+ dxFirstSuggestion = line_inter_x - torg.x;
+ dyFirstSuggestion = line_inter_y - torg.y;
}
@@ -1332,8 +1333,8 @@ namespace TriangleNet
else
{// we are not creating a bad triangle
// slab intersection is advised
- dxFirstSuggestion = line_result[2] - torg.pt.X;
- dyFirstSuggestion = line_result[3] - torg.pt.Y;
+ dxFirstSuggestion = line_result[2] - torg.x;
+ dyFirstSuggestion = line_result[3] - torg.y;
}
}
@@ -1342,7 +1343,7 @@ namespace TriangleNet
else
{
/// NOW APPLY A BREADTH-FIRST SEARCH ON THE VORONOI
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, neighborCircumcenter.X, neighborCircumcenter.Y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
{
// go back to circumcenter
dxFirstSuggestion = dx;
@@ -1354,8 +1355,8 @@ namespace TriangleNet
{
// we are not creating a bad triangle
// neighbor's circumcenter is suggested
- dxFirstSuggestion = voronoiOrInter[2] - torg.pt.X;
- dyFirstSuggestion = voronoiOrInter[3] - torg.pt.Y;
+ dxFirstSuggestion = voronoiOrInter[2] - torg.x;
+ dyFirstSuggestion = voronoiOrInter[3] - torg.y;
}
@@ -1366,43 +1367,43 @@ namespace TriangleNet
{ // there is no voronoi vertex between intersection point and circumcenter
//-----------------hale new continues 2-----------------//
// now check if the line intersection is between cc and intersection point
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.X, myCircumcenter.Y, line_inter_x, line_inter_y, ref line_result);
+ PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
{
// check if we can go further by picking the slab line and petal intersection
// calculate the distance to the smallest angle corner
- if (((smallestAngleCorner.X - petal_slab_inter_x_first) * (smallestAngleCorner.X - petal_slab_inter_x_first) +
- (smallestAngleCorner.Y - petal_slab_inter_y_first) * (smallestAngleCorner.Y - petal_slab_inter_y_first) >
- lengthConst * ((smallestAngleCorner.X - line_inter_x) *
- (smallestAngleCorner.X - line_inter_x) +
- (smallestAngleCorner.Y - line_inter_y) *
- (smallestAngleCorner.Y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, petal_slab_inter_x_first, petal_slab_inter_y_first))
+ if (((smallestAngleCorner.x - petal_slab_inter_x_first) * (smallestAngleCorner.x - petal_slab_inter_x_first) +
+ (smallestAngleCorner.y - petal_slab_inter_y_first) * (smallestAngleCorner.y - petal_slab_inter_y_first) >
+ lengthConst * ((smallestAngleCorner.x - line_inter_x) *
+ (smallestAngleCorner.x - line_inter_x) +
+ (smallestAngleCorner.y - line_inter_y) *
+ (smallestAngleCorner.y - line_inter_y)))
+ && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_first, petal_slab_inter_y_first))
&& MinDistanceToNeighbor(m, petal_slab_inter_x_first, petal_slab_inter_y_first, ref neighborotri) > MinDistanceToNeighbor(m, line_inter_x, line_inter_y, ref neighborotri))
{
//slab and petal intersection is advised
- dxFirstSuggestion = petal_slab_inter_x_first - torg.pt.X;
- dyFirstSuggestion = petal_slab_inter_y_first - torg.pt.Y;
+ dxFirstSuggestion = petal_slab_inter_x_first - torg.x;
+ dyFirstSuggestion = petal_slab_inter_y_first - torg.y;
}
else
{ // slab intersection point is further away
- if (IsBadTriangleAngle(largestAngleCorner.X, largestAngleCorner.Y, middleAngleCorner.X, middleAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, line_inter_x, line_inter_y))
{
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.X) * (line_inter_x - myCircumcenter.X) +
- (line_inter_y - myCircumcenter.Y) * (line_inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
+ (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - line_inter_x;
- ay = myCircumcenter.Y - line_inter_y;
+ ax = myCircumcenter.x - line_inter_x;
+ ay = myCircumcenter.y - line_inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
{
// go back to circumcenter
dxFirstSuggestion = dx;
@@ -1412,8 +1413,8 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxFirstSuggestion = line_inter_x - torg.pt.X;
- dyFirstSuggestion = line_inter_y - torg.pt.Y;
+ dxFirstSuggestion = line_inter_x - torg.x;
+ dyFirstSuggestion = line_inter_y - torg.y;
}
@@ -1422,8 +1423,8 @@ namespace TriangleNet
else
{// we are not creating a bad triangle
// slab intersection is advised
- dxFirstSuggestion = line_result[2] - torg.pt.X;
- dyFirstSuggestion = line_result[3] - torg.pt.Y;
+ dxFirstSuggestion = line_result[2] - torg.x;
+ dyFirstSuggestion = line_result[3] - torg.y;
}
}
@@ -1433,24 +1434,24 @@ namespace TriangleNet
else
{
- if (IsBadTriangleAngle(largestAngleCorner.X, largestAngleCorner.Y, middleAngleCorner.X, middleAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, inter_x, inter_y))
{
//printf("testtriangle returned false! bad triangle\n");
// if it is inside feasible region, then insert v2
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.X) * (inter_x - myCircumcenter.X) +
- (inter_y - myCircumcenter.Y) * (inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
+ (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - inter_x;
- ay = myCircumcenter.Y - inter_y;
+ ax = myCircumcenter.x - inter_x;
+ ay = myCircumcenter.y - inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
{
// go back to circumcenter
dxFirstSuggestion = dx;
@@ -1462,28 +1463,28 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxFirstSuggestion = inter_x - torg.pt.X;
- dyFirstSuggestion = inter_y - torg.pt.Y;
+ dxFirstSuggestion = inter_x - torg.x;
+ dyFirstSuggestion = inter_y - torg.y;
}
}
else
{
// intersection point is suggested
- dxFirstSuggestion = inter_x - torg.pt.X;
- dyFirstSuggestion = inter_y - torg.pt.Y;
+ dxFirstSuggestion = inter_x - torg.x;
+ dyFirstSuggestion = inter_y - torg.y;
}
}
}
/// if it is an acute triangle, check if it is a good enough location ///
// for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.X - myCircumcenter.X) * (smallestAngleCorner.X - myCircumcenter.X) +
- (smallestAngleCorner.Y - myCircumcenter.Y) * (smallestAngleCorner.Y - myCircumcenter.Y) >
- lengthConst * ((smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y))))
+ if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
+ (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
+ lengthConst * ((smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y))))
{
// use circumcenter
dxFirstSuggestion = dx;
@@ -1496,42 +1497,42 @@ namespace TriangleNet
/// DO THE SAME THING FOR THE OTHER DIRECTION ///
/// find the third point of the neighbor triangle ///
- neighborNotFound_second = GetNeighborsVertex(m, badotri, largestAngleCorner.X, largestAngleCorner.Y,
- smallestAngleCorner.X, smallestAngleCorner.Y, ref thirdPoint, ref neighborotri);
+ neighborNotFound_second = GetNeighborsVertex(m, badotri, largestAngleCorner.x, largestAngleCorner.y,
+ smallestAngleCorner.x, smallestAngleCorner.y, ref thirdPoint, ref neighborotri);
/// find the circumcenter of the neighbor triangle ///
dxSecondSuggestion = dx; // if we cannot find any appropriate suggestion, we use circumcenter
dySecondSuggestion = dy;
/// choose the correct intersection point ///
// calculate middle point of the longest edge(bisector)
- xMidOfMiddleEdge = (largestAngleCorner.X + smallestAngleCorner.X) / 2.0;
- yMidOfMiddleEdge = (largestAngleCorner.Y + smallestAngleCorner.Y) / 2.0;
+ xMidOfMiddleEdge = (largestAngleCorner.x + smallestAngleCorner.x) / 2.0;
+ yMidOfMiddleEdge = (largestAngleCorner.y + smallestAngleCorner.y) / 2.0;
// if there is a neighbor triangle
if (!neighborNotFound_second)
{
- neighborvertex_1=neighborotri.Org();
- neighborvertex_2=neighborotri.Dest();
- neighborvertex_3=neighborotri.Apex();
+ neighborvertex_1 = neighborotri.Org();
+ neighborvertex_2 = neighborotri.Dest();
+ neighborvertex_3 = neighborotri.Apex();
// now calculate neighbor's circumcenter which is the voronoi site
- neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1.pt, neighborvertex_2.pt, neighborvertex_3.pt, ref xi_tmp, ref eta_tmp, false);
+ neighborCircumcenter = Primitives.FindCircumcenter(neighborvertex_1, neighborvertex_2, neighborvertex_3, ref xi_tmp, ref eta_tmp, false);
/// compute petal and Voronoi edge intersection ///
// in order to avoid degenerate cases, we need to do a vector based calculation for line
- vector_x = (largestAngleCorner.Y - smallestAngleCorner.Y);//(-y, x)
- vector_y = smallestAngleCorner.X - largestAngleCorner.X;
- vector_x = myCircumcenter.X + vector_x;
- vector_y = myCircumcenter.Y + vector_y;
+ vector_x = (largestAngleCorner.y - smallestAngleCorner.y);//(-y, x)
+ vector_y = smallestAngleCorner.x - largestAngleCorner.x;
+ vector_x = myCircumcenter.x + vector_x;
+ vector_y = myCircumcenter.y + vector_y;
// by intersecting bisectors you will end up with the one you want to walk on
// then this line and circle should be intersected
- CircleLineIntersection(myCircumcenter.X, myCircumcenter.Y, vector_x, vector_y,
+ CircleLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y,
xPetalCtr, yPetalCtr, petalRadius, ref p);
// we need to find correct intersection point, since line intersects circle twice
// this direction is always ACUTE
isCorrect = ChooseCorrectPoint(xMidOfMiddleEdge, yMidOfMiddleEdge, p[3], p[4],
- myCircumcenter.X, myCircumcenter.Y, false/*(isObtuse+1)%2*/);
+ myCircumcenter.x, myCircumcenter.y, false/*(isObtuse+1)%2*/);
// make sure which point is the correct one to be considered
if (isCorrect)
{
@@ -1545,16 +1546,16 @@ namespace TriangleNet
}
//----------------------hale new second direction:for slab calculation---------------//
// calculate the intersection of angle lines and Voronoi
- linepnt1_x = largestAngleCorner.X;
- linepnt1_y = largestAngleCorner.Y;
+ linepnt1_x = largestAngleCorner.x;
+ linepnt1_y = largestAngleCorner.y;
// vector from largestAngleCorner to middleAngleCorner
- line_vector_x = middleAngleCorner.X - largestAngleCorner.X;
- line_vector_y = middleAngleCorner.Y - largestAngleCorner.Y;
+ line_vector_x = middleAngleCorner.x - largestAngleCorner.x;
+ line_vector_y = middleAngleCorner.y - largestAngleCorner.y;
// rotate the vector around largestAngleCorner in ccw by maxangle degrees
linepnt2_x = petal_slab_inter_x_second;
linepnt2_y = petal_slab_inter_y_second;
// now calculate the intersection of two lines
- LineLineIntersection(myCircumcenter.X, myCircumcenter.Y, vector_x, vector_y, linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y, ref line_p);
+ LineLineIntersection(myCircumcenter.x, myCircumcenter.y, vector_x, vector_y, linepnt1_x, linepnt1_y, linepnt2_x, linepnt2_y, ref line_p);
// check if there is a suitable intersection
if (line_p[0] > 0.0)
{
@@ -1565,13 +1566,13 @@ namespace TriangleNet
{
// for debugging (to make sure)
//printf("1) No intersection between two lines!!!\n");
- //printf("(%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f)\n",myCircumcenter.X,myCircumcenter.Y,vector_x,vector_y,linepnt1_x,linepnt1_y,linepnt2_x,linepnt2_y);
+ //printf("(%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f) (%.14f,%.14f)\n",myCircumcenter.x,myCircumcenter.y,vector_x,vector_y,linepnt1_x,linepnt1_y,linepnt2_x,linepnt2_y);
}
//---------------------------------------------------------------------//
/// check if there is a Voronoi vertex between before intersection ///
// check if the voronoi vertex is between the intersection and circumcenter
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.X, myCircumcenter.Y,
- neighborCircumcenter.X, neighborCircumcenter.Y, ref voronoiOrInter);
+ PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y,
+ neighborCircumcenter.x, neighborCircumcenter.y, ref voronoiOrInter);
/// determine the point to be suggested ///
if (p[0] > 0.0)
{ // there is at least one intersection point
@@ -1581,45 +1582,45 @@ namespace TriangleNet
{
//-----------------hale new continues 1------------------//
// now check if the line intersection is between cc and voronoi
- PointBetweenPoints(voronoiOrInter[2], voronoiOrInter[3], myCircumcenter.X, myCircumcenter.Y, line_inter_x, line_inter_y, ref line_result);
+ PointBetweenPoints(voronoiOrInter[2], voronoiOrInter[3], myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
{
// check if we can go further by picking the slab line and petal intersection
// calculate the distance to the smallest angle corner
//
- if (((smallestAngleCorner.X - petal_slab_inter_x_second) * (smallestAngleCorner.X - petal_slab_inter_x_second) +
- (smallestAngleCorner.Y - petal_slab_inter_y_second) * (smallestAngleCorner.Y - petal_slab_inter_y_second) >
- lengthConst * ((smallestAngleCorner.X - line_inter_x) *
- (smallestAngleCorner.X - line_inter_x) +
- (smallestAngleCorner.Y - line_inter_y) *
- (smallestAngleCorner.Y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, petal_slab_inter_x_second, petal_slab_inter_y_second))
+ if (((smallestAngleCorner.x - petal_slab_inter_x_second) * (smallestAngleCorner.x - petal_slab_inter_x_second) +
+ (smallestAngleCorner.y - petal_slab_inter_y_second) * (smallestAngleCorner.y - petal_slab_inter_y_second) >
+ lengthConst * ((smallestAngleCorner.x - line_inter_x) *
+ (smallestAngleCorner.x - line_inter_x) +
+ (smallestAngleCorner.y - line_inter_y) *
+ (smallestAngleCorner.y - line_inter_y)))
+ && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_second, petal_slab_inter_y_second))
&& MinDistanceToNeighbor(m, petal_slab_inter_x_second, petal_slab_inter_y_second, ref neighborotri) > MinDistanceToNeighbor(m, line_inter_x, line_inter_y, ref neighborotri))
{
// slab and petal intersection is advised
- dxSecondSuggestion = petal_slab_inter_x_second - torg.pt.X;
- dySecondSuggestion = petal_slab_inter_y_second - torg.pt.Y;
+ dxSecondSuggestion = petal_slab_inter_x_second - torg.x;
+ dySecondSuggestion = petal_slab_inter_y_second - torg.y;
}
else
{ // slab intersection point is further away
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
{
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.X) * (line_inter_x - myCircumcenter.X) +
- (line_inter_y - myCircumcenter.Y) * (line_inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
+ (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - line_inter_x;
- ay = myCircumcenter.Y - line_inter_y;
+ ax = myCircumcenter.x - line_inter_x;
+ ay = myCircumcenter.y - line_inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
{
// go back to circumcenter
dxSecondSuggestion = dx;
@@ -1630,8 +1631,8 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxSecondSuggestion = line_inter_x - torg.pt.X;
- dySecondSuggestion = line_inter_y - torg.pt.Y;
+ dxSecondSuggestion = line_inter_x - torg.x;
+ dySecondSuggestion = line_inter_y - torg.y;
}
@@ -1640,8 +1641,8 @@ namespace TriangleNet
else
{// we are not creating a bad triangle
// slab intersection is advised
- dxSecondSuggestion = line_result[2] - torg.pt.X;
- dySecondSuggestion = line_result[3] - torg.pt.Y;
+ dxSecondSuggestion = line_result[2] - torg.x;
+ dySecondSuggestion = line_result[3] - torg.y;
}
}
@@ -1649,7 +1650,7 @@ namespace TriangleNet
}
else
{
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, neighborCircumcenter.X, neighborCircumcenter.Y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, neighborCircumcenter.x, neighborCircumcenter.y))
{
// go back to circumcenter
dxSecondSuggestion = dx;
@@ -1660,8 +1661,8 @@ namespace TriangleNet
else
{ // we are not creating a bad triangle
// neighbor's circumcenter is suggested
- dxSecondSuggestion = voronoiOrInter[2] - torg.pt.X;
- dySecondSuggestion = voronoiOrInter[3] - torg.pt.Y;
+ dxSecondSuggestion = voronoiOrInter[2] - torg.x;
+ dySecondSuggestion = voronoiOrInter[3] - torg.y;
}
@@ -1671,43 +1672,43 @@ namespace TriangleNet
{ // there is no voronoi vertex between intersection point and circumcenter
//-----------------hale new continues 2-----------------//
// now check if the line intersection is between cc and intersection point
- PointBetweenPoints(inter_x, inter_y, myCircumcenter.X, myCircumcenter.Y, line_inter_x, line_inter_y, ref line_result);
+ PointBetweenPoints(inter_x, inter_y, myCircumcenter.x, myCircumcenter.y, line_inter_x, line_inter_y, ref line_result);
if (Math.Abs(line_result[0] - 1.0) <= EPS && line_p[0] > 0.0)
{
// check if we can go further by picking the slab line and petal intersection
// calculate the distance to the smallest angle corner
- if (((smallestAngleCorner.X - petal_slab_inter_x_second) * (smallestAngleCorner.X - petal_slab_inter_x_second) +
- (smallestAngleCorner.Y - petal_slab_inter_y_second) * (smallestAngleCorner.Y - petal_slab_inter_y_second) >
- lengthConst * ((smallestAngleCorner.X - line_inter_x) *
- (smallestAngleCorner.X - line_inter_x) +
- (smallestAngleCorner.Y - line_inter_y) *
- (smallestAngleCorner.Y - line_inter_y)))
- && (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, petal_slab_inter_x_second, petal_slab_inter_y_second))
+ if (((smallestAngleCorner.x - petal_slab_inter_x_second) * (smallestAngleCorner.x - petal_slab_inter_x_second) +
+ (smallestAngleCorner.y - petal_slab_inter_y_second) * (smallestAngleCorner.y - petal_slab_inter_y_second) >
+ lengthConst * ((smallestAngleCorner.x - line_inter_x) *
+ (smallestAngleCorner.x - line_inter_x) +
+ (smallestAngleCorner.y - line_inter_y) *
+ (smallestAngleCorner.y - line_inter_y)))
+ && (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, petal_slab_inter_x_second, petal_slab_inter_y_second))
&& MinDistanceToNeighbor(m, petal_slab_inter_x_second, petal_slab_inter_y_second, ref neighborotri) > MinDistanceToNeighbor(m, line_inter_x, line_inter_y, ref neighborotri))
{
// slab and petal intersection is advised
- dxSecondSuggestion = petal_slab_inter_x_second - torg.pt.X;
- dySecondSuggestion = petal_slab_inter_y_second - torg.pt.Y;
+ dxSecondSuggestion = petal_slab_inter_x_second - torg.x;
+ dySecondSuggestion = petal_slab_inter_y_second - torg.y;
}
else
{ // slab intersection point is further away ;
- if (IsBadTriangleAngle(largestAngleCorner.X, largestAngleCorner.Y, middleAngleCorner.X, middleAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(largestAngleCorner.x, largestAngleCorner.y, middleAngleCorner.x, middleAngleCorner.y, line_inter_x, line_inter_y))
{
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((line_inter_x - myCircumcenter.X) * (line_inter_x - myCircumcenter.X) +
- (line_inter_y - myCircumcenter.Y) * (line_inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((line_inter_x - myCircumcenter.x) * (line_inter_x - myCircumcenter.x) +
+ (line_inter_y - myCircumcenter.y) * (line_inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - line_inter_x;
- ay = myCircumcenter.Y - line_inter_y;
+ ax = myCircumcenter.x - line_inter_x;
+ ay = myCircumcenter.y - line_inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
line_inter_x = line_inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
line_inter_y = line_inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, line_inter_x, line_inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, line_inter_x, line_inter_y))
{
// go back to circumcenter
dxSecondSuggestion = dx;
@@ -1717,8 +1718,8 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxSecondSuggestion = line_inter_x - torg.pt.X;
- dySecondSuggestion = line_inter_y - torg.pt.Y;
+ dxSecondSuggestion = line_inter_x - torg.x;
+ dySecondSuggestion = line_inter_y - torg.y;
}
@@ -1727,8 +1728,8 @@ namespace TriangleNet
else
{// we are not creating a bad triangle
// slab intersection is advised
- dxSecondSuggestion = line_result[2] - torg.pt.X;
- dySecondSuggestion = line_result[3] - torg.pt.Y;
+ dxSecondSuggestion = line_result[2] - torg.x;
+ dySecondSuggestion = line_result[3] - torg.y;
}
}
@@ -1737,23 +1738,23 @@ namespace TriangleNet
}
else
{
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
{
// if it is inside feasible region, then insert v2
// apply perturbation
// find the distance between circumcenter and intersection point
- d = Math.Sqrt((inter_x - myCircumcenter.X) * (inter_x - myCircumcenter.X) +
- (inter_y - myCircumcenter.Y) * (inter_y - myCircumcenter.Y));
+ d = Math.Sqrt((inter_x - myCircumcenter.x) * (inter_x - myCircumcenter.x) +
+ (inter_y - myCircumcenter.y) * (inter_y - myCircumcenter.y));
// then find the vector going from intersection point to circumcenter
- ax = myCircumcenter.X - inter_x;
- ay = myCircumcenter.Y - inter_y;
+ ax = myCircumcenter.x - inter_x;
+ ay = myCircumcenter.y - inter_y;
ax = ax / d;
ay = ay / d;
// now calculate the new intersection point which is perturbated towards the circumcenter
inter_x = inter_x + ax * pertConst * Math.Sqrt(shortestEdgeDist);
inter_y = inter_y + ay * pertConst * Math.Sqrt(shortestEdgeDist);
- if (IsBadTriangleAngle(middleAngleCorner.X, middleAngleCorner.Y, largestAngleCorner.X, largestAngleCorner.Y, inter_x, inter_y))
+ if (IsBadTriangleAngle(middleAngleCorner.x, middleAngleCorner.y, largestAngleCorner.x, largestAngleCorner.y, inter_x, inter_y))
{
// go back to circumcenter
dxSecondSuggestion = dx;
@@ -1764,8 +1765,8 @@ namespace TriangleNet
else
{
// intersection point is suggested
- dxSecondSuggestion = inter_x - torg.pt.X;
- dySecondSuggestion = inter_y - torg.pt.Y;
+ dxSecondSuggestion = inter_x - torg.x;
+ dySecondSuggestion = inter_y - torg.y;
}
}
@@ -1773,8 +1774,8 @@ namespace TriangleNet
{
// intersection point is suggested
- dxSecondSuggestion = inter_x - torg.pt.X;
- dySecondSuggestion = inter_y - torg.pt.Y;
+ dxSecondSuggestion = inter_x - torg.x;
+ dySecondSuggestion = inter_y - torg.y;
}
}
@@ -1782,12 +1783,12 @@ namespace TriangleNet
/// if it is an acute triangle, check if it is a good enough location ///
// for acute triangle case, we need to check if it is ok to use either of them
- if ((smallestAngleCorner.X - myCircumcenter.X) * (smallestAngleCorner.X - myCircumcenter.X) +
- (smallestAngleCorner.Y - myCircumcenter.Y) * (smallestAngleCorner.Y - myCircumcenter.Y) >
- lengthConst * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))))
+ if ((smallestAngleCorner.x - myCircumcenter.x) * (smallestAngleCorner.x - myCircumcenter.x) +
+ (smallestAngleCorner.y - myCircumcenter.y) * (smallestAngleCorner.y - myCircumcenter.y) >
+ lengthConst * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))))
{
// use circumcenter
dxSecondSuggestion = dx;
@@ -1801,14 +1802,14 @@ namespace TriangleNet
if (neighborNotFound_first && neighborNotFound_second)
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.X - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.Y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.Y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.X - (xMidOfLongestEdge)) *
- (smallestAngleCorner.X - (xMidOfLongestEdge)) +
- (smallestAngleCorner.Y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.Y - (yMidOfLongestEdge)))
+ if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
+ (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
+ (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
+ (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) *
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) +
+ (smallestAngleCorner.y - (yMidOfLongestEdge)) *
+ (smallestAngleCorner.y - (yMidOfLongestEdge)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1824,14 +1825,14 @@ namespace TriangleNet
else if (neighborNotFound_first)
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))) >
- (smallestAngleCorner.X - (xMidOfLongestEdge)) *
- (smallestAngleCorner.X - (xMidOfLongestEdge)) +
- (smallestAngleCorner.Y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.Y - (yMidOfLongestEdge)))
+ if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) *
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) +
+ (smallestAngleCorner.y - (yMidOfLongestEdge)) *
+ (smallestAngleCorner.y - (yMidOfLongestEdge)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1847,14 +1848,14 @@ namespace TriangleNet
else if (neighborNotFound_second)
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.X - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.Y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.Y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)))
+ if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
+ (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
+ (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
+ (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1870,14 +1871,14 @@ namespace TriangleNet
else
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))) >
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)))
+ if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1897,14 +1898,14 @@ namespace TriangleNet
if (neighborNotFound_first && neighborNotFound_second)
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.X - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.Y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.Y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.X - (xMidOfLongestEdge)) *
- (smallestAngleCorner.X - (xMidOfLongestEdge)) +
- (smallestAngleCorner.Y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.Y - (yMidOfLongestEdge)))
+ if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
+ (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
+ (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
+ (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) *
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) +
+ (smallestAngleCorner.y - (yMidOfLongestEdge)) *
+ (smallestAngleCorner.y - (yMidOfLongestEdge)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1920,14 +1921,14 @@ namespace TriangleNet
else if (neighborNotFound_first)
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))) >
- (smallestAngleCorner.X - (xMidOfLongestEdge)) *
- (smallestAngleCorner.X - (xMidOfLongestEdge)) +
- (smallestAngleCorner.Y - (yMidOfLongestEdge)) *
- (smallestAngleCorner.Y - (yMidOfLongestEdge)))
+ if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) *
+ (smallestAngleCorner.x - (xMidOfLongestEdge)) +
+ (smallestAngleCorner.y - (yMidOfLongestEdge)) *
+ (smallestAngleCorner.y - (yMidOfLongestEdge)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1943,14 +1944,14 @@ namespace TriangleNet
else if (neighborNotFound_second)
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (xMidOfMiddleEdge)) *
- (smallestAngleCorner.X - (xMidOfMiddleEdge)) +
- (smallestAngleCorner.Y - (yMidOfMiddleEdge)) *
- (smallestAngleCorner.Y - (yMidOfMiddleEdge))) >
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)))
+ if (justAcute * ((smallestAngleCorner.x - (xMidOfMiddleEdge)) *
+ (smallestAngleCorner.x - (xMidOfMiddleEdge)) +
+ (smallestAngleCorner.y - (yMidOfMiddleEdge)) *
+ (smallestAngleCorner.y - (yMidOfMiddleEdge))) >
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1966,14 +1967,14 @@ namespace TriangleNet
else
{
//obtuse: check if the other direction works
- if (justAcute * ((smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxSecondSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dySecondSuggestion + torg.pt.Y))) >
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) *
- (smallestAngleCorner.X - (dxFirstSuggestion + torg.pt.X)) +
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)) *
- (smallestAngleCorner.Y - (dyFirstSuggestion + torg.pt.Y)))
+ if (justAcute * ((smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxSecondSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dySecondSuggestion + torg.y))) >
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) *
+ (smallestAngleCorner.x - (dxFirstSuggestion + torg.x)) +
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)) *
+ (smallestAngleCorner.y - (dyFirstSuggestion + torg.y)))
{
dx = dxSecondSuggestion;
dy = dySecondSuggestion;
@@ -1993,13 +1994,13 @@ namespace TriangleNet
if (relocated <= 0)
{
- circumcenter.pt.X = torg.pt.X + dx;
- circumcenter.pt.Y = torg.pt.Y + dy;
+ circumcenter.x = torg.x + dx;
+ circumcenter.y = torg.y + dy;
}
else
{
- circumcenter.pt.X = origin_x + dx;
- circumcenter.pt.Y = origin_y + dy;
+ circumcenter.x = origin_x + dx;
+ circumcenter.y = origin_y + dy;
}
xi = (yao * dx - xao * dy) * (2.0 * denominator);
eta = (xdo * dy - ydo * dx) * (2.0 * denominator);
@@ -2308,28 +2309,28 @@ namespace TriangleNet
switch (whichPoint)
{
case 1:
- first_x = p.pt.X; // point at the center
- first_y = p.pt.Y;
- second_x = r.pt.X; // second vertex of first edge to consider
- second_y = r.pt.Y;
- third_x = q.pt.X; // for terminating the search
- third_y = q.pt.Y;
+ first_x = p.x; // point at the center
+ first_y = p.y;
+ second_x = r.x; // second vertex of first edge to consider
+ second_y = r.y;
+ third_x = q.x; // for terminating the search
+ third_y = q.y;
break;
case 2:
- first_x = q.pt.X; // point at the center
- first_y = q.pt.Y;
- second_x = p.pt.X; // second vertex of first edge to consider
- second_y = p.pt.Y;
- third_x = r.pt.X; // for terminating the search
- third_y = r.pt.Y;
+ first_x = q.x; // point at the center
+ first_y = q.y;
+ second_x = p.x; // second vertex of first edge to consider
+ second_y = p.y;
+ third_x = r.x; // for terminating the search
+ third_y = r.y;
break;
case 3:
- first_x = r.pt.X; // point at the center
- first_y = r.pt.Y;
- second_x = q.pt.X; // second vertex of first edge to consider
- second_y = q.pt.Y;
- third_x = p.pt.X; // for terminating the search
- third_y = p.pt.Y;
+ first_x = r.x; // point at the center
+ first_y = r.y;
+ second_x = q.x; // second vertex of first edge to consider
+ second_y = q.y;
+ third_x = p.x; // for terminating the search
+ third_y = p.y;
break;
}
tempotri = badotri;
@@ -2416,9 +2417,9 @@ namespace TriangleNet
neighborvertex_3 = neighbor.Apex();
// check if it is really a triangle
- if ((neighborvertex_1.pt.X == neighborvertex_2.pt.X && neighborvertex_1.pt.Y == neighborvertex_2.pt.Y)
- || (neighborvertex_2.pt.X == neighborvertex_3.pt.X && neighborvertex_2.pt.Y == neighborvertex_3.pt.Y)
- || (neighborvertex_1.pt.X == neighborvertex_3.pt.X && neighborvertex_1.pt.Y == neighborvertex_3.pt.Y))
+ if ((neighborvertex_1.x == neighborvertex_2.x && neighborvertex_1.y == neighborvertex_2.y)
+ || (neighborvertex_2.x == neighborvertex_3.x && neighborvertex_2.y == neighborvertex_3.y)
+ || (neighborvertex_1.x == neighborvertex_3.x && neighborvertex_1.y == neighborvertex_3.y))
{
//printf("Two vertices are the same!!!!!!!\n");
}
@@ -2426,20 +2427,20 @@ namespace TriangleNet
{
// begin searching for the correct neighbor triangle
firstVertexMatched = 0;
- if ((Math.Abs(first_x - neighborvertex_1.pt.X) < EPS) &&
- (Math.Abs(first_y - neighborvertex_1.pt.Y) < EPS))
+ if ((Math.Abs(first_x - neighborvertex_1.x) < EPS) &&
+ (Math.Abs(first_y - neighborvertex_1.y) < EPS))
{
firstVertexMatched = 11; // neighbor's 1st vertex is matched to first vertex
}
- else if ((Math.Abs(first_x - neighborvertex_2.pt.X) < EPS) &&
- (Math.Abs(first_y - neighborvertex_2.pt.Y) < EPS))
+ else if ((Math.Abs(first_x - neighborvertex_2.x) < EPS) &&
+ (Math.Abs(first_y - neighborvertex_2.y) < EPS))
{
firstVertexMatched = 12; // neighbor's 2nd vertex is matched to first vertex
}
- else if ((Math.Abs(first_x - neighborvertex_3.pt.X) < EPS) &&
- (Math.Abs(first_y - neighborvertex_3.pt.Y) < EPS))
+ else if ((Math.Abs(first_x - neighborvertex_3.x) < EPS) &&
+ (Math.Abs(first_y - neighborvertex_3.y) < EPS))
{
firstVertexMatched = 13; // neighbor's 3rd vertex is matched to first vertex
@@ -2448,18 +2449,18 @@ namespace TriangleNet
} // end of first vertex matching */
secondVertexMatched = 0;
- if ((Math.Abs(second_x - neighborvertex_1.pt.X) < EPS) &&
- (Math.Abs(second_y - neighborvertex_1.pt.Y) < EPS))
+ if ((Math.Abs(second_x - neighborvertex_1.x) < EPS) &&
+ (Math.Abs(second_y - neighborvertex_1.y) < EPS))
{
secondVertexMatched = 21; // neighbor's 1st vertex is matched to second vertex
}
- else if ((Math.Abs(second_x - neighborvertex_2.pt.X) < EPS) &&
- (Math.Abs(second_y - neighborvertex_2.pt.Y) < EPS))
+ else if ((Math.Abs(second_x - neighborvertex_2.x) < EPS) &&
+ (Math.Abs(second_y - neighborvertex_2.y) < EPS))
{
secondVertexMatched = 22; // neighbor's 2nd vertex is matched to second vertex
}
- else if ((Math.Abs(second_x - neighborvertex_3.pt.X) < EPS) &&
- (Math.Abs(second_y - neighborvertex_3.pt.Y) < EPS))
+ else if ((Math.Abs(second_x - neighborvertex_3.x) < EPS) &&
+ (Math.Abs(second_y - neighborvertex_3.y) < EPS))
{
secondVertexMatched = 23; // neighbor's 3rd vertex is matched to second vertex
}/*else{
@@ -2484,39 +2485,39 @@ namespace TriangleNet
case 11:
if (secondVertexMatched == 22)
{
- thirdpoint[0] = neighborvertex_3.pt.X;
- thirdpoint[1] = neighborvertex_3.pt.Y;
+ thirdpoint[0] = neighborvertex_3.x;
+ thirdpoint[1] = neighborvertex_3.y;
}
else if (secondVertexMatched == 23)
{
- thirdpoint[0] = neighborvertex_2.pt.X;
- thirdpoint[1] = neighborvertex_2.pt.Y;
+ thirdpoint[0] = neighborvertex_2.x;
+ thirdpoint[1] = neighborvertex_2.y;
}
else { notFound = true; }
break;
case 12:
if (secondVertexMatched == 21)
{
- thirdpoint[0] = neighborvertex_3.pt.X;
- thirdpoint[1] = neighborvertex_3.pt.Y;
+ thirdpoint[0] = neighborvertex_3.x;
+ thirdpoint[1] = neighborvertex_3.y;
}
else if (secondVertexMatched == 23)
{
- thirdpoint[0] = neighborvertex_1.pt.X;
- thirdpoint[1] = neighborvertex_1.pt.Y;
+ thirdpoint[0] = neighborvertex_1.x;
+ thirdpoint[1] = neighborvertex_1.y;
}
else { notFound = true; }
break;
case 13:
if (secondVertexMatched == 21)
{
- thirdpoint[0] = neighborvertex_2.pt.X;
- thirdpoint[1] = neighborvertex_2.pt.Y;
+ thirdpoint[0] = neighborvertex_2.x;
+ thirdpoint[1] = neighborvertex_2.y;
}
else if (secondVertexMatched == 22)
{
- thirdpoint[0] = neighborvertex_1.pt.X;
- thirdpoint[1] = neighborvertex_1.pt.Y;
+ thirdpoint[0] = neighborvertex_1.x;
+ thirdpoint[1] = neighborvertex_1.y;
}
else { notFound = true; }
break;
@@ -4101,7 +4102,7 @@ namespace TriangleNet
double d1, d2, d3, ahead;
//triangle ptr; // Temporary variable used by sym().
- Point2 newvertex = new Point2(newlocX, newlocY);
+ Point newvertex = new Point(newlocX, newlocY);
// printf("newvertex %f,%f\n", newvertex[0], newvertex[1]);
// Find the location of the vertex to be inserted. Check if a good
@@ -4116,13 +4117,13 @@ namespace TriangleNet
torg = searchtri.Org();
tdest = searchtri.Dest();
// Check the starting triangle's vertices.
- if ((torg.pt.X == newvertex.X) && (torg.pt.Y == newvertex.Y))
+ if ((torg.x == newvertex.x) && (torg.y == newvertex.y))
{
intersect = LocateResult.OnVertex;
searchtri.Copy(ref horiz);
}
- else if ((tdest.pt.X == newvertex.X) && (tdest.pt.Y == newvertex.Y))
+ else if ((tdest.x == newvertex.x) && (tdest.y == newvertex.y))
{
searchtri.LnextSelf();
intersect = LocateResult.OnVertex;
@@ -4131,7 +4132,7 @@ namespace TriangleNet
else
{
// Orient 'searchtri' to fit the preconditions of calling preciselocate().
- ahead = Primitives.CounterClockwise(torg.pt, tdest.pt, newvertex);
+ ahead = Primitives.CounterClockwise(torg, tdest, newvertex);
if (ahead < 0.0)
{
// Turn around so that 'searchpoint' is to the left of the
@@ -4143,8 +4144,8 @@ namespace TriangleNet
else if (ahead == 0.0)
{
// Check if 'searchpoint' is between 'torg' and 'tdest'.
- if (((torg.pt.X < newvertex.X) == (newvertex.X < tdest.pt.X)) &&
- ((torg.pt.Y < newvertex.Y) == (newvertex.Y < tdest.pt.Y)))
+ if (((torg.x < newvertex.x) == (newvertex.x < tdest.x)) &&
+ ((torg.y < newvertex.y) == (newvertex.y < tdest.y)))
{
intersect = LocateResult.OnEdge;
searchtri.Copy(ref horiz);
@@ -4169,9 +4170,9 @@ namespace TriangleNet
v1 = horiz.Org();
v2 = horiz.Dest();
v3 = horiz.Apex();
- d1 = (v1.pt.X - newvertex.X) * (v1.pt.X - newvertex.X) + (v1.pt.Y - newvertex.Y) * (v1.pt.Y - newvertex.Y);
- d2 = (v2.pt.X - newvertex.X) * (v2.pt.X - newvertex.X) + (v2.pt.Y - newvertex.Y) * (v2.pt.Y - newvertex.Y);
- d3 = (v3.pt.X - newvertex.X) * (v3.pt.X - newvertex.X) + (v3.pt.Y - newvertex.Y) * (v3.pt.Y - newvertex.Y);
+ d1 = (v1.x - newvertex.x) * (v1.x - newvertex.x) + (v1.y - newvertex.y) * (v1.y - newvertex.y);
+ d2 = (v2.x - newvertex.x) * (v2.x - newvertex.x) + (v2.y - newvertex.y) * (v2.y - newvertex.y);
+ d3 = (v3.x - newvertex.x) * (v3.x - newvertex.x) + (v3.y - newvertex.y) * (v3.y - newvertex.y);
//m.VertexDealloc(newvertex);
// find minimum of the distance
if (d1 <= d2 && d1 <= d3)
@@ -4188,142 +4189,5 @@ namespace TriangleNet
}
}
}
-
- /*
- ///
- /// Finds min angle of a triangle for .part file.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- static double ReturnMinAngle(double p1x, double p1y, double p2x, double p2y, double p3x, double p3y)
- {
- double angle_p1, angle_p2, angle_p3, a2, b2, c2;
- a2 = (p1x - p2x) * (p1x - p2x) + (p1y - p2y) * (p1y - p2y);
- b2 = (p1x - p3x) * (p1x - p3x) + (p1y - p3y) * (p1y - p3y);
- c2 = (p2x - p3x) * (p2x - p3x) + (p2y - p3y) * (p2y - p3y);
- angle_p1 = Math.Acos((a2 + b2 - c2) / (2.0 * Math.Sqrt(a2) * Math.Sqrt(b2))) * 180.0 / Math.PI;
- angle_p2 = Math.Acos((a2 + c2 - b2) / (2.0 * Math.Sqrt(a2) * Math.Sqrt(c2))) * 180.0 / Math.PI;
- angle_p3 = Math.Acos((c2 + b2 - a2) / (2.0 * Math.Sqrt(c2) * Math.Sqrt(b2))) * 180.0 / Math.PI;
- if (angle_p1 <= angle_p2 && angle_p1 <= angle_p3)
- {
- return angle_p1;
- }
- else if (angle_p2 <= angle_p3)
- {
- return angle_p2;
- }
- else
- {
- return angle_p3;
- }
- }
-
- ///
- /// Finds max angle of a triangle for .part file.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- static double returnMaxAngle(double p1x, double p1y, double p2x, double p2y, double p3x, double p3y)
- {
- double angle_p1, angle_p2, angle_p3, a2, b2, c2;
- a2 = (p1x - p2x) * (p1x - p2x) + (p1y - p2y) * (p1y - p2y);
- b2 = (p1x - p3x) * (p1x - p3x) + (p1y - p3y) * (p1y - p3y);
- c2 = (p2x - p3x) * (p2x - p3x) + (p2y - p3y) * (p2y - p3y);
- angle_p1 = Math.Acos((a2 + b2 - c2) / (2.0 * Math.Sqrt(a2) * Math.Sqrt(b2))) * 180.0 / Math.PI;
- angle_p2 = Math.Acos((a2 + c2 - b2) / (2.0 * Math.Sqrt(a2) * Math.Sqrt(c2))) * 180.0 / Math.PI;
- angle_p3 = Math.Acos((c2 + b2 - a2) / (2.0 * Math.Sqrt(c2) * Math.Sqrt(b2))) * 180.0 / Math.PI;
- if (angle_p1 >= angle_p2 && angle_p1 >= angle_p3)
- {
- return angle_p1;
- }
- else if (angle_p2 >= angle_p3)
- {
- return angle_p2;
- }
- else
- {
- return angle_p3;
- }
- }
-
- //*****************************************************************
- //
- // writeparts() Write the triangles to a .part file with the information
- // that it is bad or good
- //
- //*****************************************************************
- #ifndef TRILIBRARY
- void writeparts(mesh m, int argc, char **argv)
- {
- FILE *outfile;
- otri triangleloop;
- vertex p1, p2, p3;
- long elementnumber;
- int i;
- int bad;
- double minAngleTri, maxAngleTri;
- char partfilename[FILENAMESIZE];
- strcpy(partfilename, behavior.innodefilename);
- partfilename[strlen(partfilename) - 5] = '\0';
- strcat(partfilename, ".1.part");
- if (!behavior.quiet) {
- printf("Writing %s.\n", partfilename);
- }
- outfile = fopen(partfilename, "w");
- if (outfile == (FILE *) NULL) {
- printf(" Error: Cannot create file %s.\n", partfilename);
- triexit(1);
- }
- // Number of triangles, vertices per triangle, attributes per triangle.
- fprintf(outfile, "%ld 103\n", m.triangles.items);
-
- traversalinit(&m.triangles);
- triangleloop.tri = triangletraverse(m);
- triangleloop.orient = 0;
- elementnumber = behavior.firstnumber;
- while (triangleloop.tri != (triangle *) NULL) {
- org(triangleloop, p1);
- dest(triangleloop, p2);
- apex(triangleloop, p3);
- if (behavior.order == 1) {
- // we need to check if this triangle is good or not
- //bad = testTriangleAngleArea(m, b, &p1[0], &p1[1],&p2[0], &p2[1],&p3[0], &p3[1]);
- bad = testTriangleAngle(m, b, &p1[0], &p1[1],&p2[0], &p2[1],&p3[0], &p3[1]);
- minAngleTri = returnMinAngle(p1[0], p1[1],p2[0], p2[1],p3[0], p3[1]);
- maxAngleTri = returnMaxAngle(p1[0], p1[1],p2[0], p2[1],p3[0], p3[1]);
- if(bad){
- //printf("!!!!!!!!bad >> p1[0]=%f,p1[1]=%f,p2[0]=%f,p2[1]=%f,p3[0]=%f,p3[1]=%f\n", p1[0], p1[1],p2[0], p2[1],p3[0], p3[1]);
- // Triangle number, indices for three vertices.
- if(behavior.maxangle != 0.00000){
- fprintf(outfile, "%4ld %d ", elementnumber,(int)((180.0-maxAngleTri)*0.35+2.0));
- }else{
- fprintf(outfile, "%4ld %d ", elementnumber, 1);
- }
- }else{
- if(behavior.maxangle != 0.00000){
- fprintf(outfile, "%4ld %d ", elementnumber,(int)((180.0-maxAngleTri)*0.35+54.0+2.0));
- }else{
- fprintf(outfile, "%4ld %d ", elementnumber, 103);
- }
- }
- }
-
- fprintf(outfile, "\n");
- triangleloop.tri = triangletraverse(m);
- elementnumber++;
- }
- finishfile(outfile, argc, argv);
- }
- */
}
}
\ No newline at end of file
diff --git a/Triangle.NET/Triangle/Primitives.cs b/Triangle.NET/Triangle/Primitives.cs
index 3e61aed..3f22673 100644
--- a/Triangle.NET/Triangle/Primitives.cs
+++ b/Triangle.NET/Triangle/Primitives.cs
@@ -9,6 +9,8 @@ namespace TriangleNet
{
using System;
using TriangleNet.Data;
+ using TriangleNet.Geometry;
+ using TriangleNet.Tools;
///
/// Provides some primitives regularly used in computational geometry.
@@ -84,14 +86,14 @@ namespace TriangleNet
/// also a rough approximation of twice the signed area of the triangle defined
/// by the three points.
///
- ///
- ///
- ///
+ /// Point a.
+ /// Point b.
+ /// Point c.
/// Return a positive value if the points pa, pb, and pc occur in
/// counterclockwise order; a negative value if they occur in clockwise order;
/// and zero if they are collinear.
///
- /// Uses exact arithmetic if necessary to ensure a correct answer. The
+ /// Uses exact arithmetic if necessary to ensure a correct answer. The
/// result returned is the determinant of a matrix. This determinant is
/// computed adaptively, in the sense that exact arithmetic is used only to
/// the degree it is needed to ensure that the returned value has the
@@ -100,15 +102,15 @@ namespace TriangleNet
///
/// See Robust Predicates paper for details.
///
- public static double CounterClockwise(Point2 pa, Point2 pb, Point2 pc)
+ public static double CounterClockwise(Point pa, Point pb, Point pc)
{
double detleft, detright, det;
double detsum, errbound;
Statistic.CounterClockwiseCount++;
- detleft = (pa.X - pc.X) * (pb.Y - pc.Y);
- detright = (pa.Y - pc.Y) * (pb.X - pc.X);
+ detleft = (pa.x - pc.x) * (pb.y - pc.y);
+ detright = (pa.y - pc.y) * (pb.x - pc.x);
det = detleft - detright;
if (Behavior.NoExact)
@@ -161,10 +163,10 @@ namespace TriangleNet
/// points pa, pb, and pc must be in counterclockwise order, or the sign of the result
/// will be reversed.
///
- ///
- ///
- ///
- ///
+ /// Point a.
+ /// Point b.
+ /// Point c.
+ /// Point d.
/// Return a positive value if the point pd lies inside the circle passing through
/// pa, pb, and pc; a negative value if it lies outside; and zero if the four points
/// are cocircular.
@@ -178,7 +180,7 @@ namespace TriangleNet
///
/// See Robust Predicates paper for details.
///
- public static double InCircle(Point2 pa, Point2 pb, Point2 pc, Point2 pd)
+ public static double InCircle(Point pa, Point pb, Point pc, Point pd)
{
double adx, bdx, cdx, ady, bdy, cdy;
double bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
@@ -188,12 +190,12 @@ namespace TriangleNet
Statistic.InCircleCount++;
- adx = pa.X - pd.X;
- bdx = pb.X - pd.X;
- cdx = pc.X - pd.X;
- ady = pa.Y - pd.Y;
- bdy = pb.Y - pd.Y;
- cdy = pc.Y - pd.Y;
+ adx = pa.x - pd.x;
+ bdx = pb.x - pd.x;
+ cdx = pc.x - pd.x;
+ ady = pa.y - pd.y;
+ bdy = pb.y - pd.y;
+ cdy = pc.y - pd.y;
bdxcdy = bdx * cdy;
cdxbdy = cdx * bdy;
@@ -239,19 +241,14 @@ namespace TriangleNet
/// pc must be in counterclockwise order, or the sign of the result will be
/// reversed.
///
- ///
- ///
- ///
- ///
- ///
- ///
- /// If the -w switch is used, the points are lifted onto the parabolic
- /// lifting map, then they are dropped according to their weights, then the
- /// 3D orientation test is applied. If the -W switch is used, the points'
- /// heights are already provided, so the 3D orientation test is applied
- /// directly. If neither switch is used, the incircle test is applied.
- ///
- public static double NonRegular(Point2 pa, Point2 pb, Point2 pc, Point2 pd)
+ /// Point a.
+ /// Point b.
+ /// Point c.
+ /// Point d.
+ /// Return a positive value if the point pd lies inside the circle passing through
+ /// pa, pb, and pc; a negative value if it lies outside; and zero if the four points
+ /// are cocircular.
+ public static double NonRegular(Point pa, Point pb, Point pc, Point pd)
{
return InCircle(pa, pb, pc, pd);
}
@@ -259,13 +256,13 @@ namespace TriangleNet
///
/// Find the circumcenter of a triangle.
///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
+ /// Triangle point.
+ /// Triangle point.
+ /// Triangle point.
+ /// Relative coordinate of new location.
+ /// Relative coordinate of new location.
+ /// Use off-center for new location.
+ /// Coordinates of the circumcenter (or off-center)
///
/// The result is returned both in terms of x-y coordinates and xi-eta
/// (barycentric) coordinates. The xi-eta coordinate system is defined in
@@ -275,7 +272,7 @@ namespace TriangleNet
/// This procedure also returns the square of the length of the triangle's
/// shortest edge.
///
- public static Point2 FindCircumcenter(Point2 torg, Point2 tdest, Point2 tapex,
+ public static Point FindCircumcenter(Point torg, Point tdest, Point tapex,
ref double xi, ref double eta, bool offcenter)
{
double xdo, ydo, xao, yao;
@@ -286,14 +283,14 @@ namespace TriangleNet
Statistic.CircumcenterCount++;
// Compute the circumcenter of the triangle.
- xdo = tdest.X - torg.X;
- ydo = tdest.Y - torg.Y;
- xao = tapex.X - torg.X;
- yao = tapex.Y - torg.Y;
+ xdo = tdest.x - torg.x;
+ ydo = tdest.y - torg.y;
+ xao = tapex.x - torg.x;
+ yao = tapex.y - torg.y;
dodist = xdo * xdo + ydo * ydo;
aodist = xao * xao + yao * yao;
- dadist = (tdest.X - tapex.X) * (tdest.X - tapex.X) +
- (tdest.Y - tapex.Y) * (tdest.Y - tapex.Y);
+ dadist = (tdest.x - tapex.x) * (tdest.x - tapex.x) +
+ (tdest.y - tapex.y) * (tdest.y - tapex.y);
if (Behavior.NoExact)
{
denominator = 0.5 / (xdo * yao - xao * ydo);
@@ -350,10 +347,10 @@ namespace TriangleNet
{
if (offcenter && (Behavior.Offconstant > 0.0))
{
- dxoff = 0.5 * (tapex.X - tdest.X) -
- Behavior.Offconstant * (tapex.Y - tdest.Y);
- dyoff = 0.5 * (tapex.Y - tdest.Y) +
- Behavior.Offconstant * (tapex.X - tdest.X);
+ dxoff = 0.5 * (tapex.x - tdest.x) -
+ Behavior.Offconstant * (tapex.y - tdest.y);
+ dyoff = 0.5 * (tapex.y - tdest.y) +
+ Behavior.Offconstant * (tapex.x - tdest.x);
// If the off-center is closer to the destination than the
// circumcenter, use the off-center instead.
if (dxoff * dxoff + dyoff * dyoff <
@@ -365,7 +362,7 @@ namespace TriangleNet
}
}
- Point2 circumcenter = new Point2(torg.X + dx, torg.Y + dy);
+ Point circumcenter = new Point(torg.x + dx, torg.y + dy);
// To interpolate vertex attributes for the new vertex inserted at
// the circumcenter, define a coordinate system with a xi-axis,
@@ -377,87 +374,5 @@ namespace TriangleNet
return circumcenter;
}
-
-
- /*
- ///
- /// Return a positive value if the point pd lies below the plane passing
- /// through pa, pb, and pc; "below" is defined so that pa, pb, and pc appear
- /// in counterclockwise order when viewed from above the plane. The result is
- /// also a rough approximation of six times the signed volume of the
- /// tetrahedron defined by the four points.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- /// Return a positive value if the point pd lies below the plane
- /// passing through pa, pb, and pc. Returns a negative value if pd lies above
- /// the plane. Returns zero if the points are coplanar.
- ///
- /// Uses exact arithmetic if necessary to ensure a correct answer. The
- /// result returned is the determinant of a matrix. This determinant is
- /// computed adaptively, in the sense that exact arithmetic is used only to
- /// the degree it is needed to ensure that the returned value has the
- /// correct sign. Hence, this function is usually quite fast, but will run
- /// more slowly when the input points are coplanar or nearly so.
- ///
- /// See my Robust Predicates paper for details.
- ///
- public static double Orient3d2(Point2 pa, Point2 pb, Point2 pc, Point2 pd,
- double aheight, double bheight, double cheight, double dheight)
- {
- double adx, bdx, cdx, ady, bdy, cdy, adheight, bdheight, cdheight;
- double bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady;
- double det;
- double permanent, errbound;
-
- Statistic.Orient3dCount++;
-
- adx = pa.X - pd.X;
- bdx = pb.X - pd.X;
- cdx = pc.X - pd.X;
- ady = pa.Y - pd.Y;
- bdy = pb.Y - pd.Y;
- cdy = pc.Y - pd.Y;
- adheight = aheight - dheight;
- bdheight = bheight - dheight;
- cdheight = cheight - dheight;
-
- bdxcdy = bdx * cdy;
- cdxbdy = cdx * bdy;
-
- cdxady = cdx * ady;
- adxcdy = adx * cdy;
-
- adxbdy = adx * bdy;
- bdxady = bdx * ady;
-
- det = adheight * (bdxcdy - cdxbdy)
- + bdheight * (cdxady - adxcdy)
- + cdheight * (adxbdy - bdxady);
-
- if (Behavior.NoExact)
- {
- return det;
- }
-
- permanent = (Math.Abs(bdxcdy) + Math.Abs(cdxbdy)) * Math.Abs(adheight)
- + (Math.Abs(cdxady) + Math.Abs(adxcdy)) * Math.Abs(bdheight)
- + (Math.Abs(adxbdy) + Math.Abs(bdxady)) * Math.Abs(cdheight);
- errbound = o3derrboundA * permanent;
- if ((det > errbound) || (-det > errbound))
- {
- return det;
- }
-
- throw new Exception();
- //return orient3dadapt(pa, pb, pc, pd, aheight, bheight, cheight, dheight, permanent);
- }
- */
}
}
diff --git a/Triangle.NET/Triangle/Quality.cs b/Triangle.NET/Triangle/Quality.cs
index a094ae0..f1db6a6 100644
--- a/Triangle.NET/Triangle/Quality.cs
+++ b/Triangle.NET/Triangle/Quality.cs
@@ -11,6 +11,7 @@ namespace TriangleNet
using System.Collections.Generic;
using TriangleNet.Data;
using TriangleNet.Log;
+ using TriangleNet.Geometry;
///
/// Provides methods for mesh quality enforcement and testing.
@@ -20,7 +21,9 @@ namespace TriangleNet
Queue badsubsegs;
BadTriQueue queue;
Mesh mesh;
- Func userTest;
+
+ // Not used at the moment
+ Func userTest;
ILog logger;
@@ -34,9 +37,9 @@ namespace TriangleNet
}
///
- /// Deallocate space for a bad subsegment, marking it dead.
+ /// Add a bad subsegment to the queue.
///
- ///
+ /// Bad subsegment.
public void AddBadSubseg(BadSubseg badseg)
{
badsubsegs.Enqueue(badseg);
@@ -75,8 +78,10 @@ namespace TriangleNet
{ // Only test for inversion once.
// Test if the triangle is flat or inverted.
triapex = tri.Apex();
- if (Primitives.CounterClockwise(triorg.pt, tridest.pt, triapex.pt) <= 0.0)
+ if (Primitives.CounterClockwise(triorg, tridest, triapex) <= 0.0)
{
+ logger.Warning("Triangle is flat or inverted.",
+ "Quality.CheckMesh()");
horrors++;
}
}
@@ -183,16 +188,17 @@ namespace TriangleNet
// If a subsegment separates the triangles, then the edge is
// constrained, so no local Delaunay test should be done.
triangleloop.SegPivot(ref opposubseg);
- if (opposubseg.ss != Mesh.dummysub)
+ if (opposubseg.seg != Mesh.dummysub)
{
shouldbedelaunay = false;
}
}
if (shouldbedelaunay)
{
- if (Primitives.NonRegular(triorg.pt, tridest.pt, triapex.pt, oppoapex.pt) > 0.0)
+ if (Primitives.NonRegular(triorg, tridest, triapex, oppoapex) > 0.0)
{
- logger.Warning("Non-regular pair of triangles found.", "Quality.CheckDelaunay()");
+ string coords = triorg.ToString() + " " + tridest.ToString();
+ logger.Warning("Non-regular pair of triangles found. " + coords, "Quality.CheckDelaunay()");
horrors++;
}
}
@@ -223,7 +229,7 @@ namespace TriangleNet
///
/// Check a subsegment to see if it is encroached; add it to the list if it is.
///
- ///
+ /// The subsegment to check.
/// Returns a nonzero value if the subsegment is encroached.
///
/// A subsegment is encroached if there is a vertex in its diametral lens.
@@ -268,17 +274,17 @@ namespace TriangleNet
// of two sides of the triangle is used to check whether the angle
// at the apex is greater than (180 - 2 'minangle') degrees (for
// lenses; 90 degrees for diametral circles).
- dotproduct = (eorg.pt.X - eapex.pt.X) * (edest.pt.X - eapex.pt.X) +
- (eorg.pt.Y - eapex.pt.Y) * (edest.pt.Y - eapex.pt.Y);
+ dotproduct = (eorg.x - eapex.x) * (edest.x - eapex.x) +
+ (eorg.y - eapex.y) * (edest.y - eapex.y);
if (dotproduct < 0.0)
{
if (Behavior.ConformDel ||
(dotproduct * dotproduct >=
(2.0 * Behavior.GoodAngle - 1.0) * (2.0 * Behavior.GoodAngle - 1.0) *
- ((eorg.pt.X - eapex.pt.X) * (eorg.pt.X - eapex.pt.X) +
- (eorg.pt.Y - eapex.pt.Y) * (eorg.pt.Y - eapex.pt.Y)) *
- ((edest.pt.X - eapex.pt.X) * (edest.pt.X - eapex.pt.X) +
- (edest.pt.Y - eapex.pt.Y) * (edest.pt.Y - eapex.pt.Y))))
+ ((eorg.x - eapex.x) * (eorg.x - eapex.x) +
+ (eorg.y - eapex.y) * (eorg.y - eapex.y)) *
+ ((edest.x - eapex.x) * (edest.x - eapex.x) +
+ (edest.y - eapex.y) * (edest.y - eapex.y))))
{
encroached = 1;
}
@@ -295,17 +301,17 @@ namespace TriangleNet
eapex = neighbortri.Apex();
// Check whether the apex is in the diametral lens of the subsegment
// (or the diametral circle, if 'conformdel' is set).
- dotproduct = (eorg.pt.X - eapex.pt.X) * (edest.pt.X - eapex.pt.X) +
- (eorg.pt.Y - eapex.pt.Y) * (edest.pt.Y - eapex.pt.Y);
+ dotproduct = (eorg.x - eapex.x) * (edest.x - eapex.x) +
+ (eorg.y - eapex.y) * (edest.y - eapex.y);
if (dotproduct < 0.0)
{
if (Behavior.ConformDel ||
(dotproduct * dotproduct >=
(2.0 * Behavior.GoodAngle - 1.0) * (2.0 * Behavior.GoodAngle - 1.0) *
- ((eorg.pt.X - eapex.pt.X) * (eorg.pt.X - eapex.pt.X) +
- (eorg.pt.Y - eapex.pt.Y) * (eorg.pt.Y - eapex.pt.Y)) *
- ((edest.pt.X - eapex.pt.X) * (edest.pt.X - eapex.pt.X) +
- (edest.pt.Y - eapex.pt.Y) * (edest.pt.Y - eapex.pt.Y))))
+ ((eorg.x - eapex.x) * (eorg.x - eapex.x) +
+ (eorg.y - eapex.y) * (eorg.y - eapex.y)) *
+ ((edest.x - eapex.x) * (edest.x - eapex.x) +
+ (edest.y - eapex.y) * (edest.y - eapex.y))))
{
encroached += 2;
}
@@ -329,7 +335,7 @@ namespace TriangleNet
encroachedseg.subsegorg = edest;
encroachedseg.subsegdest = eorg;
}
-
+
badsubsegs.Enqueue(encroachedseg);
}
@@ -365,12 +371,12 @@ namespace TriangleNet
torg = testtri.Org();
tdest = testtri.Dest();
tapex = testtri.Apex();
- dxod = torg.pt.X - tdest.pt.X;
- dyod = torg.pt.Y - tdest.pt.Y;
- dxda = tdest.pt.X - tapex.pt.X;
- dyda = tdest.pt.Y - tapex.pt.Y;
- dxao = tapex.pt.X - torg.pt.X;
- dyao = tapex.pt.Y - torg.pt.Y;
+ dxod = torg.x - tdest.x;
+ dyod = torg.y - tdest.y;
+ dxda = tdest.x - tapex.x;
+ dyda = tdest.y - tapex.y;
+ dxao = tapex.x - torg.x;
+ dyao = tapex.y - torg.y;
dxod2 = dxod * dxod;
dyod2 = dyod * dyod;
dxda2 = dxda * dxda;
@@ -487,7 +493,7 @@ namespace TriangleNet
// Check if both points lie in a common segment. If they do, the
// skinny triangle is enqueued to be split as usual.
tri1.SegPivot(ref testsub);
- if (testsub.ss == Mesh.dummysub)
+ if (testsub.seg == Mesh.dummysub)
{
// No common segment. Find a subsegment that contains 'torg'.
tri1.Copy(ref tri2);
@@ -495,7 +501,7 @@ namespace TriangleNet
{
tri1.OprevSelf();
tri1.SegPivot(ref testsub);
- } while (testsub.ss == Mesh.dummysub);
+ } while (testsub.seg == Mesh.dummysub);
// Find the endpoints of the containing segment.
org1 = testsub.SegOrg();
dest1 = testsub.SegDest();
@@ -504,17 +510,17 @@ namespace TriangleNet
{
tri2.DnextSelf();
tri2.SegPivot(ref testsub);
- } while (testsub.ss == Mesh.dummysub);
+ } while (testsub.seg == Mesh.dummysub);
// Find the endpoints of the containing segment.
org2 = testsub.SegOrg();
dest2 = testsub.SegDest();
// Check if the two containing segments have an endpoint in common.
joinvertex = null;
- if ((dest1.pt.X == org2.pt.X) && (dest1.pt.Y == org2.pt.Y))
+ if ((dest1.x == org2.x) && (dest1.y == org2.y))
{
joinvertex = dest1;
}
- else if ((org1.pt.X == dest2.pt.X) && (org1.pt.Y == dest2.pt.Y))
+ else if ((org1.x == dest2.x) && (org1.y == dest2.y))
{
joinvertex = org1;
}
@@ -522,10 +528,10 @@ namespace TriangleNet
{
// Compute the distance from the common endpoint (of the two
// segments) to each of the endpoints of the shortest edge.
- dist1 = ((base1.pt.X - joinvertex.pt.X) * (base1.pt.X - joinvertex.pt.X) +
- (base1.pt.Y - joinvertex.pt.Y) * (base1.pt.Y - joinvertex.pt.Y));
- dist2 = ((base2.pt.X - joinvertex.pt.X) * (base2.pt.X - joinvertex.pt.X) +
- (base2.pt.Y - joinvertex.pt.Y) * (base2.pt.Y - joinvertex.pt.Y));
+ dist1 = ((base1.x - joinvertex.x) * (base1.x - joinvertex.x) +
+ (base1.y - joinvertex.y) * (base1.y - joinvertex.y));
+ dist2 = ((base2.x - joinvertex.x) * (base2.x - joinvertex.x) +
+ (base2.y - joinvertex.y) * (base2.y - joinvertex.y));
// If the two distances are equal, don't split the triangle.
if ((dist1 < 1.001 * dist2) && (dist1 > 0.999 * dist2))
{
@@ -549,19 +555,16 @@ namespace TriangleNet
/// Traverse the entire list of subsegments, and check each to see if it
/// is encroached. If so, add it to the list.
///
- void TallyEncs()
+ private void TallyEncs()
{
Osub subsegloop = default(Osub);
- int dummy;
+ subsegloop.orient = 0;
- subsegloop.ssorient = 0;
-
- foreach (var s in mesh.subsegs.Values)
+ foreach (var seg in mesh.subsegs.Values)
{
- subsegloop.ss = s;
+ subsegloop.seg = seg;
// If the segment is encroached, add it to the list.
- dummy = CheckSeg4Encroach(ref subsegloop);
- //subsegloop.ss = subsegtraverse(m);
+ CheckSeg4Encroach(ref subsegloop);
}
}
@@ -576,7 +579,7 @@ namespace TriangleNet
/// vertex at or near its midpoint. Newly inserted vertices may encroach
/// upon other subsegments; these are also repaired.
///
- void SplitEncSegs(bool triflaws)
+ private void SplitEncSegs(bool triflaws)
{
Otri enctri = default(Otri);
Otri testtri = default(Otri);
@@ -610,7 +613,7 @@ namespace TriangleNet
// when it was determined to be encroached. If the segment was
// enqueued multiple times (because several newly inserted
// vertices encroached it), it may have already been split.
- if (!Osub.IsDead(currentenc.ss) && (eorg == seg.subsegorg) && (edest == seg.subsegdest))
+ if (!Osub.IsDead(currentenc.seg) && (eorg == seg.subsegorg) && (edest == seg.subsegdest))
{
// To decide where to split a segment, we need to know if the
// segment shares an endpoint with an adjacent segment.
@@ -631,11 +634,11 @@ namespace TriangleNet
currentenc.TriPivot(ref enctri);
enctri.Lnext(ref testtri);
testtri.SegPivot(ref testsh);
- acuteorg = testsh.ss != Mesh.dummysub;
+ acuteorg = testsh.seg != Mesh.dummysub;
// Is the destination shared with another segment?
testtri.LnextSelf();
testtri.SegPivot(ref testsh);
- acutedest = testsh.ss != Mesh.dummysub;
+ acutedest = testsh.seg != Mesh.dummysub;
// If we're using Chew's algorithm (rather than Ruppert's)
// to define encroachment, delete free vertices from the
@@ -644,8 +647,8 @@ namespace TriangleNet
{
eapex = enctri.Apex();
while ((eapex.type == VertexType.FreeVertex) &&
- ((eorg.pt.X - eapex.pt.X) * (edest.pt.X - eapex.pt.X) +
- (eorg.pt.Y - eapex.pt.Y) * (edest.pt.Y - eapex.pt.Y) < 0.0))
+ ((eorg.x - eapex.x) * (edest.x - eapex.x) +
+ (eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
{
mesh.DeleteVertex(ref testtri);
currentenc.TriPivot(ref enctri);
@@ -661,12 +664,12 @@ namespace TriangleNet
// Is the destination shared with another segment?
testtri.LnextSelf();
testtri.SegPivot(ref testsh);
- acutedest2 = testsh.ss != Mesh.dummysub;
+ acutedest2 = testsh.seg != Mesh.dummysub;
acutedest = acutedest || acutedest2;
// Is the origin shared with another segment?
testtri.LnextSelf();
testtri.SegPivot(ref testsh);
- acuteorg2 = testsh.ss != Mesh.dummysub;
+ acuteorg2 = testsh.seg != Mesh.dummysub;
acuteorg = acuteorg || acuteorg2;
// Delete free vertices from the subsegment's diametral circle.
@@ -674,8 +677,8 @@ namespace TriangleNet
{
eapex = testtri.Org();
while ((eapex.type == VertexType.FreeVertex) &&
- ((eorg.pt.X - eapex.pt.X) * (edest.pt.X - eapex.pt.X) +
- (eorg.pt.Y - eapex.pt.Y) * (edest.pt.Y - eapex.pt.Y) < 0.0))
+ ((eorg.x - eapex.x) * (edest.x - eapex.x) +
+ (eorg.y - eapex.y) * (edest.y - eapex.y) < 0.0))
{
mesh.DeleteVertex(ref testtri);
enctri.Sym(ref testtri);
@@ -689,8 +692,8 @@ namespace TriangleNet
// with another adjacent segment.
if (acuteorg || acutedest)
{
- segmentlength = Math.Sqrt((edest.pt.X - eorg.pt.X) * (edest.pt.X - eorg.pt.X) +
- (edest.pt.Y - eorg.pt.Y) * (edest.pt.Y - eorg.pt.Y));
+ segmentlength = Math.Sqrt((edest.x - eorg.x) * (edest.x - eorg.x) +
+ (edest.y - eorg.y) * (edest.y - eorg.y));
// Find the power of two that most evenly splits the segment.
// The worst case is a 2:1 ratio between subsegment lengths.
nearestpoweroftwo = 1.0;
@@ -717,8 +720,12 @@ namespace TriangleNet
}
// Create the new vertex.
- newvertex = new Vertex(mesh.nextras);
- mesh.vertices.Add(newvertex.Hash, newvertex);
+ newvertex = new Vertex(); // TODO: mesh.nextras
+
+ newvertex.hash = mesh.hash_vtx++;
+ newvertex.id = newvertex.hash;
+
+ mesh.vertices.Add(newvertex.hash, newvertex);
// Interpolate its coordinate and attributes.
for (int i = 0; i < mesh.nextras; i++)
@@ -727,25 +734,25 @@ namespace TriangleNet
+ split * (edest.attributes[i] - eorg.attributes[i]);
}
- newvertex.pt.X = eorg.pt.X + split * (edest.pt.X - eorg.pt.X);
- newvertex.pt.Y = eorg.pt.Y + split * (edest.pt.Y - eorg.pt.Y);
+ newvertex.x = eorg.x + split * (edest.x - eorg.x);
+ newvertex.y = eorg.y + split * (edest.y - eorg.y);
if (!Behavior.NoExact)
{
// Roundoff in the above calculation may yield a 'newvertex'
// that is not precisely collinear with 'eorg' and 'edest'.
// Improve collinearity by one step of iterative refinement.
- multiplier = Primitives.CounterClockwise(eorg.pt, edest.pt, newvertex.pt);
- divisor = ((eorg.pt.X - edest.pt.X) * (eorg.pt.X - edest.pt.X) +
- (eorg.pt.Y - edest.pt.Y) * (eorg.pt.Y - edest.pt.Y));
+ multiplier = Primitives.CounterClockwise(eorg, edest, newvertex);
+ divisor = ((eorg.x - edest.x) * (eorg.x - edest.x) +
+ (eorg.y - edest.y) * (eorg.y - edest.y));
if ((multiplier != 0.0) && (divisor != 0.0))
{
multiplier = multiplier / divisor;
// Watch out for NANs.
if (!double.IsNaN(multiplier))
{
- newvertex.pt.X += multiplier * (edest.pt.Y - eorg.pt.Y);
- newvertex.pt.Y += multiplier * (eorg.pt.X - edest.pt.X);
+ newvertex.x += multiplier * (edest.y - eorg.y);
+ newvertex.y += multiplier * (eorg.x - edest.x);
}
}
}
@@ -754,8 +761,8 @@ namespace TriangleNet
newvertex.type = VertexType.SegmentVertex;
// Check whether the new vertex lies on an endpoint.
- if (((newvertex.pt.X == eorg.pt.X) && (newvertex.pt.Y == eorg.pt.Y)) ||
- ((newvertex.pt.X == edest.pt.X) && (newvertex.pt.Y == edest.pt.Y)))
+ if (((newvertex.x == eorg.x) && (newvertex.y == eorg.y)) ||
+ ((newvertex.x == edest.x) && (newvertex.y == edest.y)))
{
logger.Error("Ran out of precision: I attempted to split a"
@@ -791,15 +798,14 @@ namespace TriangleNet
///
/// Test every triangle in the mesh for quality measures.
///
- void TallyFaces()
+ private void TallyFaces()
{
Otri triangleloop = default(Otri);
-
triangleloop.orient = 0;
- foreach (var t in mesh.triangles.Values)
+ foreach (var tri in mesh.triangles.Values)
{
- triangleloop.triangle = t;
+ triangleloop.triangle = tri;
// If the triangle is bad, enqueue it.
TestTriangle(ref triangleloop);
@@ -811,7 +817,7 @@ namespace TriangleNet
/// the newly inserted vertex if it encroaches upon a segment.
///
///
- void SplitTriangle(BadTriangle badtri)
+ private void SplitTriangle(BadTriangle badtri)
{
Otri badotri = default(Otri);
Vertex borg, bdest, bapex;
@@ -819,7 +825,6 @@ namespace TriangleNet
double xi = 0, eta = 0;
InsertVertexResult success;
bool errorflag;
- int i;
badotri = badtri.poortri;
borg = badotri.Org();
@@ -834,7 +839,7 @@ namespace TriangleNet
{
errorflag = false;
// Create a new vertex at the triangle's circumcenter.
- newvertex = new Vertex(mesh.nextras);
+ newvertex = new Vertex(); // TODO: mesh.nextras
// Using the original (simpler) Steiner point location method
// for mesh refinement.
@@ -842,7 +847,9 @@ namespace TriangleNet
// reset VertexType?
if (Behavior.FixedArea || Behavior.VarArea)
{
- newvertex.pt = Primitives.FindCircumcenter(borg.pt, bdest.pt, bapex.pt, ref xi, ref eta, true);
+ Point tmp = Primitives.FindCircumcenter(borg, bdest, bapex, ref xi, ref eta, true);
+ newvertex.x = tmp.x;
+ newvertex.y = tmp.y;
}
else
{
@@ -850,9 +857,9 @@ namespace TriangleNet
}
// Check whether the new vertex lies on a triangle vertex.
- if (((newvertex.pt.X == borg.pt.X) && (newvertex.pt.Y == borg.pt.Y)) ||
- ((newvertex.pt.X == bdest.pt.X) && (newvertex.pt.Y == bdest.pt.Y)) ||
- ((newvertex.pt.X == bapex.pt.X) && (newvertex.pt.Y == bapex.pt.Y)))
+ if (((newvertex.x == borg.x) && (newvertex.y == borg.y)) ||
+ ((newvertex.x == bdest.x) && (newvertex.y == bdest.y)) ||
+ ((newvertex.x == bapex.x) && (newvertex.y == bapex.y)))
{
if (Behavior.Verbose)
{
@@ -862,7 +869,7 @@ namespace TriangleNet
}
else
{
- for (i = 0; i < mesh.nextras; i++)
+ for (int i = 0; i < mesh.nextras; i++)
{
// Interpolate the vertex attributes at the circumcenter.
newvertex.attributes[i] = borg.attributes[i]
@@ -871,8 +878,8 @@ namespace TriangleNet
}
// The new vertex must be in the interior, and therefore is a
// free vertex with a marker of zero.
- newvertex.mark = 0;
newvertex.type = VertexType.FreeVertex;
+ //newvertex.mark = 0;
// Ensure that the handle 'badotri' does not represent the longest
// edge of the triangle. This ensures that the circumcenter must
@@ -893,7 +900,10 @@ namespace TriangleNet
if (success == InsertVertexResult.Successful)
{
- mesh.vertices.Add(newvertex.Hash, newvertex);
+ newvertex.hash = mesh.hash_vtx++;
+ newvertex.id = newvertex.hash;
+
+ mesh.vertices.Add(newvertex.hash, newvertex);
if (mesh.steinerleft > 0)
{
@@ -971,11 +981,6 @@ namespace TriangleNet
// Record any new bad triangles that result.
SplitEncSegs(true);
}
- else
- {
- // Return the bad triangle to the pool.
- //queue.badtriangles.Remove(badtri);
- }
}
}
@@ -986,13 +991,14 @@ namespace TriangleNet
// Might we have run out of Steiner points too soon?
if (Behavior.Verbose && Behavior.ConformDel && (badsubsegs.Count > 0) && (mesh.steinerleft == 0))
{
-
+
logger.Warning("I ran out of Steiner points, but the mesh has encroached subsegments, "
+ "and therefore might not be truly Delaunay. If the Delaunay property is important "
- + "to you, try increasing the number of Steiner points",
+ + "to you, try increasing the number of Steiner points",
"Quality.EnforceQuality()");
}
}
+
#endregion
}
}
diff --git a/Triangle.NET/Triangle/Statistic.cs b/Triangle.NET/Triangle/Tools/Statistic.cs
similarity index 93%
rename from Triangle.NET/Triangle/Statistic.cs
rename to Triangle.NET/Triangle/Tools/Statistic.cs
index 150c87a..620005e 100644
--- a/Triangle.NET/Triangle/Statistic.cs
+++ b/Triangle.NET/Triangle/Tools/Statistic.cs
@@ -5,11 +5,12 @@
//
// -----------------------------------------------------------------------
-namespace TriangleNet
+namespace TriangleNet.Tools
{
using System;
using System.Text;
using TriangleNet.Data;
+ using TriangleNet.Geometry;
///
/// Gather mesh statistics.
@@ -74,7 +75,7 @@ namespace TriangleNet
///
/// Gets the shortest altitude.
///
- public double ShortestAltitude { get { return minAspect; } }
+ public double ShortestAltitude { get { return minAspect; } }
double maxAspect = 0;
///
@@ -224,8 +225,8 @@ namespace TriangleNet
{
j = plus1Mod3[i];
k = minus1Mod3[i];
- dx[i] = p[j].pt.X - p[k].pt.X;
- dy[i] = p[j].pt.Y - p[k].pt.Y;
+ dx[i] = p[j].x - p[k].x;
+ dy[i] = p[j].y - p[k].y;
edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i];
if (edgelength[i] > trilongest2)
{
@@ -234,8 +235,8 @@ namespace TriangleNet
}
//triarea = Primitives.CounterClockwise(p[0], p[1], p[2]);
- triarea = Math.Abs((p[2].pt.X - p[0].pt.X) * (p[1].pt.Y - p[0].pt.Y) -
- (p[1].pt.X - p[0].pt.X) * (p[2].pt.Y - p[0].pt.Y)) / 2.0;
+ triarea = Math.Abs((p[2].x - p[0].x) * (p[1].y - p[0].y) -
+ (p[1].x - p[0].x) * (p[2].y - p[0].y)) / 2.0;
triminaltitude2 = triarea * triarea / trilongest2;
@@ -272,7 +273,7 @@ namespace TriangleNet
intBoundaryEdges = mesh.subsegs.Count - (int)mesh.hullsize;
constrainedEdges = mesh.subsegs.Count;
- Point2[] p = new Point2[3];
+ Point[] p = new Point[3];
int k1, k2;
int degreeStep;
@@ -310,7 +311,7 @@ namespace TriangleNet
angleTable[i] = 0;
}
- minAspect = mesh.xmax - mesh.xmin + mesh.ymax - mesh.ymin;
+ minAspect = mesh.bounds.Width + mesh.bounds.Height;
minAspect = minAspect * minAspect;
maxAspect = 0.0;
minEdge = minAspect;
@@ -330,9 +331,9 @@ namespace TriangleNet
triMinAngle = 0; // Min angle: 0 < a < 60 degress
triMaxAngle = 1; // Max angle: 60 < a < 180 degress
- p[0] = tri.vertices[0].pt;
- p[1] = tri.vertices[1].pt;
- p[2] = tri.vertices[2].pt;
+ p[0] = tri.vertices[0];
+ p[1] = tri.vertices[1];
+ p[2] = tri.vertices[2];
triLongest2 = 0.0;
@@ -476,7 +477,7 @@ namespace TriangleNet
{
maxAngles[sampleDegrees - degreeStep - 1]++;
}
-
+
acuteBiggestTri = true;
}
diff --git a/Triangle.NET/Triangle/Triangle.csproj b/Triangle.NET/Triangle/Triangle.csproj
index 07e5998..fe17888 100644
--- a/Triangle.NET/Triangle/Triangle.csproj
+++ b/Triangle.NET/Triangle/Triangle.csproj
@@ -47,25 +47,23 @@
-
-
-
-
-
-
+
+
+
+
@@ -82,9 +80,8 @@
-
+
-