Replaced old test app with mesh explorer
Removed MeshData class (use InputGeometry for mesh input) Direct access to mesh geometry using public properties Lots of smaller changes git-svn-id: https://triangle.svn.codeplex.com/svn@67719 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// Displays an angle histogram.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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)
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ColorScheme.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </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);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
|
||||
namespace TestApp.Controls
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SliderDark.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates control that visualy displays certain integer value and allows user to change
|
||||
/// it within desired range. It imitates <see cref="System.Windows.Forms.TrackBar"/> as far as
|
||||
/// mouse usage is concerned.
|
||||
/// </summary>
|
||||
public class DarkSlider : Control
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Fires when Slider position has changed
|
||||
/// </summary>
|
||||
public event EventHandler ValueChanging;
|
||||
|
||||
private void OnValueChanging()
|
||||
{
|
||||
var evt = ValueChanging;
|
||||
|
||||
if (evt != null)
|
||||
{
|
||||
evt(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires when Slider position has changed
|
||||
/// </summary>
|
||||
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;
|
||||
/// <summary>
|
||||
/// Gets or sets the value of Slider.
|
||||
/// </summary>
|
||||
/// <value>The value.</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;
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value.
|
||||
/// </summary>
|
||||
/// <value>The minimum value.</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;
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum value.
|
||||
/// </summary>
|
||||
/// <value>The maximum value.</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;
|
||||
/// <summary>
|
||||
/// Gets or sets trackbar's small change. It affects how to behave when directional keys are pressed
|
||||
/// </summary>
|
||||
/// <value>The small change value.</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
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ColorSlider"/> class.
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.Forms.Control.Paint"></see> event.
|
||||
/// </summary>
|
||||
/// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"></see> that contains the event data.</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the colorslider control using passed colors.
|
||||
/// </summary>
|
||||
/// <param name="e">The <see cref="T:System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
|
||||
/// <param name="thumbOuterColorPaint">The thumb outer color paint.</param>
|
||||
/// <param name="thumbInnerColorPaint">The thumb inner color paint.</param>
|
||||
/// <param name="thumbPenColorPaint">The thumb pen color paint.</param>
|
||||
/// <param name="barOuterColorPaint">The bar outer color paint.</param>
|
||||
/// <param name="barInnerColorPaint">The bar inner color paint.</param>
|
||||
/// <param name="barPenColorPaint">The bar pen color paint.</param>
|
||||
/// <param name="elapsedOuterColorPaint">The elapsed outer color paint.</param>
|
||||
/// <param name="elapsedInnerColorPaint">The elapsed inner color paint.</param>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.Forms.Control.EnabledChanged"></see> event.
|
||||
/// </summary>
|
||||
/// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
|
||||
protected override void OnEnabledChanged(EventArgs e)
|
||||
{
|
||||
base.OnEnabledChanged(e);
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.Forms.Control.MouseLeave"></see> event.
|
||||
/// </summary>
|
||||
/// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
|
||||
protected override void OnMouseLeave(EventArgs e)
|
||||
{
|
||||
base.OnMouseLeave(e);
|
||||
mouseInThumbRegion = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.Forms.Control.MouseDown"></see> event.
|
||||
/// </summary>
|
||||
/// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
|
||||
protected override void OnMouseDown(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
this.Capture = true;
|
||||
OnValueChanging();
|
||||
OnMouseMove(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.Forms.Control.MouseMove"></see> event.
|
||||
/// </summary>
|
||||
/// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="E:System.Windows.Forms.Control.MouseUp"></see> event.
|
||||
/// </summary>
|
||||
/// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
|
||||
protected override void OnMouseUp(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
this.Capture = false;
|
||||
mouseInThumbRegion = thumbRect.Contains(e.Location);
|
||||
OnValueChanged();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Help routines
|
||||
|
||||
/// <summary>
|
||||
/// Sets the trackbar value so that it wont exceed allowed range.
|
||||
/// </summary>
|
||||
/// <param name="val">The value.</param>
|
||||
private void SetProperValue(int val)
|
||||
{
|
||||
if (val < barMinimum) Value = barMinimum;
|
||||
else if (val > barMaximum) Value = barMaximum;
|
||||
else Value = val;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
/// Summary description for FlatTabControl.
|
||||
/// </summary>
|
||||
public class DarkTabControl : System.Windows.Forms.TabControl
|
||||
{
|
||||
#region Designer
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TestApp.Controls
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="DarkToolStripRenderer.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer.Controls
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,24 +4,24 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh using GDI.
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// Code of the online examples.
|
||||
///
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drawing the Voronoi diagram.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smoothing a mesh.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Smoothing a mesh.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+89
@@ -0,0 +1,89 @@
|
||||
namespace MeshExplorer
|
||||
{
|
||||
partial class FormLog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.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;
|
||||
}
|
||||
}
|
||||
@@ -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<SimpleLogItem> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+797
-99
@@ -1,4 +1,4 @@
|
||||
namespace TestApp
|
||||
namespace MeshExplorer
|
||||
{
|
||||
partial class FormMain
|
||||
{
|
||||
@@ -28,148 +28,846 @@
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+422
-188
@@ -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<double[]> points = new List<double[]>();
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,4 +117,7 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
+11
-432
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="UcdFile.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </summary>
|
||||
public class JsonFile : MeshExplorer.IO.IMeshFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the supported file extensions.
|
||||
/// </summary>
|
||||
public string[] Extensions
|
||||
{
|
||||
get { return new string[] { ".json" }; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="filename"></param>
|
||||
/// <returns></returns>
|
||||
public InputGeometry Read(string filename)
|
||||
{
|
||||
string json = File.ReadAllText(filename);
|
||||
|
||||
JsonParser parser = new JsonParser("json");
|
||||
object rawData = parser.Decode();
|
||||
|
||||
InputGeometry data = new InputGeometry();
|
||||
|
||||
List<ITriangle> triangles = new List<ITriangle>();
|
||||
|
||||
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("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="TriangleFile.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </summary>
|
||||
public class TriangleFile : MeshExplorer.IO.IMeshFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the supported file extensions.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TestApp
|
||||
namespace MeshExplorer
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
@@ -20,8 +20,7 @@ namespace TestApp
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color scheme.
|
||||
/// </summary>
|
||||
@@ -39,7 +38,7 @@ namespace TestApp
|
||||
/// <param name="steiner">Steiner points color.</param>
|
||||
/// <param name="lines">Line color.</param>
|
||||
/// <param name="segments">Segment color.</param>
|
||||
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
|
||||
/// <param name="width">The target width of the image (pixel).</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the voronoi diagram and writes the image file.
|
||||
/// </summary>
|
||||
/// <param name="mesh">The mesh to visualize.</param>
|
||||
/// <param name="filename">The filename (only PNG supported).</param>
|
||||
/// <param name="width">The target width of the image (pixel).</param>
|
||||
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
|
||||
/// <summary>
|
||||
/// Draw mesh to the graphics object.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw mesh to the graphics object.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Bounding box.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Controls\ColorScheme.cs" />
|
||||
<Compile Include="Controls\DarkButton.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
@@ -55,10 +56,29 @@
|
||||
<Compile Include="Controls\AngleHistogram.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkListBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkSlider.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkTabControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkTextBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Controls\DarkToolStripRenderer.cs" />
|
||||
<Compile Include="DarkMessageBox.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Examples.cs" />
|
||||
<Compile Include="FormLog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FormLog.Designer.cs">
|
||||
<DependentUpon>FormLog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormMain.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -77,12 +97,16 @@
|
||||
<Compile Include="ImageWriter.cs" />
|
||||
<Compile Include="IO\FileProcessor.cs" />
|
||||
<Compile Include="IO\Formats\DatFile.cs" />
|
||||
<Compile Include="IO\Formats\JsonFile.cs" />
|
||||
<Compile Include="IO\Formats\TriangleFile.cs" />
|
||||
<Compile Include="IO\IMeshFormat.cs" />
|
||||
<Compile Include="IO\JsonParser.cs" />
|
||||
<Compile Include="PolygonGenerator.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Rendering\RenderData.cs" />
|
||||
<Compile Include="Rendering\Zoom.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<EmbeddedResource Include="FormMain.resx">
|
||||
<DependentUpon>FormMain.cs</DependentUpon>
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="PolygonGenerator.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TestApp
|
||||
namespace MeshExplorer
|
||||
{
|
||||
static class Program
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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<ITriangle> 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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <remarks>This methods assumes that the mesh.Renumber() has been called.</remarks>
|
||||
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<Edge> edgeList = new List<Edge>(mesh.NumberOfEdges);
|
||||
|
||||
while (e.MoveNext())
|
||||
{
|
||||
edgeList.Add(e.Current);
|
||||
}
|
||||
|
||||
this.Edges = edgeList.ToArray();
|
||||
}
|
||||
|
||||
private void SetPoints(IEnumerable<Vertex> 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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()
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Settings.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshExplorer
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Form a Delaunay triangulation by the divide-and-conquer method.
|
||||
/// </summary>
|
||||
@@ -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;
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace TriangleNet.Algorithm
|
||||
{
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Log;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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;
|
||||
|
||||
@@ -13,27 +13,14 @@ namespace TriangleNet.Algorithm
|
||||
using System.Text;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Log;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a delaunay triangulation using the sweepline algorithm.
|
||||
/// </summary>
|
||||
class SweepLine
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.).
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// A node in a heap used to store events for the sweepline Delaunay algorithm.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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'.
|
||||
/// </remarks>
|
||||
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.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.).
|
||||
/// </summary>
|
||||
class SweepEventVertex : Vertex
|
||||
{
|
||||
public SweepEvent evt;
|
||||
|
||||
public SweepEventVertex(SweepEvent e)
|
||||
{
|
||||
evt = e;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A node in the splay tree.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,13 @@ namespace TriangleNet
|
||||
using TriangleNet.Data;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// A (priority) queue for bad triangles.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
// 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.
|
||||
/// </remarks>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Add a bad triangle data structure to the end of a queue.
|
||||
/// </summary>
|
||||
/// <param name="badtri"></param>
|
||||
/// <remarks>
|
||||
// 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.
|
||||
/// </remarks>
|
||||
/// <param name="badtri">The bad triangle to enqueue.</param>
|
||||
public void Enqueue(BadTriangle badtri)
|
||||
{
|
||||
double length, multiplier;
|
||||
@@ -154,9 +151,6 @@ namespace TriangleNet
|
||||
/// <param name="enqapex"></param>
|
||||
/// <param name="enqorg"></param>
|
||||
/// <param name="enqdest"></param>
|
||||
/// <remarks>
|
||||
/// Allocates a badtriang data structure for the triangle, then passes it to enqueuebadtriang().
|
||||
/// </remarks>
|
||||
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
|
||||
/// <returns></returns>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,32 +15,104 @@ namespace TriangleNet
|
||||
/// </summary>
|
||||
static class Behavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Input is a Planar Straight Line Graph.
|
||||
/// </summary>
|
||||
public static bool Poly { get; set; }
|
||||
/// <summary>
|
||||
/// Quality mesh generation.
|
||||
/// </summary>
|
||||
public static bool Quality { get; set; }
|
||||
/// <summary>
|
||||
/// Apply a maximum triangle area constraint.
|
||||
/// </summary>
|
||||
public static bool VarArea { get; set; }
|
||||
/// <summary>
|
||||
/// Apply a maximum triangle area constraint.
|
||||
/// </summary>
|
||||
public static bool FixedArea { get; set; }
|
||||
/// <summary>
|
||||
/// Apply a user-defined triangle constraint.
|
||||
/// </summary>
|
||||
public static bool Usertest { get; set; }
|
||||
/// <summary>
|
||||
/// Apply attributes to identify triangles in certain regions.
|
||||
/// </summary>
|
||||
public static bool RegionAttrib { get; set; }
|
||||
/// <summary>
|
||||
/// Enclose the convex hull with segments.
|
||||
/// </summary>
|
||||
public static bool Convex { get; set; }
|
||||
/// <summary>
|
||||
/// Jettison unused vertices from output.
|
||||
/// </summary>
|
||||
public static bool Jettison { get; set; }
|
||||
/// <summary>
|
||||
/// Compute boundary information.
|
||||
/// </summary>
|
||||
public static bool UseBoundaryMarkers { get; set; }
|
||||
/// <summary>
|
||||
/// Ignores holes in polygons.
|
||||
/// </summary>
|
||||
public static bool NoHoles { get; set; }
|
||||
/// <summary>
|
||||
/// No exact arithmetic.
|
||||
/// </summary>
|
||||
public static bool NoExact { get; set; }
|
||||
/// <summary>
|
||||
/// Conforming Delaunay (all triangles are truly Delaunay).
|
||||
/// </summary>
|
||||
public static bool ConformDel { get; set; }
|
||||
/// <summary>
|
||||
/// Algorithm to use for triangulation.
|
||||
/// </summary>
|
||||
public static TriangulationAlgorithm Algorithm { get; set; }
|
||||
/// <summary>
|
||||
/// Log detailed information.
|
||||
/// </summary>
|
||||
public static bool Verbose { get; set; }
|
||||
public static bool UseSegments { get; set; }
|
||||
/// <summary>
|
||||
/// Use segments (should not be set manually)
|
||||
/// </summary>
|
||||
public static bool UseSegments { get; set; } // TODO: internal set
|
||||
|
||||
public static int NoBisect { get; set; } // <- int
|
||||
/// <summary>
|
||||
/// Suppresses boundary segment splitting.
|
||||
/// </summary>
|
||||
public static int NoBisect { get; set; } // <- int !
|
||||
/// <summary>
|
||||
/// Use maximum number of added Steiner points.
|
||||
/// </summary>
|
||||
public static int Steiner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Minimum angle constraint.
|
||||
/// </summary>
|
||||
public static double MinAngle { get; set; }
|
||||
/// <summary>
|
||||
/// (should not be set manually)
|
||||
/// </summary>
|
||||
public static double GoodAngle { get; set; }
|
||||
/// <summary>
|
||||
/// (should not be set manually)
|
||||
/// </summary>
|
||||
public static double Offconstant { get; set; }
|
||||
/// <summary>
|
||||
/// Maximum area constraint.
|
||||
/// </summary>
|
||||
public static double MaxArea { get; set; }
|
||||
/// <summary>
|
||||
/// Maximum angle constraint.
|
||||
/// </summary>
|
||||
public static double MaxAngle { get; set; }
|
||||
/// <summary>
|
||||
/// (should not be set manually)
|
||||
/// </summary>
|
||||
public static double MaxGoodAngle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Load behavior defaults.
|
||||
/// </summary>
|
||||
public static void Init()
|
||||
{
|
||||
Poly = false;
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace TriangleNet
|
||||
{
|
||||
using TriangleNet.Data;
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="holelist"></param>
|
||||
/// <param name="holes"></param>
|
||||
/// <param name="regionlist"></param>
|
||||
/// <param name="regions"></param>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="FlipStacker.cs" company="">
|
||||
// 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/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Data
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// A stack of triangles flipped during the most recent vertex insertion.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The stack is used to undo the vertex insertion if the vertex encroaches
|
||||
/// upon a subsegment.
|
||||
/// </remarks>
|
||||
class FlipStacker
|
||||
{
|
||||
public Otri flippedtri; // A recently flipped triangle.
|
||||
public FlipStacker prevflip; // Previous flip in the stack.
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,16 @@ namespace TriangleNet.Data
|
||||
/// </remarks>
|
||||
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
|
||||
/// </remarks>
|
||||
public void Sym(ref Osub o2)
|
||||
{
|
||||
o2.ss = ss;
|
||||
o2.ssorient = 1 - ssorient;
|
||||
o2.seg = seg;
|
||||
o2.orient = 1 - orient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,7 +53,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SymSelf()
|
||||
{
|
||||
ssorient = 1 - ssorient;
|
||||
orient = 1 - orient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,7 +64,7 @@ namespace TriangleNet.Data
|
||||
/// </remarks>
|
||||
public void Pivot(ref Osub o2)
|
||||
{
|
||||
o2 = ss.subsegs[ssorient];
|
||||
o2 = seg.subsegs[orient];
|
||||
//sdecode(sptr, o2);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void PivotSelf()
|
||||
{
|
||||
this = ss.subsegs[ssorient];
|
||||
this = seg.subsegs[orient];
|
||||
//sdecode(sptr, osub);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace TriangleNet.Data
|
||||
/// </remarks>
|
||||
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
|
||||
/// </summary>
|
||||
public void NextSelf()
|
||||
{
|
||||
this = ss.subsegs[1 - ssorient];
|
||||
this = seg.subsegs[1 - orient];
|
||||
//sdecode(sptr, osub);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public Vertex Org()
|
||||
{
|
||||
return ss.vertices[ssorient];
|
||||
return seg.vertices[orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,7 +111,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public Vertex Dest()
|
||||
{
|
||||
return ss.vertices[1 - ssorient];
|
||||
return seg.vertices[1 - orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -119,7 +119,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SetOrg(Vertex ptr)
|
||||
{
|
||||
ss.vertices[ssorient] = ptr;
|
||||
seg.vertices[orient] = ptr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -127,7 +127,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SetDest(Vertex ptr)
|
||||
{
|
||||
ss.vertices[1 - ssorient] = ptr;
|
||||
seg.vertices[1 - orient] = ptr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,7 +135,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public Vertex SegOrg()
|
||||
{
|
||||
return ss.vertices[2 + ssorient];
|
||||
return seg.vertices[2 + orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -143,7 +143,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public Vertex SegDest()
|
||||
{
|
||||
return ss.vertices[3 - ssorient];
|
||||
return seg.vertices[3 - orient];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,7 +151,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SetSegOrg(Vertex ptr)
|
||||
{
|
||||
ss.vertices[2 + ssorient] = ptr;
|
||||
seg.vertices[2 + orient] = ptr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -159,7 +159,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SetSegDest(Vertex ptr)
|
||||
{
|
||||
ss.vertices[3 - ssorient] = ptr;
|
||||
seg.vertices[3 - orient] = ptr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -169,7 +169,7 @@ namespace TriangleNet.Data
|
||||
/// setting boundary conditions in finite element solvers.</remarks>
|
||||
public int Mark()
|
||||
{
|
||||
return ss.boundary;
|
||||
return seg.boundary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -177,7 +177,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SetMark(int value)
|
||||
{
|
||||
ss.boundary = value;
|
||||
seg.boundary = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -185,8 +185,8 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -196,7 +196,7 @@ namespace TriangleNet.Data
|
||||
/// connected to this subsegment.</remarks>
|
||||
public void Dissolve()
|
||||
{
|
||||
ss.subsegs[ssorient].ss = Mesh.dummysub;
|
||||
seg.subsegs[orient].seg = Mesh.dummysub;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -204,8 +204,8 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void Copy(ref Osub o2)
|
||||
{
|
||||
o2.ss = ss;
|
||||
o2.ssorient = ssorient;
|
||||
o2.seg = seg;
|
||||
o2.orient = orient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,24 +213,24 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public bool Equal(Osub o2)
|
||||
{
|
||||
return ((ss == o2.ss) && (ssorient == o2.ssorient));
|
||||
return ((seg == o2.seg) && (orient == o2.orient));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check a subsegment's deallocation.
|
||||
/// </summary>
|
||||
public static bool IsDead(Subseg sub)
|
||||
public static bool IsDead(Segment sub)
|
||||
{
|
||||
return sub.subsegs[0].ss == null;
|
||||
return sub.subsegs[0].seg == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a subsegment's deallocation.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,7 +238,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void TriPivot(ref Otri ot)
|
||||
{
|
||||
ot = ss.triangles[ssorient];
|
||||
ot = seg.triangles[orient];
|
||||
//decode(ptr, otri)
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void TriDissolve()
|
||||
{
|
||||
ss.triangles[ssorient].triangle = Mesh.dummytri;
|
||||
seg.triangles[orient].triangle = Mesh.dummytri;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -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
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -470,7 +476,7 @@ namespace TriangleNet.Data
|
||||
/// </summary>
|
||||
public void SegDissolve()
|
||||
{
|
||||
triangle.subsegs[orient].ss = Mesh.dummysub;
|
||||
triangle.subsegs[orient].seg = Mesh.dummysub;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Point2.cs" company="">
|
||||
// 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/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Data
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 2D point.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Region.cs" company="">
|
||||
// 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/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Data
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,32 +18,25 @@ namespace TriangleNet.Data
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Reset the hash seed.
|
||||
/// Gets the first endpoints vertex id.
|
||||
/// </summary>
|
||||
/// <param name="value">The new has seed value.</param>
|
||||
/// <remarks>Reset value will usally 0, if a new triangulation starts,
|
||||
/// or the number of subsegments, if refinement is done.</remarks>
|
||||
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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the seconds endpoints vertex id.
|
||||
/// </summary>
|
||||
public int P1
|
||||
{
|
||||
get { return this.vertices[1].id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the segment boundary mark.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SplayNode.cs" company="">
|
||||
// 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/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Data
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// A node in the splay tree.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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.
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SweepEvent.cs" company="">
|
||||
// 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/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Data
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// A node in a heap used to store events for the sweepline Delaunay algorithm.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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'.
|
||||
/// </remarks>
|
||||
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.
|
||||
}
|
||||
}
|
||||
@@ -11,28 +11,24 @@ namespace TriangleNet.Data
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// The triangle data structure.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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".
|
||||
/// </remarks>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Reset the hash seed.
|
||||
/// Gets the triangle id.
|
||||
/// </summary>
|
||||
/// <param name="value">The new has seed value.</param>
|
||||
/// <remarks>Reset value will usally 0, if a new triangulation starts,
|
||||
/// or the number of triangles, if refinement is done.</remarks>
|
||||
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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first corners vertex id.
|
||||
/// </summary>
|
||||
public int P0
|
||||
{
|
||||
get { return this.vertices[0] == null ? -1 : this.vertices[0].id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the seconds corners vertex id.
|
||||
/// </summary>
|
||||
public int P1
|
||||
{
|
||||
get { return this.vertices[1] == null ? -1 : this.vertices[1].id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified corners vertex id.
|
||||
/// </summary>
|
||||
public int this[int index]
|
||||
{
|
||||
get { return this.vertices[index] == null ? -1 : this.vertices[index].id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the third corners vertex id.
|
||||
/// </summary>
|
||||
public int P2
|
||||
{
|
||||
get { return this.vertices[2] == null ? -1 : this.vertices[2].id; }
|
||||
}
|
||||
|
||||
public bool SupportsNeighbors
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first neighbors id.
|
||||
/// </summary>
|
||||
public int N0
|
||||
{
|
||||
get { return this.neighbors[0].triangle.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second neighbors id.
|
||||
/// </summary>
|
||||
public int N1
|
||||
{
|
||||
get { return this.neighbors[1].triangle.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the third neighbors id.
|
||||
/// </summary>
|
||||
public int N2
|
||||
{
|
||||
get { return this.neighbors[2].triangle.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle area constraint.
|
||||
/// </summary>
|
||||
public double Area
|
||||
{
|
||||
get { return this.area; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle attributes.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,43 +11,52 @@ namespace TriangleNet.Data
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// The vertex data structure.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Each vertex is actually an array of doubles. An integer boundary marker,
|
||||
/// and sometimes a to a triangle, is appended after the doubles.
|
||||
/// </remarks>
|
||||
class Vertex : IComparable<Vertex>, IEquatable<Vertex>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertex id.
|
||||
/// </summary>
|
||||
public int ID
|
||||
{
|
||||
get { return this.id; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the vertex type.
|
||||
/// </summary>
|
||||
public VertexType Type
|
||||
{
|
||||
get { return this.type; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the hash seed.
|
||||
/// </summary>
|
||||
/// <param name="value">The new has seed value.</param>
|
||||
/// <remarks>Reset value will usally 0, if a new triangulation starts,
|
||||
/// or the number of points, if refinement is done.</remarks>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,5 +90,5 @@ namespace TriangleNet
|
||||
/// <summary>
|
||||
/// The type of the mesh vertex.
|
||||
/// </summary>
|
||||
enum VertexType { InputVertex, SegmentVertex, FreeVertex, DeadVertex, UndeadVertex };
|
||||
public enum VertexType { InputVertex, SegmentVertex, FreeVertex, DeadVertex, UndeadVertex };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="EdgeEnumerator.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Geometry
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates the edges of a triangulation.
|
||||
/// </summary>
|
||||
public class EdgeEnumerator : IEnumerator<Edge>
|
||||
{
|
||||
IEnumerator<Triangle> triangles;
|
||||
Otri tri = default(Otri);
|
||||
Otri neighbor = default(Otri);
|
||||
Edge current;
|
||||
Vertex p1, p2;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EdgeEnumerator" /> class.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ namespace TriangleNet.Geometry
|
||||
/// </summary>
|
||||
public IEnumerable<Point> Points
|
||||
{
|
||||
get { return null; }
|
||||
get { return points; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -131,7 +131,7 @@ namespace TriangleNet.Geometry
|
||||
/// <param name="boundary">Boundary marker.</param>
|
||||
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
|
||||
/// <param name="boundary">Segment marker.</param>
|
||||
public void AddSegment(int p0, int p1, int boundary)
|
||||
{
|
||||
if (p0 == p1)
|
||||
if (p0 == p1 || p0 < 0 || p1 < 0)
|
||||
{
|
||||
throw new NotSupportedException("Invalid endpoints.");
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace TriangleNet.IO
|
||||
using System.Globalization;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Log;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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
|
||||
|
||||
@@ -12,286 +12,15 @@ namespace TriangleNet.IO
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a mesh representaion using arrays.
|
||||
/// </summary>
|
||||
public static class DataWriter
|
||||
{
|
||||
static NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
|
||||
|
||||
static int verticesCount;
|
||||
static int elementsCount;
|
||||
|
||||
#region Library
|
||||
|
||||
/// <summary>
|
||||
/// Number the vertices and write them to raw output data.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="data"></param>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the triangles to raw output data.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="data"></param>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the segments and holes to raw output data.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="data"></param>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the edges to raw output data.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="data"></param>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the triangle neighbors to raw output data.
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <remarks>WARNING: Be sure WriteElements has been called before,
|
||||
/// so the elements are numbered right!</remarks>
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Voronoi diagram as raw output data.
|
||||
/// </summary>
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="DebugWriter.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://home.edo.tu-dortmund.de/~woltering/triangle/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.IO
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using TriangleNet.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Writes a the current mesh into a text file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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
|
||||
/// </remarks>
|
||||
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";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new session with given name.
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the session (and output files).</param>
|
||||
public void NewSession(string name)
|
||||
{
|
||||
this.iteration = 0;
|
||||
this.name = name + "-{0}.mesh";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write complete mesh to a .mesh file.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ namespace TriangleNet.IO
|
||||
using System.Globalization;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Log;
|
||||
using TriangleNet.Geometry;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <summary>
|
||||
/// Helper for reading Triangle files.
|
||||
@@ -26,7 +28,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="filename">The file to read.</param>
|
||||
/// <remarks>Will NOT read associated files by default.</remarks>
|
||||
public static MeshData ReadFile(string filename)
|
||||
public static InputGeometry ReadFile(string filename)
|
||||
{
|
||||
return ReadFile(filename, false);
|
||||
}
|
||||
@@ -36,7 +38,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="filename">The file to read.</param>
|
||||
/// <param name="readsupp">Read associated files (ele, area, neigh).</param>
|
||||
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)
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <param name="line"></param>
|
||||
/// <param name="n">Number of point attributes</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -112,7 +117,7 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodefilename"></param>
|
||||
/// <remarks>Will NOT read associated .ele by default.</remarks>
|
||||
public static MeshData ReadNodeFile(string nodefilename)
|
||||
public static InputGeometry ReadNodeFile(string nodefilename)
|
||||
{
|
||||
return ReadNodeFile(nodefilename, false);
|
||||
}
|
||||
@@ -122,9 +127,9 @@ namespace TriangleNet.IO
|
||||
/// </summary>
|
||||
/// <param name="nodefilename"></param>
|
||||
/// <param name="readElements"></param>
|
||||
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
|
||||
/// </summary>
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <remarks>Will NOT read associated .ele by default.</remarks>
|
||||
public static MeshData ReadPolyFile(string polyfilename)
|
||||
public static InputGeometry ReadPolyFile(string polyfilename)
|
||||
{
|
||||
return ReadPolyFile(polyfilename, false, false);
|
||||
}
|
||||
@@ -231,7 +226,7 @@ namespace TriangleNet.IO
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <param name="readElements">If true, look for an associated .ele file.</param>
|
||||
/// <remarks>Will NOT read associated .area by default.</remarks>
|
||||
public static 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
|
||||
/// <param name="polyfilename"></param>
|
||||
/// <param name="readElements">If true, look for an associated .ele file.</param>
|
||||
/// <param name="readElements">If true, look for an associated .area file.</param>
|
||||
public static 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<ITriangle> ReadEleFile(string elefilename)
|
||||
{
|
||||
MeshData data = new MeshData();
|
||||
|
||||
ReadEleFile(elefilename, data, false);
|
||||
|
||||
return data;
|
||||
return ReadEleFile(elefilename, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -504,10 +462,12 @@ namespace TriangleNet.IO
|
||||
/// <param name="elefilename"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="readArea"></param>
|
||||
private static void ReadEleFile(string elefilename, MeshData data, bool readArea)
|
||||
private static List<ITriangle> ReadEleFile(string elefilename, bool readArea)
|
||||
{
|
||||
int intriangles = 0, attributes = 0;
|
||||
|
||||
List<ITriangle> 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<ITriangle>(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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -586,8 +547,10 @@ namespace TriangleNet.IO
|
||||
/// <param name="areafilename"></param>
|
||||
/// <param name="intriangles"></param>
|
||||
/// <param name="data"></param>
|
||||
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<Edge> ReadEdgeFile(string edgeFile, int invertices)
|
||||
{
|
||||
// Read poly file
|
||||
MeshData data = new MeshData();
|
||||
List<Edge> data = null;
|
||||
|
||||
startIndex = 0;
|
||||
|
||||
@@ -653,15 +618,10 @@ namespace TriangleNet.IO
|
||||
|
||||
if (inedges > 0)
|
||||
{
|
||||
data.Edges = new int[inedges][];
|
||||
data = new List<Edge>(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace TriangleNet.IO
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Triangle.cs" company="">
|
||||
// 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/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.IO
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Simple triangle class for input.
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle id.
|
||||
/// </summary>
|
||||
public int ID
|
||||
{
|
||||
get { return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first corners vertex id.
|
||||
/// </summary>
|
||||
public int P0
|
||||
{
|
||||
get { return this.vertices[0]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the seconds corners vertex id.
|
||||
/// </summary>
|
||||
public int P1
|
||||
{
|
||||
get { return this.vertices[1]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the third corners vertex id.
|
||||
/// </summary>
|
||||
public int P2
|
||||
{
|
||||
get { return this.vertices[2]; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified corners vertex id.
|
||||
/// </summary>
|
||||
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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle area constraint.
|
||||
/// </summary>
|
||||
public double Area
|
||||
{
|
||||
get { return -1; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the triangle attributes.
|
||||
/// </summary>
|
||||
public double[] Attributes
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="TriangulateIO.cs">
|
||||
// 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
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the mesh data in- and output.
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,18 @@
|
||||
|
||||
namespace TriangleNet.IO
|
||||
{
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the voronoi data (output only).
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace TriangleNet.Log
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// A simple logger, which logs messages to a List<string>.
|
||||
/// A simple logger, which logs messages to a List.
|
||||
/// </summary>
|
||||
/// <remarks>Using singleton pattern as proposed by Jon Skeet.
|
||||
/// http://csharpindepth.com/Articles/General/Singleton.aspx
|
||||
|
||||
+464
-591
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,8 @@ namespace TriangleNet
|
||||
{
|
||||
using System;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="pa"></param>
|
||||
/// <param name="pb"></param>
|
||||
/// <param name="pc"></param>
|
||||
/// <param name="pa">Point a.</param>
|
||||
/// <param name="pb">Point b.</param>
|
||||
/// <param name="pc">Point c.</param>
|
||||
/// <returns>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.</returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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.
|
||||
/// </summary>
|
||||
/// <param name="pa"></param>
|
||||
/// <param name="pb"></param>
|
||||
/// <param name="pc"></param>
|
||||
/// <param name="pd"></param>
|
||||
/// <param name="pa">Point a.</param>
|
||||
/// <param name="pb">Point b.</param>
|
||||
/// <param name="pc">Point c.</param>
|
||||
/// <param name="pd">Point d.</param>
|
||||
/// <returns>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.</returns>
|
||||
@@ -178,7 +180,7 @@ namespace TriangleNet
|
||||
///
|
||||
/// See Robust Predicates paper for details.
|
||||
/// </remarks>
|
||||
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.
|
||||
/// </summary>
|
||||
/// <param name="pa"></param>
|
||||
/// <param name="pb"></param>
|
||||
/// <param name="pc"></param>
|
||||
/// <param name="pd"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public static double NonRegular(Point2 pa, Point2 pb, Point2 pc, Point2 pd)
|
||||
/// <param name="pa">Point a.</param>
|
||||
/// <param name="pb">Point b.</param>
|
||||
/// <param name="pc">Point c.</param>
|
||||
/// <param name="pd">Point d.</param>
|
||||
/// <returns>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.</returns>
|
||||
public static double NonRegular(Point pa, Point pb, Point pc, Point pd)
|
||||
{
|
||||
return InCircle(pa, pb, pc, pd);
|
||||
}
|
||||
@@ -259,13 +256,13 @@ namespace TriangleNet
|
||||
/// <summary>
|
||||
/// Find the circumcenter of a triangle.
|
||||
/// </summary>
|
||||
/// <param name="torg"></param>
|
||||
/// <param name="tdest"></param>
|
||||
/// <param name="tapex"></param>
|
||||
/// <param name="circumcenter"></param>
|
||||
/// <param name="xi"></param>
|
||||
/// <param name="eta"></param>
|
||||
/// <param name="offcenter"></param>
|
||||
/// <param name="torg">Triangle point.</param>
|
||||
/// <param name="tdest">Triangle point.</param>
|
||||
/// <param name="tapex">Triangle point.</param>
|
||||
/// <param name="xi">Relative coordinate of new location.</param>
|
||||
/// <param name="eta">Relative coordinate of new location.</param>
|
||||
/// <param name="offcenter">Use off-center for new location.</param>
|
||||
/// <returns>Coordinates of the circumcenter (or off-center)</returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="pa"></param>
|
||||
/// <param name="pb"></param>
|
||||
/// <param name="pc"></param>
|
||||
/// <param name="pd"></param>
|
||||
/// <param name="aheight"></param>
|
||||
/// <param name="bheight"></param>
|
||||
/// <param name="cheight"></param>
|
||||
/// <param name="dheight"></param>
|
||||
/// <returns>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.</returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace TriangleNet
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Log;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods for mesh quality enforcement and testing.
|
||||
@@ -20,7 +21,9 @@ namespace TriangleNet
|
||||
Queue<BadSubseg> badsubsegs;
|
||||
BadTriQueue queue;
|
||||
Mesh mesh;
|
||||
Func<Vertex, Vertex, Vertex, double, bool> userTest;
|
||||
|
||||
// Not used at the moment
|
||||
Func<Point, Point, Point, double, bool> userTest;
|
||||
|
||||
ILog<SimpleLogItem> logger;
|
||||
|
||||
@@ -34,9 +37,9 @@ namespace TriangleNet
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deallocate space for a bad subsegment, marking it dead.
|
||||
/// Add a bad subsegment to the queue.
|
||||
/// </summary>
|
||||
/// <param name="dyingseg"></param>
|
||||
/// <param name="badseg">Bad subsegment.</param>
|
||||
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
|
||||
/// <summary>
|
||||
/// Check a subsegment to see if it is encroached; add it to the list if it is.
|
||||
/// </summary>
|
||||
/// <param name="testsubseg"></param>
|
||||
/// <param name="testsubseg">The subsegment to check.</param>
|
||||
/// <returns>Returns a nonzero value if the subsegment is encroached.</returns>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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.
|
||||
/// </remarks>
|
||||
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
|
||||
/// <summary>
|
||||
/// Test every triangle in the mesh for quality measures.
|
||||
/// </summary>
|
||||
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.
|
||||
/// </summary>
|
||||
/// <param name="badtri"></param>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet
|
||||
namespace TriangleNet.Tools
|
||||
{
|
||||
using System;
|
||||
using System.Text;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Gather mesh statistics.
|
||||
@@ -74,7 +75,7 @@ namespace TriangleNet
|
||||
/// <summary>
|
||||
/// Gets the shortest altitude.
|
||||
/// </summary>
|
||||
public double ShortestAltitude { get { return minAspect; } }
|
||||
public double ShortestAltitude { get { return minAspect; } }
|
||||
|
||||
double maxAspect = 0;
|
||||
/// <summary>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -47,25 +47,23 @@
|
||||
<Compile Include="Carver.cs" />
|
||||
<Compile Include="Data\BadSubseg.cs" />
|
||||
<Compile Include="Data\BadTriangle.cs" />
|
||||
<Compile Include="Data\FlipStacker.cs" />
|
||||
<Compile Include="Data\Osub.cs" />
|
||||
<Compile Include="Data\Otri.cs" />
|
||||
<Compile Include="Data\Point2.cs" />
|
||||
<Compile Include="Data\Region.cs" />
|
||||
<Compile Include="Data\SplayNode.cs" />
|
||||
<Compile Include="Data\Subseg.cs" />
|
||||
<Compile Include="Data\SweepEvent.cs" />
|
||||
<Compile Include="Data\Segment.cs" />
|
||||
<Compile Include="Data\Triangle.cs" />
|
||||
<Compile Include="Data\Vertex.cs" />
|
||||
<Compile Include="Algorithm\Dwyer.cs" />
|
||||
<Compile Include="Geometry\BoundingBox.cs" />
|
||||
<Compile Include="Geometry\Edge.cs" />
|
||||
<Compile Include="Geometry\EdgeEnumerator.cs" />
|
||||
<Compile Include="Geometry\InputGeometry.cs" />
|
||||
<Compile Include="Geometry\ITriangle.cs" />
|
||||
<Compile Include="Geometry\Point.cs" />
|
||||
<Compile Include="Geometry\RegionPointer.cs" />
|
||||
<Compile Include="IO\DataReader.cs" />
|
||||
<Compile Include="IO\DebugWriter.cs" />
|
||||
<Compile Include="IO\FileWriter.cs" />
|
||||
<Compile Include="IO\InputTriangle.cs" />
|
||||
<Compile Include="IO\VoronoiData.cs" />
|
||||
<Compile Include="IO\DataWriter.cs" />
|
||||
<Compile Include="IO\FileReader.cs" />
|
||||
@@ -82,9 +80,8 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Sampler.cs" />
|
||||
<Compile Include="Smoothing\ISmoother.cs" />
|
||||
<Compile Include="Statistic.cs" />
|
||||
<Compile Include="Tools\Statistic.cs" />
|
||||
<Compile Include="Algorithm\SweepLine.cs" />
|
||||
<Compile Include="IO\MeshData.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
Reference in New Issue
Block a user