Test app improvements
git-svn-id: https://triangle.svn.codeplex.com/svn@67941 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
+83
-136
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+38
-10
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user