Test app improvements

git-svn-id: https://triangle.svn.codeplex.com/svn@67941 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2012-06-09 21:18:51 +00:00
parent c0d89aebeb
commit 4c7ca69e27
25 changed files with 1956 additions and 1154 deletions
@@ -11,14 +11,12 @@ namespace MeshExplorer.Controls
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);
+45 -21
View File
@@ -179,7 +179,7 @@ namespace MeshExplorer.Controls
get { return criticalPercent; }
set { criticalPercent = value; }
}
private Color thumbOuterColor = Color.White;
private Color thumbInnerColor = Color.Gainsboro;
private Color thumbPenColor = Color.Silver;
@@ -190,7 +190,7 @@ namespace MeshExplorer.Controls
private Color elapsedInnerColor = Color.Chartreuse;
#endregion
#region Constructors
/// <summary>
@@ -204,7 +204,7 @@ namespace MeshExplorer.Controls
| ControlStyles.ResizeRedraw
| ControlStyles.Selectable
| ControlStyles.SupportsTransparentBackColor
| ControlStyles.UserMouse
| ControlStyles.UserMouse
| ControlStyles.UserPaint, true);
BackColor = Color.Transparent;
@@ -226,7 +226,7 @@ namespace MeshExplorer.Controls
{
if (!Enabled)
{
DrawColorSlider(e.Graphics);
DrawDisabledSlider(e.Graphics);
}
else
{
@@ -245,18 +245,39 @@ namespace MeshExplorer.Controls
}
}
private void DrawDisabledSlider(Graphics g)
{
try
{
//adjust drawing rects
barRect = new Rectangle(1, this.Height / 2, this.Width - 2, 5);
Brush sliderLGBrushH = new LinearGradientBrush(barRect, ColorScheme.ColorGray122,
ColorScheme.ColorGray107, LinearGradientMode.Horizontal);
//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);
}
sliderLGBrushH.Dispose();
}
catch (Exception)
{ }
finally
{ }
}
/// <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
@@ -305,10 +326,10 @@ namespace MeshExplorer.Controls
sliderLGBrushH.Dispose();
//draw thumb
Brush brushInner = new LinearGradientBrush(thumbRect,
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);
@@ -357,7 +378,7 @@ namespace MeshExplorer.Controls
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
if (e.Button == MouseButtons.Left && this.Enabled)
{
this.Capture = true;
OnValueChanging();
@@ -403,11 +424,14 @@ namespace MeshExplorer.Controls
/// <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();
if (this.Enabled)
{
base.OnMouseUp(e);
this.Capture = false;
mouseInThumbRegion = thumbRect.Contains(e.Location);
OnValueChanged();
Invalidate();
}
}
#endregion
@@ -21,25 +21,27 @@ namespace MeshExplorer.Controls
/// <summary>
/// Renders a mesh using GDI.
/// </summary>
public class MeshRenderer : Control
public class RendererControl : Control
{
// Rendering stuff
private BufferedGraphics buffer;
private BufferedGraphicsContext context;
Pen lines = new Pen(Color.FromArgb(30, 30, 30));
Zoom zoom;
RenderData data;
MeshRenderer meshRenderer;
VoronoiRenderer voronoiRenderer;
RenderColors renderColors;
bool initialized = false;
VoronoiRenderer voronoi;
bool showVoronoi = false;
string coordinate = String.Empty;
Timer timer;
public long RenderTime { get; private set; }
public RenderData Data { get { return data; } }
public bool ShowVoronoi
{
@@ -48,20 +50,22 @@ namespace MeshExplorer.Controls
{
showVoronoi = value;
if (voronoi != null && showVoronoi)
if (voronoiRenderer != null && showVoronoi)
{
voronoi.Update();
voronoiRenderer.Update();
}
this.Render();
}
}
public MeshRenderer()
public RendererControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
this.BackColor = Color.Black;
renderColors = RenderColors.Default;
this.BackColor = renderColors.Background;
zoom = new Zoom();
context = new BufferedGraphicsContext();
@@ -86,10 +90,19 @@ namespace MeshExplorer.Controls
this.Invalidate();
}
public void ShowQuality(int measure)
{
//Tuple<int, byte>[] q = TriangleQuality.Measure(data, measure);
//this.RenderQualities(q);
}
public void SetData(InputGeometry mesh)
{
data.SetData(mesh);
meshRenderer = new MeshRenderer(data);
// Reset the zoom on new data
zoom.Initialize(this.ClientRectangle, data.Bounds);
@@ -100,11 +113,13 @@ namespace MeshExplorer.Controls
public void SetData(Mesh mesh)
{
voronoi = new VoronoiRenderer(mesh);
voronoi.Update();
data.SetData(mesh);
meshRenderer = new MeshRenderer(data);
voronoiRenderer = new VoronoiRenderer(mesh);
voronoiRenderer.Update();
initialized = true;
this.Render();
@@ -154,109 +169,15 @@ namespace MeshExplorer.Controls
}
}
private void RenderPoints(Graphics g)
{
PointF pt;
PointF[] pts = data.Points;
int i, n;
// Draw input points
n = data.NumberOfInputPoints;
for (i = 0; i < n; i++)
{
if (zoom.ViewportContains(pts[i]))
{
pt = zoom.WorldToScreen(pts[i]);
g.FillEllipse(Brushes.Green, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
//g.FillEllipse(Brushes.Black, pt.X - 2, pt.Y - 2, 4, 4);
//g.DrawEllipse(Pens.Green, pt.X - 2, pt.Y - 2, 4, 4);
}
}
// Draw Steiner points
n = pts.Length;
for (; i < n; i++)
{
if (zoom.ViewportContains(pts[i]))
{
pt = zoom.WorldToScreen(pts[i]);
g.FillEllipse(Brushes.Peru, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
//g.FillEllipse(Brushes.Black, pt.X - 2, pt.Y - 2, 4, 4);
//g.DrawEllipse(Pens.Peru, pt.X - 2, pt.Y - 2, 4, 4);
}
}
}
private void RenderTriangles(Graphics g)
{
PointF p0, p1, p2;
PointF[] pts = data.Points;
var triangles = data.Triangles;
// Draw triangles
foreach (var tri in triangles)
{
if (zoom.ViewportContains(pts[tri.P0]) ||
zoom.ViewportContains(pts[tri.P1]) ||
zoom.ViewportContains(pts[tri.P2]))
{
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);
g.DrawLine(lines, p2, p0);
}
}
}
private void RenderEdges(Graphics g)
{
PointF p0, p1;
PointF[] pts = data.Points;
var edges = data.Edges;
// Draw edges
foreach (var edge in edges)
{
if (zoom.ViewportContains(pts[edge.P0]) ||
zoom.ViewportContains(pts[edge.P1]))
{
p0 = zoom.WorldToScreen(pts[edge.P0]);
p1 = zoom.WorldToScreen(pts[edge.P1]);
g.DrawLine(lines, p0, p1);
}
}
}
private void RenderSegments(Graphics g)
{
PointF p0, p1;
PointF[] pts = data.Points;
var segments = data.Segments;
foreach (var seg in segments)
{
if (zoom.ViewportContains(pts[seg.P0]) ||
zoom.ViewportContains(pts[seg.P1]))
{
p0 = zoom.WorldToScreen(pts[seg.P0]);
p1 = zoom.WorldToScreen(pts[seg.P1]);
g.DrawLine(Pens.DarkBlue, p0, p1);
}
}
}
private void Render()
{
coordinate = String.Empty;
if (buffer == null)
{
return;
}
Graphics g = buffer.Graphics;
g.Clear(this.BackColor);
@@ -267,40 +188,66 @@ namespace MeshExplorer.Controls
g.SmoothingMode = SmoothingMode.AntiAlias;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (data.Edges != null)
if (meshRenderer != null)
{
this.RenderEdges(g);
}
else if (data.Triangles != null)
{
this.RenderTriangles(g);
meshRenderer.Render(g, zoom, renderColors);
}
if (voronoi != null && this.showVoronoi)
if (voronoiRenderer != null && this.showVoronoi)
{
voronoi.Render(g, zoom);
voronoiRenderer.Render(g, zoom, renderColors);
}
if (data.Segments != null)
{
this.RenderSegments(g);
}
if (data.Points != null)
{
this.RenderPoints(g);
}
stopwatch.Stop();
this.RenderTime = stopwatch.ElapsedMilliseconds;
this.Invalidate();
}
/*
private void RenderQualitiesX(Tuple<int, byte>[] q)
{
PointF[] p = new PointF[3];
PointF[] pts = data.Points;
int[] tri;
Brush q1 = new SolidBrush(Color.FromArgb(50, Color.Orange));
Brush q2 = new SolidBrush(Color.FromArgb(50, Color.Red));
Graphics g = buffer.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
int n = q.Length;
for (int i = 0; i < n; i++)
{
tri = data.Triangles[q[i].Item1];
if (zoom.ViewportContains(pts[tri[0]]) ||
zoom.ViewportContains(pts[tri[1]]) ||
zoom.ViewportContains(pts[tri[2]]))
{
p[0] = zoom.WorldToScreen(pts[tri[0]]);
p[1] = zoom.WorldToScreen(pts[tri[1]]);
p[2] = zoom.WorldToScreen(pts[tri[2]]);
// Fill
g.FillPolygon(q[i].Item2 > 1 ? q2 : q1, p);
// Outline
g.DrawLine(lines, p[0], p[1]);
g.DrawLine(lines, p[1], p[2]);
g.DrawLine(lines, p[2], p[0]);
// Points
g.FillEllipse(Brushes.Green, p[0].X - 1.5f, p[0].Y - 1.5f, 3, 3);
g.FillEllipse(Brushes.Green, p[1].X - 1.5f, p[1].Y - 1.5f, 3, 3);
g.FillEllipse(Brushes.Green, p[2].X - 1.5f, p[2].Y - 1.5f, 3, 3);
}
}
this.Invalidate();
}*/
#region Control overrides
protected override void OnPaint(PaintEventArgs pe)
+48 -46
View File
@@ -23,12 +23,14 @@ namespace MeshExplorer
// Make sure this path points to the polygon sample data.
static readonly string pathToData = @"..\..\..\Data\";
static ImageWriter imageWriter = new ImageWriter();
/// <summary>
/// Generating Delaunay triangulations
/// </summary>
public static void Example1()
{
ImageWriter.SetColorSchemeLight();
imageWriter.SetColorSchemeLight();
// Create a mesh instance.
Mesh mesh = new Mesh();
@@ -36,18 +38,18 @@ namespace MeshExplorer
// Read spiral node file and gernerate the delaunay triangulation
// of the point set.
mesh.Triangulate(pathToData + "spiral.node");
ImageWriter.WritePng(mesh, "spiral.png", 180);
imageWriter.WritePng(mesh, "spiral.png", 180);
// Read face polygon file and gernerate the delaunay triangulation
// of the PSLG. We reuse the mesh instance here.
InputGeometry data = FileReader.ReadFile(pathToData + "face.poly");
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "face.png", 200);
imageWriter.WritePng(mesh, "face.png", 200);
// Generate a conforming delaunay triangulation of the face polygon.
mesh.SetOption(Options.ConformingDelaunay, true);
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "face-CDT.png", 200);
imageWriter.WritePng(mesh, "face-CDT.png", 200);
}
/// <summary>
@@ -55,7 +57,7 @@ namespace MeshExplorer
/// </summary>
public static void Example2()
{
ImageWriter.SetColorSchemeLight();
imageWriter.SetColorSchemeLight();
// Create a mesh instance.
Mesh mesh = new Mesh();
@@ -66,18 +68,18 @@ namespace MeshExplorer
InputGeometry data = FileReader.ReadNodeFile(pathToData + "spiral.node");
mesh.SetOption(Options.Quality, true);
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "spiral-Angle-20.png", 200);
imageWriter.WritePng(mesh, "spiral-Angle-20.png", 200);
// Set a minimum angle of 30 degrees.
mesh.SetOption(Options.MinAngle, 35);
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "spiral-Angle-35.png", 200);
imageWriter.WritePng(mesh, "spiral-Angle-35.png", 200);
// Reset the minimum angle and add a global area constraint.
mesh.SetOption(Options.MinAngle, 20);
mesh.SetOption(Options.MaxArea, 0.2);
mesh.Triangulate(data);
ImageWriter.WritePng(mesh, "spiral-Area.png", 200);
imageWriter.WritePng(mesh, "spiral-Area.png", 200);
}
/// <summary>
@@ -85,7 +87,7 @@ namespace MeshExplorer
/// </summary>
public static void Example3()
{
ImageWriter.SetColorSchemeLight();
imageWriter.SetColorSchemeLight();
// Create a mesh instance.
Mesh mesh = new Mesh();
@@ -95,7 +97,7 @@ namespace MeshExplorer
mesh.SetOption(Options.Quality, true);
mesh.SetOption(Options.Convex, true);
mesh.Triangulate(pathToData + "box.poly");
ImageWriter.WritePng(mesh, "box.png", 200);
imageWriter.WritePng(mesh, "box.png", 200);
// Save the current mesh to .node and .ele files
FileWriter.WriteNodes(mesh, "box.1.node");
@@ -103,11 +105,11 @@ namespace MeshExplorer
// Refine the mesh by setting a global area constraint.
mesh.Refine(0.2);
ImageWriter.WritePng(mesh, "box-Refine-1.png", 200);
imageWriter.WritePng(mesh, "box-Refine-1.png", 200);
// Refine again by setting a smaller area constraint.
mesh.Refine(0.05);
ImageWriter.WritePng(mesh, "box-Refine-2.png", 200);
imageWriter.WritePng(mesh, "box-Refine-2.png", 200);
// Load the previously saved box.1 mesh. Since a box.1.area
// file exist, the variable area constraint option is set
@@ -115,7 +117,7 @@ namespace MeshExplorer
mesh.Load(pathToData + "box.1.node");
mesh.SetOption(Options.MinAngle, 0);
mesh.Refine();
ImageWriter.WritePng(mesh, "box-Refine-3.png", 200);
imageWriter.WritePng(mesh, "box-Refine-3.png", 200);
}
/// <summary>
@@ -123,19 +125,19 @@ namespace MeshExplorer
/// </summary>
public static void Example4()
{
ImageWriter.SetColorSchemeLight();
//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 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();
//// 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);
//// Gernerate a delaunay triangulation
//mesh.Triangulate(data);
//ImageWriter.WritePng(mesh, "circle-mesh.png", 400);
//ImageWriter.WriteVoronoiPng(mesh, "circle-voronoi.png", 400);
}
/// <summary>
@@ -143,18 +145,18 @@ namespace MeshExplorer
/// </summary>
public static void Example5()
{
ImageWriter.SetColorSchemeLight();
//ImageWriter.SetColorSchemeLight();
// Create a mesh instance.
Mesh mesh = new Mesh();
//// 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();
//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);
//ImageWriter.WritePng(mesh, "slit-smooth.png", 300);
}
/// <summary>
@@ -162,29 +164,29 @@ namespace MeshExplorer
/// </summary>
public static void ExampleXYZ()
{
ImageWriter.SetColorSchemeLight();
//ImageWriter.SetColorSchemeLight();
Mesh mesh = new Mesh();
//Mesh mesh = new Mesh();
mesh.SetOption(Options.Quality, true);
mesh.SetOption(Options.MinAngle, 25);
mesh.SetOption(Options.MaxArea, 0.05);
//mesh.SetOption(Options.Quality, true);
//mesh.SetOption(Options.MinAngle, 25);
//mesh.SetOption(Options.MaxArea, 0.05);
mesh.Triangulate(pathToData + "Smooth-Square.poly");
//mesh.Triangulate(pathToData + "Smooth-Square.poly");
ImageWriter.WritePng(mesh, "test1.png", 300);
//ImageWriter.WritePng(mesh, "test1.png", 300);
mesh.SetOption(Options.MaxArea, 0.01);
//mesh.SetOption(Options.MaxArea, 0.01);
// Refine with new max area
mesh.Refine();
//// Refine with new max area
//mesh.Refine();
ImageWriter.WritePng(mesh, "test2.png", 300);
//ImageWriter.WritePng(mesh, "test2.png", 300);
mesh.SetOption(Options.SteinerPoints, 50);
mesh.Triangulate(pathToData + "Smooth-Square.poly");
//mesh.SetOption(Options.SteinerPoints, 50);
//mesh.Triangulate(pathToData + "Smooth-Square.poly");
ImageWriter.WritePng(mesh, "test3.png", 300);
//ImageWriter.WritePng(mesh, "test3.png", 300);
}
}
}
@@ -1,6 +1,6 @@
namespace MeshExplorer
{
partial class FormQuality
partial class FormExport
{
/// <summary>
/// Required designer variable.
@@ -29,33 +29,59 @@
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.darkButton1 = new MeshExplorer.Controls.DarkButton();
this.btnExport = new MeshExplorer.Controls.DarkButton();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.ForeColor = System.Drawing.Color.White;
this.label1.BackColor = System.Drawing.Color.Transparent;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(38, 13);
this.label1.TabIndex = 0;
this.label1.Text = "-";
this.label1.Size = new System.Drawing.Size(302, 39);
this.label1.TabIndex = 2;
this.label1.Text = "No options available at the moment.\r\n\r\nYou will find the saved image in the appli" +
"cation directory.";
//
// FormQuality
// darkButton1
//
this.darkButton1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.darkButton1.Location = new System.Drawing.Point(162, 141);
this.darkButton1.Name = "darkButton1";
this.darkButton1.Size = new System.Drawing.Size(82, 23);
this.darkButton1.TabIndex = 1;
this.darkButton1.Text = "Cancel";
this.darkButton1.UseVisualStyleBackColor = true;
//
// btnExport
//
this.btnExport.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnExport.Location = new System.Drawing.Point(250, 141);
this.btnExport.Name = "btnExport";
this.btnExport.Size = new System.Drawing.Size(82, 23);
this.btnExport.TabIndex = 0;
this.btnExport.Text = "Save";
this.btnExport.UseVisualStyleBackColor = true;
//
// FormExport
//
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(200, 300);
this.ClientSize = new System.Drawing.Size(344, 172);
this.Controls.Add(this.label1);
this.Controls.Add(this.darkButton1);
this.Controls.Add(this.btnExport);
this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.ForeColor = System.Drawing.Color.White;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "FormQuality";
this.Name = "FormExport";
this.ShowInTaskbar = false;
this.Text = "Mesh Quality";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormQuality_FormClosing);
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Export Image";
this.ResumeLayout(false);
this.PerformLayout();
@@ -63,6 +89,8 @@
#endregion
private Controls.DarkButton btnExport;
private Controls.DarkButton darkButton1;
private System.Windows.Forms.Label label1;
}
}
+29
View File
@@ -0,0 +1,29 @@
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
{
public partial class FormExport : Form
{
public FormExport()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var rect = this.ClientRectangle;
rect.Height -= 40;
e.Graphics.FillRectangle(Brushes.DimGray, rect);
}
}
}
+241
View File
@@ -0,0 +1,241 @@
namespace MeshExplorer
{
partial class FormGenerator
{
/// <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.lbParam1 = new System.Windows.Forms.Label();
this.lbParam2 = new System.Windows.Forms.Label();
this.lbParam3 = new System.Windows.Forms.Label();
this.lbParam1Val = new System.Windows.Forms.Label();
this.lbParam2Val = new System.Windows.Forms.Label();
this.lbParam3Val = new System.Windows.Forms.Label();
this.lbDescription = new System.Windows.Forms.Label();
this.sliderParam3 = new MeshExplorer.Controls.DarkSlider();
this.sliderParam2 = new MeshExplorer.Controls.DarkSlider();
this.sliderParam1 = new MeshExplorer.Controls.DarkSlider();
this.darkListBox1 = new MeshExplorer.Controls.DarkListBox();
this.btnClose = new MeshExplorer.Controls.DarkButton();
this.btnGenerate = new MeshExplorer.Controls.DarkButton();
this.SuspendLayout();
//
// lbParam1
//
this.lbParam1.BackColor = System.Drawing.Color.DimGray;
this.lbParam1.ForeColor = System.Drawing.Color.White;
this.lbParam1.Location = new System.Drawing.Point(171, 24);
this.lbParam1.Name = "lbParam1";
this.lbParam1.Size = new System.Drawing.Size(114, 13);
this.lbParam1.TabIndex = 4;
this.lbParam1.Text = "Param 1:";
//
// lbParam2
//
this.lbParam2.BackColor = System.Drawing.Color.DimGray;
this.lbParam2.ForeColor = System.Drawing.Color.White;
this.lbParam2.Location = new System.Drawing.Point(171, 47);
this.lbParam2.Name = "lbParam2";
this.lbParam2.Size = new System.Drawing.Size(114, 13);
this.lbParam2.TabIndex = 4;
this.lbParam2.Text = "Param 2:";
//
// lbParam3
//
this.lbParam3.BackColor = System.Drawing.Color.DimGray;
this.lbParam3.ForeColor = System.Drawing.Color.White;
this.lbParam3.Location = new System.Drawing.Point(171, 70);
this.lbParam3.Name = "lbParam3";
this.lbParam3.Size = new System.Drawing.Size(114, 13);
this.lbParam3.TabIndex = 4;
this.lbParam3.Text = "Param 3:";
//
// lbParam1Val
//
this.lbParam1Val.BackColor = System.Drawing.Color.DimGray;
this.lbParam1Val.ForeColor = System.Drawing.Color.White;
this.lbParam1Val.Location = new System.Drawing.Point(436, 24);
this.lbParam1Val.Name = "lbParam1Val";
this.lbParam1Val.Size = new System.Drawing.Size(40, 13);
this.lbParam1Val.TabIndex = 4;
this.lbParam1Val.Text = "-";
//
// lbParam2Val
//
this.lbParam2Val.BackColor = System.Drawing.Color.DimGray;
this.lbParam2Val.ForeColor = System.Drawing.Color.White;
this.lbParam2Val.Location = new System.Drawing.Point(436, 47);
this.lbParam2Val.Name = "lbParam2Val";
this.lbParam2Val.Size = new System.Drawing.Size(40, 13);
this.lbParam2Val.TabIndex = 4;
this.lbParam2Val.Text = "-";
//
// lbParam3Val
//
this.lbParam3Val.BackColor = System.Drawing.Color.DimGray;
this.lbParam3Val.ForeColor = System.Drawing.Color.White;
this.lbParam3Val.Location = new System.Drawing.Point(436, 70);
this.lbParam3Val.Name = "lbParam3Val";
this.lbParam3Val.Size = new System.Drawing.Size(40, 13);
this.lbParam3Val.TabIndex = 4;
this.lbParam3Val.Text = "-";
//
// lbDescription
//
this.lbDescription.BackColor = System.Drawing.Color.DimGray;
this.lbDescription.ForeColor = System.Drawing.Color.White;
this.lbDescription.Location = new System.Drawing.Point(171, 104);
this.lbDescription.Name = "lbDescription";
this.lbDescription.Size = new System.Drawing.Size(94, 13);
this.lbDescription.TabIndex = 4;
this.lbDescription.Text = "Description";
//
// sliderParam3
//
this.sliderParam3.BackColor = System.Drawing.Color.Transparent;
this.sliderParam3.CriticalPercent = ((uint)(0u));
this.sliderParam3.Enabled = false;
this.sliderParam3.Location = new System.Drawing.Point(291, 64);
this.sliderParam3.Maximum = 100;
this.sliderParam3.Minimum = 0;
this.sliderParam3.Name = "sliderParam3";
this.sliderParam3.Size = new System.Drawing.Size(138, 23);
this.sliderParam3.TabIndex = 3;
this.sliderParam3.Text = "sliderParam3";
this.sliderParam3.Value = 50;
this.sliderParam3.ValueChanging += new System.EventHandler(this.sliderParam3_ValueChanging);
//
// sliderParam2
//
this.sliderParam2.BackColor = System.Drawing.Color.Transparent;
this.sliderParam2.CriticalPercent = ((uint)(0u));
this.sliderParam2.Enabled = false;
this.sliderParam2.Location = new System.Drawing.Point(291, 41);
this.sliderParam2.Maximum = 100;
this.sliderParam2.Minimum = 0;
this.sliderParam2.Name = "sliderParam2";
this.sliderParam2.Size = new System.Drawing.Size(138, 23);
this.sliderParam2.TabIndex = 3;
this.sliderParam2.Text = "sliderParam2";
this.sliderParam2.Value = 50;
this.sliderParam2.ValueChanging += new System.EventHandler(this.sliderParam2_ValueChanging);
//
// sliderParam1
//
this.sliderParam1.BackColor = System.Drawing.Color.Transparent;
this.sliderParam1.CriticalPercent = ((uint)(0u));
this.sliderParam1.Enabled = false;
this.sliderParam1.Location = new System.Drawing.Point(291, 18);
this.sliderParam1.Maximum = 100;
this.sliderParam1.Minimum = 0;
this.sliderParam1.Name = "sliderParam1";
this.sliderParam1.Size = new System.Drawing.Size(138, 23);
this.sliderParam1.TabIndex = 3;
this.sliderParam1.Text = "sliderParam1";
this.sliderParam1.Value = 50;
this.sliderParam1.ValueChanging += new System.EventHandler(this.sliderParam1_ValueChanging);
//
// darkListBox1
//
this.darkListBox1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(96)))), ((int)(((byte)(96)))), ((int)(((byte)(96)))));
this.darkListBox1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.darkListBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawVariable;
this.darkListBox1.FormattingEnabled = true;
this.darkListBox1.ItemHeight = 22;
this.darkListBox1.Location = new System.Drawing.Point(5, 5);
this.darkListBox1.Name = "darkListBox1";
this.darkListBox1.Size = new System.Drawing.Size(160, 228);
this.darkListBox1.TabIndex = 2;
this.darkListBox1.SelectedIndexChanged += new System.EventHandler(this.darkListBox1_SelectedIndexChanged);
//
// btnClose
//
this.btnClose.Location = new System.Drawing.Point(291, 247);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(94, 23);
this.btnClose.TabIndex = 1;
this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// btnGenerate
//
this.btnGenerate.Location = new System.Drawing.Point(391, 247);
this.btnGenerate.Name = "btnGenerate";
this.btnGenerate.Size = new System.Drawing.Size(94, 23);
this.btnGenerate.TabIndex = 0;
this.btnGenerate.Text = "Generate";
this.btnGenerate.UseVisualStyleBackColor = true;
this.btnGenerate.Click += new System.EventHandler(this.btnGenerate_Click);
//
// FormGenerator
//
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(495, 278);
this.Controls.Add(this.lbParam3Val);
this.Controls.Add(this.lbDescription);
this.Controls.Add(this.lbParam3);
this.Controls.Add(this.lbParam2Val);
this.Controls.Add(this.lbParam2);
this.Controls.Add(this.lbParam1Val);
this.Controls.Add(this.lbParam1);
this.Controls.Add(this.sliderParam3);
this.Controls.Add(this.sliderParam2);
this.Controls.Add(this.sliderParam1);
this.Controls.Add(this.darkListBox1);
this.Controls.Add(this.btnClose);
this.Controls.Add(this.btnGenerate);
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 = "FormGenerator";
this.ShowInTaskbar = false;
this.Text = "Input Generator";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormGenerator_FormClosing);
this.ResumeLayout(false);
}
#endregion
private Controls.DarkButton btnGenerate;
private Controls.DarkButton btnClose;
private Controls.DarkListBox darkListBox1;
private Controls.DarkSlider sliderParam1;
private Controls.DarkSlider sliderParam2;
private Controls.DarkSlider sliderParam3;
private System.Windows.Forms.Label lbParam1;
private System.Windows.Forms.Label lbParam2;
private System.Windows.Forms.Label lbParam3;
private System.Windows.Forms.Label lbParam1Val;
private System.Windows.Forms.Label lbParam2Val;
private System.Windows.Forms.Label lbParam3Val;
private System.Windows.Forms.Label lbDescription;
}
}
+136
View File
@@ -0,0 +1,136 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using MeshExplorer.Generators;
using TriangleNet.Geometry;
namespace MeshExplorer
{
public partial class FormGenerator : Form
{
public event EventHandler InputGenerated;
IGenerator currentGenerator;
public FormGenerator()
{
InitializeComponent();
darkListBox1.Items.Add(new RandomPoints());
darkListBox1.Items.Add(new RandomPointsCircle());
darkListBox1.Items.Add(new StarInBox());
darkListBox1.Items.Add(new RingPolygon());
}
private void UpdateControls()
{
if (currentGenerator.ParameterCount > 0)
{
sliderParam1.Enabled = true;
lbParam1.Text = currentGenerator.ParameterDescription(1);
lbParam1Val.Text = currentGenerator.ParameterDescription(1, sliderParam1.Value);
}
else
{
sliderParam1.Enabled = false;
lbParam1.Text = "";
lbParam1Val.Text = "";
}
if (currentGenerator.ParameterCount > 1)
{
sliderParam2.Enabled = true;
lbParam2.Text = currentGenerator.ParameterDescription(2);
lbParam2Val.Text = currentGenerator.ParameterDescription(2, sliderParam2.Value);
}
else
{
sliderParam2.Enabled = false;
lbParam2.Text = "";
lbParam2Val.Text = "";
}
if (currentGenerator.ParameterCount > 2)
{
sliderParam3.Enabled = true;
lbParam3.Text = currentGenerator.ParameterDescription(3);
lbParam3Val.Text = currentGenerator.ParameterDescription(3, sliderParam3.Value);
}
else
{
sliderParam3.Enabled = false;
lbParam3.Text = "";
lbParam3Val.Text = "";
}
}
private void btnGenerate_Click(object sender, EventArgs e)
{
if (currentGenerator != null && InputGenerated != null)
{
InputGeometry input = currentGenerator.Generate(sliderParam1.Value,
sliderParam2.Value, sliderParam3.Value);
InputGenerated(input, EventArgs.Empty);
}
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Hide();
}
private void FormGenerator_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.Hide();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var rect = this.ClientRectangle;
rect.Height -= 40;
e.Graphics.FillRectangle(Brushes.DimGray, rect);
}
private void darkListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
currentGenerator = darkListBox1.SelectedItem as IGenerator;
if (currentGenerator != null)
{
UpdateControls();
}
}
private void sliderParam1_ValueChanging(object sender, EventArgs e)
{
if (currentGenerator != null)
{
lbParam1Val.Text = currentGenerator.ParameterDescription(1, sliderParam1.Value);
}
}
private void sliderParam2_ValueChanging(object sender, EventArgs e)
{
if (currentGenerator != null)
{
lbParam2Val.Text = currentGenerator.ParameterDescription(2, sliderParam2.Value);
}
}
private void sliderParam3_ValueChanging(object sender, EventArgs e)
{
if (currentGenerator != null)
{
lbParam3Val.Text = currentGenerator.ParameterDescription(3, sliderParam3.Value);
}
}
}
}
+120
View File
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+373 -222
View File
File diff suppressed because it is too large Load Diff
+98 -64
View File
@@ -4,12 +4,10 @@ using System.Drawing;
using System.IO;
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 TriangleNet.Tools;
namespace MeshExplorer
@@ -20,9 +18,10 @@ namespace MeshExplorer
InputGeometry input;
Mesh mesh;
Statistic stats;
QualityMeasure quality;
FormLog frmLog;
FormQuality frmQuality;
FormGenerator frmGenerator;
public FormMain()
{
@@ -37,7 +36,7 @@ namespace MeshExplorer
settings = new Settings();
meshRenderer1.Initialize();
renderControl1.Initialize();
stats = new Statistic();
@@ -48,17 +47,17 @@ namespace MeshExplorer
{
try
{
Mesh m = new Mesh();
m.SetOption(Options.MinAngle, 20);
//Mesh m = new Mesh();
//m.SetOption(Options.MinAngle, 20);
for (int j = 0; j < 10; j++)
{
for (int i = 20; i > 0; i--)
{
var geom = PolygonGenerator.CreateRandomPoints(10 * i, 100, 100);
//var geom = PolygonGenerator.CreateRandomPoints(10 * i, 100, 100);
m.Triangulate(geom);
//m.Triangulate(geom);
}
}
}
@@ -93,6 +92,16 @@ namespace MeshExplorer
}
}
void frmGenerator_InputGenerated(object sender, EventArgs e)
{
this.input = sender as InputGeometry;
if (input != null)
{
HandleNewInput();
}
}
private void btnMesh_Click(object sender, EventArgs e)
{
TriangulateOrRefine();
@@ -100,7 +109,18 @@ namespace MeshExplorer
private void btnSmooth_Click(object sender, EventArgs e)
{
//Smooth();
Smooth();
}
private void lbCodeplex_Clicked(object sender, EventArgs e)
{
try
{
ProcessStartInfo sInfo = new ProcessStartInfo("http://triangle.codeplex.com/");
Process.Start(sInfo);
}
catch (Exception)
{ }
}
private void slMinAngle_ValueChanging(object sender, EventArgs e)
@@ -122,9 +142,9 @@ namespace MeshExplorer
System.Drawing.Point pt = e.Location;
pt.Offset(-splitContainer1.SplitterDistance, 0);
if (meshRenderer1.ClientRectangle.Contains(pt))
if (renderControl1.ClientRectangle.Contains(pt))
{
meshRenderer1.Zoom(pt, e.Delta);
renderControl1.Zoom(pt, e.Delta);
}
base.OnMouseWheel(e);
}
@@ -139,7 +159,7 @@ namespace MeshExplorer
// Handle window minimize and maximize
if (!isResizing)
{
meshRenderer1.HandleResize();
renderControl1.HandleResize();
}
}
@@ -150,7 +170,7 @@ namespace MeshExplorer
if (this.ClientSize != this.oldClientSize)
{
this.oldClientSize = this.ClientSize;
meshRenderer1.HandleResize();
renderControl1.HandleResize();
}
}
@@ -187,19 +207,23 @@ namespace MeshExplorer
btnSmooth.Enabled = false;
// Render input
meshRenderer1.SetData(input);
renderControl1.SetData(input);
// Update window caption
this.Text = "Triangle.NET - Mesh Explorer - " + settings.CurrentFile;
// Disable menu items
viewMenuMQuality.Enabled = false;
viewMenuVoronoi.Enabled = false;
// Clear voronoi
viewMenuVoronoi.Checked = false;
renderControl1.ShowVoronoi = false;
}
private void HandleMeshChange()
{
// Render mesh
meshRenderer1.SetData(mesh);
renderControl1.SetData(mesh);
// Previous mesh stats
lbNumVert2.Text = lbNumVert.Text;
@@ -218,13 +242,25 @@ namespace MeshExplorer
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;
viewMenuVoronoi.Enabled = true;
// Update quality
if (quality == null)
{
quality = new QualityMeasure();
}
quality.Update(this.mesh);
lbQualAlphaMin.Text = Util.DoubleToString(quality.AlphaMinimum);
lbQualAlphaAve.Text = Util.DoubleToString(quality.AlphaAverage);
lbQualAspectMin.Text = Util.DoubleToString(quality.Q_Minimum);
lbQualAspectAve.Text = Util.DoubleToString(quality.Q_Average);
}
#endregion
@@ -297,7 +333,7 @@ namespace MeshExplorer
if (cbQuality.Checked)
{
btnMesh.Text = "Refine";
//btnSmooth.Enabled = true;
btnSmooth.Enabled = true;
}
}
else
@@ -321,16 +357,15 @@ namespace MeshExplorer
int angle = (slMinAngle.Value * 40) / 100;
mesh.SetOption(Options.MinAngle, angle);
double area = slMaxArea.Value * 0.01;
// Ignore area constraints on initial triangulation.
if (area > 0 && area < 1)
{
var size = input.Bounds;
double min = Math.Min(size.Width, size.Height);
mesh.SetOption(Options.MaxArea, area * min);
}
//double area = slMaxArea.Value * 0.01;
//if (area > 0 && area < 1)
//{
// var size = input.Bounds;
// double min = Math.Min(size.Width, size.Height);
// mesh.SetOption(Options.MaxArea, area * min);
//}
}
if (cbConvex.Checked)
@@ -338,7 +373,7 @@ namespace MeshExplorer
mesh.SetOption(Options.Convex, true);
}
try
//try
{
//sw.Start();
mesh.Triangulate(input);
@@ -353,11 +388,11 @@ namespace MeshExplorer
settings.RefineMode = true;
}
}
catch (Exception ex)
{
settings.ExceptionThrown = true;
DarkMessageBox.Show("Exception - Triangulate", ex.Message);
}
//catch (Exception ex)
//{
// settings.ExceptionThrown = true;
// DarkMessageBox.Show("Exception - Triangulate", ex.Message);
//}
UpdateLog();
}
@@ -445,21 +480,6 @@ namespace MeshExplorer
}
}
private void ShowQuality()
{
if (frmQuality == null)
{
frmQuality = new FormQuality();
}
//UpdateLog();
if (!frmQuality.Visible)
{
frmQuality.Show(this);
}
}
#endregion
#region Menu Handler
@@ -482,18 +502,22 @@ namespace MeshExplorer
ShowLog();
}
private void toolsMenuPoly1_Click(object sender, EventArgs e)
private void toolsMenuGenerator_Click(object sender, EventArgs e)
{
input = PolygonGenerator.StarInBox(20);
settings.CurrentFile = "star *";
HandleNewInput();
}
if (frmGenerator == null || frmGenerator.IsDisposed)
{
frmGenerator = new FormGenerator();
frmGenerator.InputGenerated += new EventHandler(frmGenerator_InputGenerated);
}
private void toolsMenuRandPts_Click(object sender, EventArgs e)
{
input = PolygonGenerator.CreateRandomPoints(10, 120, 100);
settings.CurrentFile = "points *";
HandleNewInput();
if (!frmGenerator.Visible)
{
frmGenerator.Show();
}
else
{
frmGenerator.Activate();
}
}
private void toolsMenuCheck_Click(object sender, EventArgs e)
@@ -505,14 +529,24 @@ namespace MeshExplorer
}
}
private void viewMenuMQuality_Click(object sender, EventArgs e)
private void menuFileExport_Click(object sender, EventArgs e)
{
if (mesh != null)
{
ShowQuality();
}
FormExport export = new FormExport();
frmQuality.UpdateQuality(meshRenderer1.Data);
if (export.ShowDialog() == DialogResult.OK)
{
ImageWriter imgWriter = new ImageWriter();
imgWriter.WritePng(this.mesh);
}
}
}
private void viewMenuVoronoi_Click(object sender, EventArgs e)
{
viewMenuVoronoi.Checked = !viewMenuVoronoi.Checked;
renderControl1.ShowVoronoi = viewMenuVoronoi.Checked;
}
private void fileMenuQuit_Click(object sender, EventArgs e)
-41
View File
@@ -1,41 +0,0 @@
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.IO;
using MeshExplorer.Rendering;
namespace MeshExplorer
{
public partial class FormQuality : Form
{
public FormQuality()
{
InitializeComponent();
}
public void UpdateQuality(RenderData data)
{
if (data != null)
{
//MeshQuality q = new MeshQuality();
//string s = q.Update(data);
//label1.Text = s;
}
}
private void FormQuality_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
this.Hide();
}
}
}
}
@@ -0,0 +1,27 @@
// -----------------------------------------------------------------------
// <copyright file="IGenerator.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
/// <summary>
/// Interface for generating input geometries.
/// </summary>
public interface IGenerator
{
string Name { get; }
string Description { get; }
int ParameterCount { get; }
string ParameterDescription(int paramIndex);
string ParameterDescription(int paramIndex, double paramValue);
InputGeometry Generate(double param1, double param2, double param3);
}
}
@@ -0,0 +1,92 @@
// -----------------------------------------------------------------------
// <copyright file="RandomPoints.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
/// <summary>
/// Simple random points generator.
/// </summary>
public class RandomPoints : IGenerator
{
public string Name
{
get { return "Random Points"; }
}
public string Description
{
get { return ""; }
}
public int ParameterCount
{
get { return 1; }
}
public string ParameterDescription(int paramIndex)
{
if (paramIndex == 1)
{
return "Number of points:";
}
return "";
}
public string ParameterDescription(int paramIndex, double paramValue)
{
if (paramIndex == 1)
{
int numPoints = (int)((5000.0 - 5.0) / 100.0 * paramValue + 5.0);
numPoints = (numPoints / 10) * 10;
if (numPoints < 5)
{
numPoints = 5;
}
return numPoints.ToString();
}
return "";
}
public InputGeometry Generate(double param1, double param2, double param3)
{
int numPoints = (int)((5000.0 - 5.0) / 100.0 * param1 + 5.0);
numPoints = (numPoints / 10) * 10;
if (numPoints < 5)
{
numPoints = 5;
}
InputGeometry input = new InputGeometry(numPoints);
int width = Util.Random.Next(100, 200);
int height = Util.Random.Next(100, 200);
for (int i = 0; i < numPoints; i++)
{
input.AddPoint(Util.Random.NextDouble() * width,
Util.Random.NextDouble() * height);
}
return input;
}
public override string ToString()
{
return this.Name;
}
}
}
@@ -0,0 +1,113 @@
// -----------------------------------------------------------------------
// <copyright file="RandomPoints.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
/// <summary>
/// Simple random points generator.
/// </summary>
public class RandomPointsCircle : IGenerator
{
public string Name
{
get { return "Random Points (Circle)"; }
}
public string Description
{
get { return ""; }
}
public int ParameterCount
{
get { return 2; }
}
public string ParameterDescription(int paramIndex)
{
if (paramIndex == 1)
{
return "Number of points:";
}
if (paramIndex == 2)
{
return "Distribution:";
}
return "";
}
public string ParameterDescription(int paramIndex, double paramValue)
{
if (paramIndex == 1)
{
int numPoints = (int)((5000.0 - 5.0) / 100.0 * paramValue + 5.0);
numPoints = (numPoints / 10) * 10;
if (numPoints < 5)
{
numPoints = 5;
}
return numPoints.ToString();
}
if (paramIndex == 2)
{
double exp = (paramValue + 10) / 100;
if (exp > 1.092)
{
exp = 1.1;
}
return exp.ToString("0.00", Util.Nfi);
}
return "";
}
public InputGeometry Generate(double param1, double param2, double param3)
{
int numPoints = (int)((5000.0 - 5.0) / 100.0 * param1 + 5.0);
numPoints = (numPoints / 10) * 10;
if (numPoints < 5)
{
numPoints = 5;
}
double exp = (param2 + 10) / 100;
InputGeometry input = new InputGeometry(numPoints);
double r, phi, radius = 100;
for (int i = 0; i < numPoints; i++)
{
// Use sqrt(rand) to get normal distribution right.
r = Math.Pow(Util.Random.NextDouble(), exp) * radius;
phi = Util.Random.NextDouble() * Math.PI * 2;
input.AddPoint(r * Math.Cos(phi), r * Math.Sin(phi));
}
return input;
}
public override string ToString()
{
return this.Name;
}
}
}
@@ -0,0 +1,116 @@
// -----------------------------------------------------------------------
// <copyright file="StarInBox.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
/// <summary>
/// TODO: Update summary.
/// </summary>
public class RingPolygon : IGenerator
{
public string Name
{
get { return "Ring"; }
}
public string Description
{
get { return ""; }
}
public int ParameterCount
{
get { return 2; }
}
public string ParameterDescription(int paramIndex)
{
if (paramIndex == 1)
{
return "Number of points:";
}
if (paramIndex == 2)
{
return "Variation:";
}
return "";
}
public string ParameterDescription(int paramIndex, double paramValue)
{
if (paramIndex == 1)
{
int numRays = (int)((250.0 - 50.0) / 100.0 * paramValue + 50.0);
return numRays.ToString();
}
if (paramIndex == 2)
{
double variation = (paramValue + 1) / 100;
return variation.ToString("0.0", Util.Nfi);
}
return "";
}
public InputGeometry Generate(double param1, double param2, double param3)
{
int n = (int)((250.0 - 50.0) / 100.0 * param1 + 50.0);
int m = n / 2;
InputGeometry input = new InputGeometry(n + 1);
double ro, r = 10;
double step = 2 * Math.PI / m;
// Inner ring
for (int i = 0; i < m; i++)
{
input.AddPoint(r * Math.Cos(i * step), r * Math.Sin(i * step));
input.AddSegment(i, (i + 1) % m);
}
r = 1.5 * r;
step = 2 * Math.PI / n;
double offset = step / 2;
// Outer ring
for (int i = 0; i < n; i++)
{
ro = r;
if (i % 2 == 0)
{
ro = r + r * Util.Random.NextDouble() * (param2 / 100);
}
input.AddPoint(ro * Math.Cos(i * step + offset), ro * Math.Sin(i * step + offset));
input.AddSegment(m + i, m + ((i + 1) % n));
}
input.AddHole(0, 0);
return input;
}
public override string ToString()
{
return this.Name;
}
}
}
@@ -0,0 +1,97 @@
// -----------------------------------------------------------------------
// <copyright file="StarInBox.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Generators
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Geometry;
/// <summary>
/// TODO: Update summary.
/// </summary>
public class StarInBox : IGenerator
{
public string Name
{
get { return "Star in Box"; }
}
public string Description
{
get { return ""; }
}
public int ParameterCount
{
get { return 1; }
}
public string ParameterDescription(int paramIndex)
{
if (paramIndex == 1)
{
return "Number of rays:";
}
return "";
}
public string ParameterDescription(int paramIndex, double paramValue)
{
if (paramIndex == 1)
{
int numRays = (int)((61.0 - 3.0) / 100.0 * paramValue + 3.0);
return numRays.ToString();
}
return "";
}
public InputGeometry Generate(double param1, double param2, double param3)
{
int numRays = (int)((61.0 - 3.0) / 100.0 * param1 + 3.0);
InputGeometry input = new InputGeometry(numRays + 4);
input.AddPoint(0, 0); // Center
double x, y, r, e, step = 2 * Math.PI / numRays;
for (int i = 0; i < numRays; 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);
numRays = input.Count;
input.AddSegment(numRays - 1, numRays - 2);
input.AddSegment(numRays - 2, numRays - 3);
input.AddSegment(numRays - 3, numRays - 4);
input.AddSegment(numRays - 4, numRays - 1);
return input;
}
public override string ToString()
{
return this.Name;
}
}
}
+47 -419
View File
@@ -6,6 +6,7 @@
namespace MeshExplorer.IO
{
using MeshExplorer.Rendering;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
@@ -19,17 +20,9 @@ namespace MeshExplorer.IO
/// <summary>
/// Writes an image of the mesh to disk.
/// </summary>
public static class ImageWriter
public class ImageWriter
{
static PointF[] points;
// Default color scheme (dark)
static Color bgColor = Color.Black;
static Color ptColor = Color.Green;
static Color spColor = Color.Peru;
static Color lnColor = Color.FromArgb(30, 30, 30);
static Color sgColor = Color.Blue;
static Color trColor = Color.FromArgb(30, 40, 50);
RenderColors colors = RenderColors.Default;
/// <summary>
/// Sets the color scheme.
@@ -39,48 +32,48 @@ namespace MeshExplorer.IO
/// <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 void SetColorScheme(Color background, Color points, Color steiner,
Color lines, Color segments, Color triangles)
{
bgColor = background;
ptColor = points;
spColor = steiner;
lnColor = lines;
sgColor = segments;
trColor = triangles;
colors.Background = background;
colors.Point = new SolidBrush(points);
colors.SteinerPoint = new SolidBrush(steiner);
colors.Triangle = new SolidBrush(triangles);
colors.Line = new Pen(lines);
colors.Segment = new Pen(segments);
}
/// <summary>
/// Set a color scheme with white background.
/// </summary>
public static void SetColorSchemeLight()
public void SetColorSchemeLight()
{
bgColor = Color.White;
ptColor = Color.MidnightBlue;
spColor = Color.DarkGreen;
lnColor = Color.FromArgb(150, 150, 150);
sgColor = Color.SteelBlue;
trColor = Color.FromArgb(230, 240, 250);
colors.Background = Color.White;
colors.Point = new SolidBrush(Color.MidnightBlue);
colors.SteinerPoint = new SolidBrush(Color.DarkGreen);
colors.Triangle = new SolidBrush(Color.FromArgb(230, 240, 250));
colors.Line = new Pen(Color.FromArgb(150, 150, 150));
colors.Segment = new Pen(Color.SteelBlue);
}
/// <summary>
/// Set a color scheme with black background.
/// </summary>
public static void SetColorSchemeDark()
public void SetColorSchemeDark()
{
bgColor = Color.Black;
ptColor = Color.Green;
spColor = Color.Peru;
lnColor = Color.FromArgb(30, 30, 30);
sgColor = Color.Blue;
trColor = Color.FromArgb(30, 40, 50);
colors.Background = Color.Black;
colors.Point = new SolidBrush(Color.Green);
colors.SteinerPoint = new SolidBrush(Color.Peru);
colors.Triangle = new SolidBrush(Color.FromArgb(30, 40, 50));
colors.Line = new Pen(Color.FromArgb(30, 30, 30));
colors.Segment = new Pen(Color.Blue);
}
/// <summary>
/// Draws the mesh and writes the image file.
/// </summary>
/// <param name="mesh">The mesh to visualize.</param>
public static void WritePng(Mesh mesh)
public void WritePng(Mesh mesh)
{
WritePng(mesh, "", 1000);
}
@@ -90,7 +83,7 @@ namespace MeshExplorer.IO
/// </summary>
/// <param name="mesh">The mesh to visualize.</param>
/// <param name="filename">The filename (only PNG supported).</param>
public static void WritePng(Mesh mesh, string filename)
public void WritePng(Mesh mesh, string filename)
{
WritePng(mesh, filename, 1000);
}
@@ -100,7 +93,7 @@ namespace MeshExplorer.IO
/// </summary>
/// <param name="mesh">The mesh to visualize.</param>
/// <param name="width">The target width of the image (pixel).</param>
public static void WritePng(Mesh mesh, int width)
public void WritePng(Mesh mesh, int width)
{
WritePng(mesh, "", width);
}
@@ -111,17 +104,13 @@ namespace MeshExplorer.IO
/// <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 WritePng(Mesh mesh, string filename, int width)
public void WritePng(Mesh mesh, string filename, int width)
{
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);
}
// Get mesh data -- TODO: Use RenderControl's RenderData
RenderData data = new RenderData();
data.SetData(mesh);
// Check file name
if (String.IsNullOrWhiteSpace(filename))
{
filename = String.Format("mesh-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
@@ -130,39 +119,43 @@ namespace MeshExplorer.IO
Bitmap bitmap;
// Check if the specified width is reasonable
if (width < 2 * Math.Sqrt(n))
if (width < 2 * Math.Sqrt(mesh.NumberOfVertices))
{
bitmap = new Bitmap(400, 200);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(Color.Black);
g.Clear(colors.Background);
string message = String.Format("Sorry, I won't render {0} points on such a small image!", n);
string message = String.Format("Sorry, I won't render {0} points on such a small image!", mesh.NumberOfVertices);
SizeF sz = g.MeasureString(message, SystemFonts.DefaultFont);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawString(message, SystemFonts.DefaultFont, Brushes.White,
g.DrawString(message, SystemFonts.DefaultFont, colors.Point,
200 - sz.Width / 2, 100 - sz.Height / 2);
g.Dispose();
}
else
{
var bounds = mesh.Bounds;
var bounds = data.Bounds;
// 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);
var target = new Rectangle(0, 0, width, (int)((bounds.Height + 2 * margin) * scale));
bitmap = new Bitmap(width, target.Height, PixelFormat.Format32bppPArgb);
Zoom zoom = new Zoom();
zoom.Initialize(target, bounds);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(bgColor);
g.Clear(colors.Background);
// Transform world to screen
g.ScaleTransform(scale, -scale);
g.TranslateTransform(-(float)bounds.Xmin + margin, -(float)bounds.Ymax - margin);
g.SmoothingMode = SmoothingMode.HighQuality;
DrawMesh(g, mesh, scale);
MeshRenderer meshRenderer = new MeshRenderer(data);
meshRenderer.Render(g, zoom, colors);
g.Dispose();
}
@@ -174,370 +167,5 @@ namespace MeshExplorer.IO
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"));
}
Voronoi data = null; // 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();
}
if (Path.GetExtension(filename) != ".png")
{
filename += ".png";
}
bitmap.Save(filename, ImageFormat.Png);
}
/// <summary>
/// Draw mesh to the graphics object.
/// </summary>
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);
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, p3;
// Draw triangle edges
foreach (var tri in mesh.Triangles)
{
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]].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
foreach (var seg in mesh.Segments)
{
p1 = points[seg.P0];
p2 = points[seg.P1];
// Draw line
g.DrawLine(sgBrush, p1, p2);
}
// Scale the points radius to 2 pixel.
float radius = 1.5f / scale, x, y;
// Draw points
int n = mesh.NumberOfInputPoints;
for (int i = 0; i < n; i++)
{
x = points[i].X;
y = points[i].Y;
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);
}
else
{
g.FillEllipse(spBrush, x - radius, y - radius, 2 * radius, 2 * radius);
//g.DrawEllipse(ptBrush, x - radius, y - radius, 2 * radius, 2 * radius);
}
}
bgBrush.Dispose();
ptBrush.Dispose();
spBrush.Dispose();
lnBrush.Dispose();
sgBrush.Dispose();
trBrush.Dispose();
}
/// <summary>
/// Draw mesh to the graphics object.
/// </summary>
private static void DrawVoronoi(Graphics g, Mesh mesh, Voronoi 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,
TriangleNet.Geometry.Point direction)
{
double x = pt.X;
double y = pt.Y;
double dx = direction.X;
double dy = direction.Y;
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;
}
}
}
}
+28 -13
View File
@@ -69,10 +69,25 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="Controls\DarkToolStripRenderer.cs" />
<Compile Include="Controls\RendererControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="DarkMessageBox.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Examples.cs" />
<Compile Include="FormExport.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormExport.Designer.cs">
<DependentUpon>FormExport.cs</DependentUpon>
</Compile>
<Compile Include="FormGenerator.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormGenerator.Designer.cs">
<DependentUpon>FormGenerator.cs</DependentUpon>
</Compile>
<Compile Include="FormLog.cs">
<SubType>Form</SubType>
</Compile>
@@ -85,15 +100,11 @@
<Compile Include="FormMain.Designer.cs">
<DependentUpon>FormMain.cs</DependentUpon>
</Compile>
<Compile Include="Controls\MeshRenderer.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="FormQuality.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormQuality.Designer.cs">
<DependentUpon>FormQuality.cs</DependentUpon>
</Compile>
<Compile Include="Generators\IGenerator.cs" />
<Compile Include="Generators\RandomPoints.cs" />
<Compile Include="Generators\RandomPointsCircle.cs" />
<Compile Include="Generators\RingPolygon.cs" />
<Compile Include="Generators\StarInBox.cs" />
<Compile Include="IO\ImageWriter.cs" />
<Compile Include="IO\FileProcessor.cs" />
<Compile Include="IO\Formats\DatFile.cs" />
@@ -101,20 +112,24 @@
<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\MeshRenderer.cs" />
<Compile Include="Rendering\RenderColors.cs" />
<Compile Include="Rendering\RenderData.cs" />
<Compile Include="Rendering\VoronoiRenderer.cs" />
<Compile Include="Rendering\Zoom.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Util.cs" />
<EmbeddedResource Include="FormExport.resx">
<DependentUpon>FormExport.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="FormGenerator.resx">
<DependentUpon>FormGenerator.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="FormQuality.resx">
<DependentUpon>FormQuality.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Triangle\Triangle.csproj">
-115
View File
@@ -1,115 +0,0 @@
// -----------------------------------------------------------------------
// <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;
}
}
}
@@ -0,0 +1,150 @@
// -----------------------------------------------------------------------
// <copyright file="MeshRenderer.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Rendering
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using TriangleNet;
/// <summary>
/// Renders a mesh.
/// </summary>
public class MeshRenderer
{
Zoom zoom;
RenderData data;
RenderColors renderColors;
public MeshRenderer(RenderData data)
{
this.data = data;
}
private void RenderPoints(Graphics g)
{
PointF pt;
PointF[] pts = data.Points;
int i, n;
// Draw input points
n = data.NumberOfInputPoints;
for (i = 0; i < n; i++)
{
if (zoom.ViewportContains(pts[i]))
{
pt = zoom.WorldToScreen(pts[i]);
g.FillEllipse(renderColors.Point, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
}
}
// Draw Steiner points
n = pts.Length;
for (; i < n; i++)
{
if (zoom.ViewportContains(pts[i]))
{
pt = zoom.WorldToScreen(pts[i]);
g.FillEllipse(renderColors.SteinerPoint, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
}
}
}
private void RenderTriangles(Graphics g)
{
PointF p0, p1, p2;
PointF[] pts = data.Points;
var triangles = data.Triangles;
// Draw triangles
foreach (var tri in triangles)
{
if (zoom.ViewportContains(pts[tri.P0]) ||
zoom.ViewportContains(pts[tri.P1]) ||
zoom.ViewportContains(pts[tri.P2]))
{
p0 = zoom.WorldToScreen(pts[tri.P0]);
p1 = zoom.WorldToScreen(pts[tri.P1]);
p2 = zoom.WorldToScreen(pts[tri.P2]);
g.DrawLine(renderColors.Line, p0, p1);
g.DrawLine(renderColors.Line, p1, p2);
g.DrawLine(renderColors.Line, p2, p0);
}
}
}
private void RenderEdges(Graphics g)
{
PointF p0, p1;
PointF[] pts = data.Points;
var edges = data.Edges;
// Draw edges
foreach (var edge in edges)
{
if (zoom.ViewportContains(pts[edge.P0]) ||
zoom.ViewportContains(pts[edge.P1]))
{
p0 = zoom.WorldToScreen(pts[edge.P0]);
p1 = zoom.WorldToScreen(pts[edge.P1]);
g.DrawLine(renderColors.Line, p0, p1);
}
}
}
private void RenderSegments(Graphics g)
{
PointF p0, p1;
PointF[] pts = data.Points;
var segments = data.Segments;
foreach (var seg in segments)
{
if (zoom.ViewportContains(pts[seg.P0]) ||
zoom.ViewportContains(pts[seg.P1]))
{
p0 = zoom.WorldToScreen(pts[seg.P0]);
p1 = zoom.WorldToScreen(pts[seg.P1]);
g.DrawLine(renderColors.Segment, p0, p1);
}
}
}
public void Render(Graphics g, Zoom zoom, RenderColors renderColors)
{
this.renderColors = renderColors;
this.zoom = zoom;
if (data.Edges != null)
{
this.RenderEdges(g);
}
else if (data.Triangles != null)
{
this.RenderTriangles(g);
}
if (data.Segments != null)
{
this.RenderSegments(g);
}
if (data.Points != null)
{
this.RenderPoints(g);
}
}
}
}
@@ -0,0 +1,39 @@
// -----------------------------------------------------------------------
// <copyright file="RenderColors.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.Rendering
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
/// <summary>
/// Mesh color scheme.
/// </summary>
public class RenderColors
{
public static RenderColors Default = new RenderColors()
{
Background = Color.FromArgb(0, 0, 0),
Point = new SolidBrush(Color.Green),
SteinerPoint = new SolidBrush(Color.Peru),
Triangle = new SolidBrush(Color.Black),
Line = new Pen(Color.FromArgb(30, 30, 30)),
Segment = new Pen(Color.DarkBlue),
VoronoiLine = new Pen(Color.FromArgb(40, 50, 60))
};
public Color Background;
public Brush Point;
public Brush SteinerPoint;
public Brush Triangle;
public Pen Line;
public Pen Segment;
public Pen VoronoiLine;
}
}
@@ -22,8 +22,7 @@ namespace MeshExplorer.Rendering
Mesh mesh;
Voronoi simpleVoro;
BoundedVoronoi boundedVoro;
Pen lines = new Pen(Color.FromArgb(40, 50, 60));
RenderColors renderColors;
public VoronoiRenderer(Mesh mesh)
{
@@ -59,8 +58,10 @@ namespace MeshExplorer.Rendering
boundedVoro = null;
}
internal void Render(Graphics g, Zoom zoom)
public void Render(Graphics g, Zoom zoom, RenderColors renderColors)
{
this.renderColors = renderColors;
if (simpleVoro != null)
{
RenderSimple(g, zoom);
@@ -78,13 +79,8 @@ namespace MeshExplorer.Rendering
{
PointF p0, p1;
BBox bounds = new BBox(mesh.Bounds);
TriangleNet.Geometry.Point[] points = simpleVoro.Points;
// Enlarge 50%
bounds.Extend(0.5f);
// Draw edges
int n = simpleVoro.Edges == null ? 0 : simpleVoro.Edges.Length;
@@ -97,24 +93,21 @@ namespace MeshExplorer.Rendering
// Infinite voronoi edge
p0 = new PointF((float)points[seg.P0].X, (float)points[seg.P0].Y);
if (!BoxRayIntersection(bounds, points[seg.P0], simpleVoro.Directions[i], out p1))
if (zoom.ViewportContains(p0) &&
BoxRayIntersection(points[seg.P0], simpleVoro.Directions[i], out p1))
{
continue;
RenderEdge(g, zoom, p0, p1);
}
}
else
{
p0 = new PointF((float)points[seg.P0].X, (float)points[seg.P0].Y);
p1 = new PointF((float)points[seg.P1].X, (float)points[seg.P1].Y);
RenderEdge(g, zoom, p0, p1);
}
// Draw line
RenderEdge(g, zoom, p0, p1);
}
// Shrink 50%
bounds.Extend(-0.5f);
// Scale the points radius to 2 pixel.
//float radius = 1.5f / scale, x, y;
@@ -157,11 +150,11 @@ namespace MeshExplorer.Rendering
p0 = zoom.WorldToScreen(p0);
p1 = zoom.WorldToScreen(p1);
g.DrawLine(lines, p0, p1);
g.DrawLine(renderColors.VoronoiLine, p0, p1);
}
}
private bool BoxRayIntersection(BBox bounds, TriangleNet.Geometry.Point pt,
private bool BoxRayIntersection(TriangleNet.Geometry.Point pt,
TriangleNet.Geometry.Point direction, out PointF intersect)
{
double x = pt.X;
@@ -171,10 +164,21 @@ namespace MeshExplorer.Rendering
double t1, x1, y1, t2, x2, y2;
// Bounding box (50% enlarged)
var box = mesh.Bounds;
double dw = box.Width * 0.5f;
double dh = box.Height * 0.5f;
double minX = box.Xmin - dw;
double maxX = box.Xmax + dw;
double minY = box.Ymin - dh;
double maxY = box.Ymax + dh;
intersect = new PointF();
// Check if point is inside the bounds
if (x < bounds.MinX || x > bounds.MaxX || y < bounds.MinY || y > bounds.MaxY)
if (x < minX || x > maxX || y < minY || y > maxY)
{
return false;
}
@@ -182,16 +186,16 @@ namespace MeshExplorer.Rendering
// 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;
// Line going to the left: intersect with x = minX
t1 = (minX - x) / dx;
x1 = 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;
// Line going to the right: intersect with x = maxX
t1 = (maxX - x) / dx;
x1 = maxX;
y1 = y + t1 * dy;
}
else
@@ -204,17 +208,17 @@ namespace MeshExplorer.Rendering
// Calculate the cut through upper and lower boundaries
if (dy < 0)
{
// Line going downwards: intersect with y = bounds.MinY
t2 = (bounds.MinY - y) / dy;
// Line going downwards: intersect with y = minY
t2 = (minY - y) / dy;
x2 = x + t2 * dx;
y2 = bounds.MinY;
y2 = minY;
}
else if (dx > 0)
{
// Line going upwards: intersect with y = bounds.MaxY
t2 = (bounds.MaxY - y) / dy;
// Line going upwards: intersect with y = maxY
t2 = (maxY - y) / dy;
x2 = x + t2 * dx;
y2 = bounds.MaxY;
y2 = maxY;
}
else
{
@@ -236,38 +240,5 @@ namespace MeshExplorer.Rendering
return true;
}
/// <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 Extend(float amount)
{
float dx = amount * this.Width;
float dy = amount * this.Height;
MinX -= dx;
MaxX += dx;
MinY -= dy;
MaxY += dy;
}
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ namespace MeshExplorer.Rendering
/// <summary>
/// Manages the current world to screen transformation
/// </summary>
internal class Zoom
public class Zoom
{
// The complete mesh
Rectangle Screen { get; set; }