Image export (png, eps and svg)

git-svn-id: https://triangle.svn.codeplex.com/svn@68154 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2012-06-18 20:40:18 +00:00
parent 95ee6f9c6c
commit fc8eb1d2cd
18 changed files with 843 additions and 146 deletions
+24 -15
View File
@@ -53,11 +53,11 @@ namespace MeshExplorer.Controls
//
this.textBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
this.textBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.textBox.Location = new System.Drawing.Point(3, 2);
this.textBox.Location = new System.Drawing.Point(4, 2);
this.textBox.Name = "textBox";
this.textBox.TabIndex = 0;
//
// TextBoxDark
// DarkTextBox
//
this.BackColor = System.Drawing.Color.White;
this.Controls.Add(this.textBox);
@@ -83,40 +83,49 @@ namespace MeshExplorer.Controls
};
textBox.Font = this.Font;
textBox.Location = new Point(3, (this.Height - textBox.Height) / 2 + 1);
textBox.Location = new Point(4, (this.Height - textBox.Height) / 2);
textBox.Width = this.Width - 8;
textBox.TextAlign = HorizontalAlignment.Right;
textBox.TextAlign = HorizontalAlignment.Left;
textBox.ForeColor = this.ForeColor;
textBox.MaxLength = 6;
//textBox.MaxLength = 6;
textBox.GotFocus += delegate(object sender, EventArgs e)
{
textBox.ForeColor = Color.White;
textBox.ForeColor = this.ForeColor;
};
textBox.LostFocus += delegate(object sender, EventArgs e)
{
textBox.ForeColor = this.ForeColor;
textBox.ForeColor = ColorScheme.ColorGray68;
};
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rect = this.ClientRectangle;
Brush brushOuter = new LinearGradientBrush(rect, Color.FromArgb(82, 82, 82), Color.FromArgb(96, 96, 96),
LinearGradientMode.Vertical);
//Brush brushOuter = new LinearGradientBrush(rect, Color.FromArgb(82, 82, 82),
// Color.FromArgb(96, 96, 96), LinearGradientMode.Vertical);
Pen brushBorder = new Pen(Color.FromArgb(38, 38, 38), 1f);
Pen borderTop = new Pen(Color.FromArgb(76, 76, 76), 1f);
Pen borderBottom = new Pen(Color.FromArgb(128, 128, 128), 1f);
e.Graphics.FillRectangle(brushOuter, rect);
//e.Graphics.FillRectangle(brushOuter, rect);
rect = new Rectangle(1, 1, this.Width - 3, this.Height - 3);
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), rect);
g.FillRectangle(new SolidBrush(this.BackColor), rect);
e.Graphics.DrawRectangle(brushBorder, rect);
g.DrawLine(borderTop, 0, 0, this.Width - 1, 0);
g.DrawLine(borderTop, 0, 0, 0, this.Height - 1);
g.DrawLine(borderBottom, 1, this.Height - 1, this.Width - 1, this.Height - 1);
g.DrawLine(borderBottom, this.Width - 1, this.Height - 1, this.Width - 1, this.Height - 1);
brushOuter.Dispose();
brushBorder.Dispose();
//brushOuter.Dispose();
borderTop.Dispose();
borderBottom.Dispose();
base.OnPaint(e);
}
@@ -63,7 +63,7 @@ namespace MeshExplorer.Controls
{
SetStyle(ControlStyles.ResizeRedraw, true);
renderColors = RenderColors.Default;
renderColors = RenderColors.Default();
this.BackColor = renderColors.Background;
+15 -14
View File
@@ -14,6 +14,7 @@ namespace MeshExplorer
using TriangleNet.IO;
using TriangleNet.Geometry;
using MeshExplorer.IO;
using MeshExplorer.Rendering;
/// <summary>
/// Code of the online examples.
@@ -23,14 +24,14 @@ namespace MeshExplorer
// Make sure this path points to the polygon sample data.
static readonly string pathToData = @"..\..\..\Data\";
static ImageWriter imageWriter = new ImageWriter();
static RasterImage imageWriter = new RasterImage();
/// <summary>
/// Generating Delaunay triangulations
/// </summary>
public static void Example1()
{
imageWriter.SetColorSchemeLight();
imageWriter.ColorScheme = RenderColors.LightScheme();
// Create a mesh instance.
Mesh mesh = new Mesh();
@@ -38,18 +39,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.Export(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.Read(pathToData + "face.poly");
mesh.Triangulate(data);
imageWriter.WritePng(mesh, "face.png", 200);
imageWriter.Export(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.Export(mesh, "face-CDT.png", 200);
}
/// <summary>
@@ -57,7 +58,7 @@ namespace MeshExplorer
/// </summary>
public static void Example2()
{
imageWriter.SetColorSchemeLight();
imageWriter.ColorScheme = RenderColors.LightScheme();
// Create a mesh instance.
Mesh mesh = new Mesh();
@@ -68,18 +69,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.Export(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.Export(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.Export(mesh, "spiral-Area.png", 200);
}
/// <summary>
@@ -87,7 +88,7 @@ namespace MeshExplorer
/// </summary>
public static void Example3()
{
imageWriter.SetColorSchemeLight();
imageWriter.ColorScheme = RenderColors.LightScheme();
// Create a mesh instance.
Mesh mesh = new Mesh();
@@ -97,7 +98,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.Export(mesh, "box.png", 200);
// Save the current mesh to .node and .ele files
FileWriter.WriteNodes(mesh, "box.1.node");
@@ -105,11 +106,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.Export(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.Export(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
@@ -117,7 +118,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.Export(mesh, "box-Refine-3.png", 200);
}
/// <summary>
+98 -7
View File
@@ -28,26 +28,105 @@
/// </summary>
private void InitializeComponent()
{
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.lbSize = new System.Windows.Forms.Label();
this.darkSlider1 = new MeshExplorer.Controls.DarkSlider();
this.darkTextBox1 = new MeshExplorer.Controls.DarkTextBox();
this.darkListBox1 = new MeshExplorer.Controls.DarkListBox();
this.darkButton1 = new MeshExplorer.Controls.DarkButton();
this.btnExport = new MeshExplorer.Controls.DarkButton();
this.SuspendLayout();
//
// label2
//
this.label2.AutoSize = true;
this.label2.BackColor = System.Drawing.Color.Transparent;
this.label2.Location = new System.Drawing.Point(12, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(65, 13);
this.label2.TabIndex = 2;
this.label2.Text = "File fromat:\r\n";
//
// label3
//
this.label3.AutoSize = true;
this.label3.BackColor = System.Drawing.Color.Transparent;
this.label3.Location = new System.Drawing.Point(12, 198);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(59, 13);
this.label3.TabIndex = 2;
this.label3.Text = "File name:";
//
// label1
//
this.label1.AutoSize = true;
this.label1.BackColor = System.Drawing.Color.Transparent;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Location = new System.Drawing.Point(12, 156);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(302, 39);
this.label1.Size = new System.Drawing.Size(74, 13);
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.";
this.label1.Text = "Image width:";
//
// lbSize
//
this.lbSize.AutoSize = true;
this.lbSize.BackColor = System.Drawing.Color.Transparent;
this.lbSize.ForeColor = System.Drawing.Color.Gray;
this.lbSize.Location = new System.Drawing.Point(272, 156);
this.lbSize.Name = "lbSize";
this.lbSize.Size = new System.Drawing.Size(40, 13);
this.lbSize.TabIndex = 2;
this.lbSize.Text = "800 px";
//
// darkSlider1
//
this.darkSlider1.BackColor = System.Drawing.Color.Transparent;
this.darkSlider1.CriticalPercent = ((uint)(0u));
this.darkSlider1.Location = new System.Drawing.Point(15, 169);
this.darkSlider1.Maximum = 100;
this.darkSlider1.Minimum = 0;
this.darkSlider1.Name = "darkSlider1";
this.darkSlider1.Size = new System.Drawing.Size(297, 17);
this.darkSlider1.TabIndex = 5;
this.darkSlider1.Text = "darkSlider1";
this.darkSlider1.Value = 35;
this.darkSlider1.ValueChanging += new System.EventHandler(this.darkSlider1_ValueChanging);
//
// darkTextBox1
//
this.darkTextBox1.BackColor = System.Drawing.Color.White;
this.darkTextBox1.Cursor = System.Windows.Forms.Cursors.IBeam;
this.darkTextBox1.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.darkTextBox1.ForeColor = System.Drawing.Color.Black;
this.darkTextBox1.Location = new System.Drawing.Point(12, 214);
this.darkTextBox1.Name = "darkTextBox1";
this.darkTextBox1.Size = new System.Drawing.Size(300, 21);
this.darkTextBox1.TabIndex = 4;
this.darkTextBox1.TextAlign = System.Windows.Forms.HorizontalAlignment.Left;
//
// 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.Items.AddRange(new object[] {
"Portable Network Graphics (*.png)",
"Encapsulated PostScript (*.eps)",
"Scalable Vector Graphics (*.svg)"});
this.darkListBox1.Location = new System.Drawing.Point(12, 25);
this.darkListBox1.Name = "darkListBox1";
this.darkListBox1.Size = new System.Drawing.Size(302, 118);
this.darkListBox1.TabIndex = 3;
this.darkListBox1.SelectedIndexChanged += new System.EventHandler(this.darkListBox1_SelectedIndexChanged);
//
// darkButton1
//
this.darkButton1.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.darkButton1.Location = new System.Drawing.Point(162, 141);
this.darkButton1.Location = new System.Drawing.Point(144, 270);
this.darkButton1.Name = "darkButton1";
this.darkButton1.Size = new System.Drawing.Size(82, 23);
this.darkButton1.TabIndex = 1;
@@ -57,7 +136,7 @@
// btnExport
//
this.btnExport.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnExport.Location = new System.Drawing.Point(250, 141);
this.btnExport.Location = new System.Drawing.Point(232, 270);
this.btnExport.Name = "btnExport";
this.btnExport.Size = new System.Drawing.Size(82, 23);
this.btnExport.TabIndex = 0;
@@ -69,8 +148,14 @@
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(344, 172);
this.ClientSize = new System.Drawing.Size(324, 299);
this.Controls.Add(this.darkSlider1);
this.Controls.Add(this.darkTextBox1);
this.Controls.Add(this.darkListBox1);
this.Controls.Add(this.label2);
this.Controls.Add(this.lbSize);
this.Controls.Add(this.label1);
this.Controls.Add(this.label3);
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)));
@@ -91,6 +176,12 @@
private Controls.DarkButton btnExport;
private Controls.DarkButton darkButton1;
private Controls.DarkListBox darkListBox1;
private System.Windows.Forms.Label label2;
private Controls.DarkTextBox darkTextBox1;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.Label label1;
private Controls.DarkSlider darkSlider1;
private System.Windows.Forms.Label lbSize;
}
}
+53
View File
@@ -6,6 +6,7 @@ using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace MeshExplorer
{
@@ -16,6 +17,28 @@ namespace MeshExplorer
InitializeComponent();
}
public int ImageFormat
{
get { return darkListBox1.SelectedIndex; }
}
public int ImageSize
{
get
{
string s = lbSize.Text;
s = s.Substring(0, s.Length - 3);
int size = 0;
int.TryParse(s, out size);
return size;
}
}
public string ImageName
{
get { return darkTextBox1.Text; }
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
@@ -25,5 +48,35 @@ namespace MeshExplorer
e.Graphics.FillRectangle(Brushes.DimGray, rect);
}
private void darkListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string filename = darkTextBox1.Text;
if (!String.IsNullOrWhiteSpace(filename))
{
string ext = ".png";
if (darkListBox1.SelectedIndex == 1)
{
ext = ".eps";
}
else if (darkListBox1.SelectedIndex == 2)
{
ext = ".svg";
}
darkTextBox1.Text = Path.ChangeExtension(filename, ext);
}
}
private void darkSlider1_ValueChanging(object sender, EventArgs e)
{
int size = (int)((2000.0 - 200.0) / 100.0 * darkSlider1.Value + 200.0);
size = size - (size % 50);
lbSize.Text = size + " px";
}
}
}
+34 -12
View File
@@ -9,6 +9,7 @@ using MeshExplorer.IO;
using TriangleNet;
using TriangleNet.Geometry;
using TriangleNet.Tools;
using MeshExplorer.Rendering;
namespace MeshExplorer
{
@@ -319,21 +320,25 @@ namespace MeshExplorer
HandleMeshImport();
}
// else Message
// Update folder settings
settings.OfdFilterIndex = ofd.FilterIndex;
settings.OfdDirectory = Path.GetFullPath(ofd.FileName);
return;
}
}
else
input = FileProcessor.Read(ofd.FileName);
if (input != null)
{
input = FileProcessor.Read(ofd.FileName);
// Update settings
settings.CurrentFile = Path.GetFileName(ofd.FileName);
if (input != null)
{
// Update settings
settings.CurrentFile = Path.GetFileName(ofd.FileName);
HandleNewInput();
}
// else Message
HandleNewInput();
}
// else Message
// Update folder settings
settings.OfdFilterIndex = ofd.FilterIndex;
@@ -588,8 +593,25 @@ namespace MeshExplorer
if (export.ShowDialog() == DialogResult.OK)
{
ImageWriter imgWriter = new ImageWriter();
imgWriter.WritePng(this.mesh);
int format = export.ImageFormat;
int size = export.ImageSize;
if (format == 1)
{
EpsImage eps = new EpsImage();
eps.Export(this.mesh, export.ImageName, size);
}
else if (format == 2)
{
SvgImage svg = new SvgImage();
svg.Export(this.mesh, export.ImageName, size);
}
else
{
RasterImage img = new RasterImage();
img.ColorScheme = RenderColors.LightScheme();
img.Export(this.mesh, export.ImageName, size);
}
}
}
}
+358
View File
@@ -0,0 +1,358 @@
// -----------------------------------------------------------------------
// <copyright file="EpsImage.cs" company="">
// John Burkardt, Florida State University
// http://people.sc.fsu.edu/~jburkardt/m_src/fem2d_poisson/
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.IO
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MeshExplorer.Rendering;
using System.IO;
using TriangleNet;
using TriangleNet.Geometry;
/// <summary>
/// Writes a mesh to an EPS file.
/// </summary>
public class EpsImage
{
// EPS page metrics
int x_ps_max = 576;
int x_ps_max_clip = 594;
int x_ps_min = 36;
int x_ps_min_clip = 18;
int y_ps_max = 666;
int y_ps_max_clip = 684;
int y_ps_min = 126;
int y_ps_min_clip = 108;
// Mesh metrics
double x_max, x_min;
double y_max, y_min;
double x_scale, y_scale;
public void Export(Mesh mesh, string filename, int width)
{
// Check file name
if (String.IsNullOrWhiteSpace(filename))
{
filename = String.Format("mesh-{0}.eps", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
}
if (!filename.EndsWith(".eps"))
{
filename = Path.ChangeExtension(filename, ".eps");
}
UpdateMetrics(mesh.Bounds);
using (StreamWriter eps = new StreamWriter(filename))
{
WriteHeader(filename, eps);
DrawClip(eps);
DrawTriangles(eps, mesh, false);
DrawSegments(eps, mesh);
DrawPoints(eps, mesh, false);
WriteTrailer(eps);
}
}
private void WriteHeader(string filename, StreamWriter eps)
{
eps.WriteLine("%!PS-Adobe-3.0 EPSF-3.0");
eps.WriteLine("%%Creator: Triangle.NET Mesh Explorer");
eps.WriteLine("%%Title: {0}", filename);
eps.WriteLine("%%Pages: 1");
eps.WriteLine("%%BoundingBox: {0} {1} {2} {3}", x_ps_min, y_ps_min, x_ps_max, y_ps_max);
eps.WriteLine("%%Document-Fonts: Times-Roman");
eps.WriteLine("%%LanguageLevel: 1");
eps.WriteLine("%%EndComments");
eps.WriteLine("%%BeginProlog");
eps.WriteLine("/inch {72 mul} def");
eps.WriteLine("%%EndProlog");
eps.WriteLine("%%Page: 1 1");
}
private static void WriteTrailer(StreamWriter eps)
{
eps.WriteLine("%");
eps.WriteLine("restore showpage");
eps.WriteLine("%");
eps.WriteLine("% End of page.");
eps.WriteLine("%");
eps.WriteLine("%%Trailer");
eps.WriteLine("%%EOF");
}
private void DrawClip(StreamWriter eps)
{
eps.WriteLine("save");
eps.WriteLine("%");
eps.WriteLine("% Set the RGB color to very light gray.");
eps.WriteLine("%");
eps.WriteLine("0.900 0.900 0.900 setrgbcolor");
eps.WriteLine("%");
eps.WriteLine("% Draw a gray border around the page.");
eps.WriteLine("%");
eps.WriteLine("newpath");
eps.WriteLine(" {0} {1} moveto", x_ps_min, y_ps_min);
eps.WriteLine(" {0} {1} lineto", x_ps_max, y_ps_min);
eps.WriteLine(" {0} {1} lineto", x_ps_max, y_ps_max);
eps.WriteLine(" {0} {1} lineto", x_ps_min, y_ps_max);
eps.WriteLine(" {0} {1} lineto", x_ps_min, y_ps_min);
eps.WriteLine("stroke");
eps.WriteLine("%");
eps.WriteLine("% Set the RGB color to black.");
eps.WriteLine("%");
eps.WriteLine("0.000 0.000 0.000 setrgbcolor");
eps.WriteLine("%");
eps.WriteLine("% Set the font and its size.");
eps.WriteLine("%");
eps.WriteLine("/Times-Roman findfont");
eps.WriteLine("0.50 inch scalefont");
eps.WriteLine("setfont");
eps.WriteLine("%");
eps.WriteLine("% Print a title.");
eps.WriteLine("%");
eps.WriteLine("%210 702 moveto");
eps.WriteLine("%(Triangulation) show");
eps.WriteLine("%");
eps.WriteLine("% Define a clipping polygon.");
eps.WriteLine("%");
eps.WriteLine("newpath");
eps.WriteLine(" {0} {1} moveto", x_ps_min_clip, y_ps_min_clip);
eps.WriteLine(" {0} {1} lineto", x_ps_max_clip, y_ps_min_clip);
eps.WriteLine(" {0} {1} lineto", x_ps_max_clip, y_ps_max_clip);
eps.WriteLine(" {0} {1} lineto", x_ps_min_clip, y_ps_max_clip);
eps.WriteLine(" {0} {1} lineto", x_ps_min_clip, y_ps_min_clip);
eps.WriteLine("clip newpath");
}
private void DrawTriangles(StreamWriter eps, Mesh mesh, bool label)
{
eps.WriteLine("%");
eps.WriteLine("% Set the triangle line color and width.");
eps.WriteLine("%");
eps.WriteLine("0.6 0.6 0.6 setrgbcolor");
eps.WriteLine("0.5 setlinewidth");
eps.WriteLine("%");
eps.WriteLine("% Draw the triangles.");
eps.WriteLine("%");
StringBuilder labels = new StringBuilder();
double x1, y1, x2, y2, x3, y3, xa, ya;
int x_ps, y_ps;
foreach (var tri in mesh.Triangles)
{
eps.WriteLine("newpath");
x1 = tri[0].X; y1 = tri[0].Y;
x2 = tri[1].X; y2 = tri[1].Y;
x3 = tri[2].X; y3 = tri[2].Y;
x_ps = (int)Math.Floor(((x_max - x1) * x_ps_min + (x1 - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y1) * y_ps_min + (y1 - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" {0} {1} moveto", x_ps, y_ps);
x_ps = (int)Math.Floor(((x_max - x2) * x_ps_min + (x2 - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y2) * y_ps_min + (y2 - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" {0} {1} lineto", x_ps, y_ps);
x_ps = (int)Math.Floor(((x_max - x3) * x_ps_min + (x3 - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y3) * y_ps_min + (y3 - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" {0} {1} lineto", x_ps, y_ps);
x_ps = (int)Math.Floor(((x_max - x1) * x_ps_min + (x1 - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y1) * y_ps_min + (y1 - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" {0} {1} lineto", x_ps, y_ps);
if (label)
{
xa = (x1 + x2 + x3) / 3.0;
ya = (y1 + y2 + y3) / 3.0;
x_ps = (int)Math.Floor(((x_max - xa) * x_ps_min + (xa - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - ya) * y_ps_min + (ya - y_min) * y_ps_max) / (y_max - y_min));
labels.AppendFormat(" {0} {1} moveto ({2}) show", x_ps, y_ps, tri.ID);
labels.AppendLine();
}
eps.WriteLine("stroke");
}
// Label the triangles.
if (label)
{
eps.WriteLine("%");
eps.WriteLine("% Label the triangles.");
eps.WriteLine("%");
eps.WriteLine("% Set the RGB color to darker red.");
eps.WriteLine("%");
eps.WriteLine("0.950 0.250 0.150 setrgbcolor");
eps.WriteLine("/Times-Roman findfont");
eps.WriteLine("0.20 inch scalefont");
eps.WriteLine("setfont");
eps.WriteLine("%");
eps.Write(labels.ToString());
}
}
private void DrawSegments(StreamWriter eps, Mesh mesh)
{
eps.WriteLine("%");
eps.WriteLine("% Set the triangle line color and width.");
eps.WriteLine("%");
eps.WriteLine("0.27 0.5 0.7 setrgbcolor");
eps.WriteLine("0.75 setlinewidth");
eps.WriteLine("%");
eps.WriteLine("% Draw the triangles.");
eps.WriteLine("%");
StringBuilder labels = new StringBuilder();
double x1, y1, x2, y2;
int x_ps, y_ps;
foreach (var seg in mesh.Segments)
{
eps.WriteLine("newpath");
x1 = seg[0].X; y1 = seg[0].Y;
x2 = seg[1].X; y2 = seg[1].Y;
x_ps = (int)Math.Floor(((x_max - x1) * x_ps_min + (x1 - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y1) * y_ps_min + (y1 - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" {0} {1} moveto", x_ps, y_ps);
x_ps = (int)Math.Floor(((x_max - x2) * x_ps_min + (x2 - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y2) * y_ps_min + (y2 - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" {0} {1} lineto", x_ps, y_ps);
eps.WriteLine("stroke");
}
}
private void DrawPoints(StreamWriter eps, Mesh mesh, bool label)
{
int n = mesh.NumberOfVertices;
int circle_size = 1;
if (n < 100)
{
circle_size = 3;
}
else if (n < 500)
{
circle_size = 2;
}
eps.WriteLine("%");
eps.WriteLine("% Draw filled dots at the nodes.");
eps.WriteLine("%");
eps.WriteLine("% Set the RGB color to blue.");
eps.WriteLine("%");
eps.WriteLine("0.0 0.4 0.0 setrgbcolor");
eps.WriteLine("%");
double x, y;
int x_ps, y_ps;
StringBuilder labels = new StringBuilder();
foreach (var node in mesh.Vertices)
{
x = node.X;
y = node.Y;
x_ps = (int)Math.Floor(((x_max - x) * x_ps_min + (x - x_min) * x_ps_max) / (x_max - x_min));
y_ps = (int)Math.Floor(((y_max - y) * y_ps_min + (y - y_min) * y_ps_max) / (y_max - y_min));
eps.WriteLine(" newpath {0} {1} {2} 0 360 arc closepath fill", x_ps, y_ps, circle_size);
if (label)
{
labels.AppendFormat(" {0} {1} moveto ({2}) show", x_ps, y_ps + 5, node);
labels.AppendLine();
}
}
// Label the nodes.
if (label)
{
eps.WriteLine("%");
eps.WriteLine("% Label the nodes.");
eps.WriteLine("%");
eps.WriteLine("% Set the RGB color to darker blue.");
eps.WriteLine("%");
eps.WriteLine("0.000 0.250 0.850 setrgbcolor");
eps.WriteLine("/Times-Roman findfont");
eps.WriteLine("0.20 inch scalefont");
eps.WriteLine("setfont");
eps.WriteLine("%");
eps.Write(labels.ToString());
}
}
private void UpdateMetrics(BoundingBox bounds)
{
x_max = bounds.Xmax;
x_min = bounds.Xmin;
y_max = bounds.Ymax;
y_min = bounds.Ymin;
// Enlarge width 5% on each side
x_scale = x_max - x_min;
x_max = x_max + 0.05 * x_scale;
x_min = x_min - 0.05 * x_scale;
x_scale = x_max - x_min;
// Enlarge height 5% on each side
y_scale = y_max - y_min;
y_max = y_max + 0.05 * y_scale;
y_min = y_min - 0.05 * y_scale;
y_scale = y_max - y_min;
if (x_scale < y_scale)
{
int delta = (int)Math.Round((x_ps_max - x_ps_min) * (y_scale - x_scale) / (2.0 * y_scale));
x_ps_max = x_ps_max - delta;
x_ps_min = x_ps_min + delta;
x_ps_max_clip = x_ps_max_clip - delta;
x_ps_min_clip = x_ps_min_clip + delta;
x_scale = y_scale;
}
else
{
int delta = (int)Math.Round((y_ps_max - y_ps_min) * (x_scale - y_scale) / (2.0 * x_scale));
y_ps_max = y_ps_max - delta;
y_ps_min = y_ps_min + delta;
y_ps_max_clip = y_ps_max_clip - delta;
y_ps_min_clip = y_ps_min_clip + delta;
y_scale = x_scale;
}
}
}
}
@@ -20,82 +20,14 @@ namespace MeshExplorer.IO
/// <summary>
/// Writes an image of the mesh to disk.
/// </summary>
public class ImageWriter
public class RasterImage
{
RenderColors colors = RenderColors.Default;
RenderColors colors = RenderColors.Default();
/// <summary>
/// Sets the color scheme.
/// </summary>
/// <param name="background">Background color.</param>
/// <param name="points">Points color.</param>
/// <param name="steiner">Steiner points color.</param>
/// <param name="lines">Line color.</param>
/// <param name="segments">Segment color.</param>
public void SetColorScheme(Color background, Color points, Color steiner,
Color lines, Color segments, Color triangles)
public RenderColors ColorScheme
{
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 void SetColorSchemeLight()
{
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 void SetColorSchemeDark()
{
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 void WritePng(Mesh mesh)
{
WritePng(mesh, "", 1000);
}
/// <summary>
/// Draws the mesh and writes the image file.
/// </summary>
/// <param name="mesh">The mesh to visualize.</param>
/// <param name="filename">The filename (only PNG supported).</param>
public void WritePng(Mesh mesh, string filename)
{
WritePng(mesh, filename, 1000);
}
/// <summary>
/// Draws the mesh and writes the image file.
/// </summary>
/// <param name="mesh">The mesh to visualize.</param>
/// <param name="width">The target width of the image (pixel).</param>
public void WritePng(Mesh mesh, int width)
{
WritePng(mesh, "", width);
get { return colors; }
set { colors = value; }
}
/// <summary>
@@ -104,7 +36,7 @@ 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 void WritePng(Mesh mesh, string filename, int width)
public void Export(Mesh mesh, string filename, int width)
{
// Get mesh data -- TODO: Use RenderControl's RenderData
RenderData data = new RenderData();
+196
View File
@@ -0,0 +1,196 @@
// -----------------------------------------------------------------------
// <copyright file="SvgImage.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.IO
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MeshExplorer.Rendering;
using System.IO;
using TriangleNet;
/// <summary>
/// Writes a mesh to an SVG file.
/// </summary>
public class SvgImage
{
float scale = 1f;
int x_offset = 0;
int y_offset = 0;
public void Export(Mesh mesh, string filename, int width)
{
// Check file name
if (String.IsNullOrWhiteSpace(filename))
{
filename = String.Format("mesh-{0}.svg", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
}
if (!filename.EndsWith(".svg"))
{
filename = Path.ChangeExtension(filename, ".svg");
}
if (width < 200)
{
width = 200;
}
var bounds = mesh.Bounds;
float margin = 0.05f * (float)bounds.Width;
scale = width / ((float)bounds.Width + 2 * margin);
x_offset = -(int)((bounds.Xmin - margin) * scale);
y_offset = (int)((bounds.Ymax + margin) * scale);
int height = (int)((bounds.Height + 2 * margin) * scale);
using (StreamWriter svg = new StreamWriter(filename))
{
svg.WriteLine("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"");
svg.WriteLine(" width=\"{0}px\" height=\"{1}px\"", width, height);
svg.WriteLine(" viewBox=\"0 0 {0} {1}\">", width, height);
svg.WriteLine("<g transform=\"translate({0}, {1}) scale(1,-1)\">", x_offset, y_offset);
DrawTriangles(svg, mesh, false);
DrawSegments(svg, mesh);
DrawPoints(svg, mesh, false);
svg.WriteLine("</g>");
svg.WriteLine("</svg>");
}
}
private void DrawTriangles(StreamWriter svg, Mesh mesh, bool label)
{
svg.Write(" <path d=\"");
StringBuilder labels = new StringBuilder();
double x1, y1, x2, y2, x3, y3, xa, ya;
foreach (var tri in mesh.Triangles)
{
x1 = scale * tri[0].X;
y1 = scale * tri[0].Y;
x2 = scale * tri[1].X;
y2 = scale * tri[1].Y;
x3 = scale * tri[2].X;
y3 = scale * tri[2].Y;
svg.Write("M {0},{1} L {2},{3} {4},{5} Z ",
x1.ToString("0.0", Util.Nfi), y1.ToString("0.0", Util.Nfi),
x2.ToString("0.0", Util.Nfi), y2.ToString("0.0", Util.Nfi),
x3.ToString("0.0", Util.Nfi), y3.ToString("0.0", Util.Nfi));
if (label)
{
xa = (x1 + x2 + x3) / 3.0;
ya = (y1 + y2 + y3) / 3.0;
labels.AppendFormat("<text x=\"{0}\" y=\"{1}\">{2}</text>",
xa.ToString("0.0", Util.Nfi), ya.ToString("0.0", Util.Nfi), tri.ID);
labels.AppendLine();
}
}
svg.WriteLine("\" style=\"stroke:#969696; fill:none; stroke-linejoin:bevel;\"/>");
// Label the triangles.
if (label)
{
svg.WriteLine(" <g font-family=\"Verdana\" font-size=\"11\" fill=\"black\">");
svg.Write(labels.ToString());
svg.WriteLine(" <g/>");
}
}
private void DrawSegments(StreamWriter svg, Mesh mesh)
{
svg.Write(" <path d=\"");
StringBuilder labels = new StringBuilder();
double x1, y1, x2, y2;
foreach (var seg in mesh.Segments)
{
x1 = scale * seg[0].X;
y1 = scale * seg[0].Y;
x2 = scale * seg[1].X;
y2 = scale * seg[1].Y;
svg.Write("M {0},{1} L {2},{3} ",
x1.ToString("0.0", Util.Nfi), y1.ToString("0.0", Util.Nfi),
x2.ToString("0.0", Util.Nfi), y2.ToString("0.0", Util.Nfi));
}
svg.WriteLine("\" style=\"stroke:#4682B4; fill:none; stroke-linejoin:bevel; stroke-width:2px;\"/>");
}
private void DrawPoints(StreamWriter svg, Mesh mesh, bool label)
{
int n = mesh.NumberOfVertices;
int circle_size = 1;
if (n < 100)
{
circle_size = 4;
}
else if (n < 500)
{
circle_size = 3;
}
else if (n < 1000)
{
circle_size = 2;
}
svg.WriteLine(" <g style=\"fill: #006400\">");
double x, y;
StringBuilder labels = new StringBuilder();
foreach (var node in mesh.Vertices)
{
x = scale * node.X;
y = scale * node.Y;
svg.WriteLine(" <circle cx=\"{0}\" cy=\"{1}\" r=\"{2}\" />",
x.ToString("0.0", Util.Nfi), y.ToString("0.0", Util.Nfi), circle_size);
if (label)
{
labels.AppendFormat("<text x=\"{0}\" y=\"{1}\">{2}</text>",
x.ToString("0.0", Util.Nfi), y.ToString("0.0", Util.Nfi), node.ID);
labels.AppendLine();
}
}
svg.WriteLine(" </g>");
// Label the nodes.
if (label)
{
svg.WriteLine(" <g font-family=\"Verdana\" font-size=\"11\" fill=\"black\">");
svg.Write(labels.ToString());
svg.WriteLine(" <g/>");
}
}
}
}
+3 -1
View File
@@ -105,13 +105,15 @@
<Compile Include="Generators\RandomPointsCircle.cs" />
<Compile Include="Generators\RingPolygon.cs" />
<Compile Include="Generators\StarInBox.cs" />
<Compile Include="IO\ImageWriter.cs" />
<Compile Include="IO\EpsImage.cs" />
<Compile Include="IO\FileProcessor.cs" />
<Compile Include="IO\Formats\DatFile.cs" />
<Compile Include="IO\Formats\JsonFile.cs" />
<Compile Include="IO\Formats\TriangleFile.cs" />
<Compile Include="IO\IMeshFile.cs" />
<Compile Include="IO\JsonParser.cs" />
<Compile Include="IO\RasterImage.cs" />
<Compile Include="IO\SvgImage.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Rendering\MeshRenderer.cs" />
+33 -9
View File
@@ -17,16 +17,40 @@ namespace MeshExplorer.Rendering
/// </summary>
public class RenderColors
{
public static RenderColors Default = new RenderColors()
/// <summary>
/// Gets a color scheme with black background.
/// </summary>
public static RenderColors Default()
{
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))
};
var colors = new RenderColors();
colors.Background = Color.FromArgb(0, 0, 0);
colors.Point = new SolidBrush(Color.Green);
colors.SteinerPoint = new SolidBrush(Color.Peru);
colors.Triangle = new SolidBrush(Color.Black);
colors.Line = new Pen(Color.FromArgb(30, 30, 30));
colors.Segment = new Pen(Color.DarkBlue);
colors.VoronoiLine = new Pen(Color.FromArgb(40, 50, 60));
return colors;
}
/// <summary>
/// Gets a color scheme with white background.
/// </summary>
public static RenderColors LightScheme()
{
var colors = new RenderColors();
colors.Background = Color.White;
colors.Point = new SolidBrush(Color.FromArgb(60, 80, 120));
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);
colors.VoronoiLine = new Pen(Color.FromArgb(160, 170, 180));
return colors;
}
public Color Background;
public Brush Point;
-4
View File
@@ -826,8 +826,6 @@ namespace TriangleNet.Algorithm
return hullsize;
}
IO.DebugWriter dbgWriter;
/// <summary>
/// Form a Delaunay triangulation by the divide-and-conquer method.
/// </summary>
@@ -844,8 +842,6 @@ namespace TriangleNet.Algorithm
this.mesh = m;
dbgWriter = new IO.DebugWriter(m);
// Allocate an array of pointers to vertices for sorting.
// TODO: use ToArray
this.sortarray = new Vertex[m.invertices];
+8
View File
@@ -68,6 +68,14 @@ namespace TriangleNet.Data
get { return this.vertices[1].id; }
}
/// <summary>
/// Gets the segments endpoint.
/// </summary>
public Vertex this[int index]
{
get { return this.vertices[index]; } // TODO: Check range?
}
/// <summary>
/// Gets the segment boundary mark.
/// </summary>
+2 -2
View File
@@ -100,9 +100,9 @@ namespace TriangleNet.Data
/// <summary>
/// Gets the specified corners vertex id.
/// </summary>
public int this[int index]
public Vertex this[int index]
{
get { return this.vertices[index] == null ? -1 : this.vertices[index].id; }
get { return this.vertices[index]; } // TODO: Check range?
}
/// <summary>
+3 -2
View File
@@ -10,6 +10,7 @@ namespace TriangleNet.Geometry
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TriangleNet.Data;
/// <summary>
/// Triangle interface.
@@ -34,9 +35,9 @@ namespace TriangleNet.Geometry
/// </summary>
int P2 { get; }
/// <summary>
/// Gets the specified vertex id.
/// Gets the vertex at specified index.
/// </summary>
int this[int index] { get; }
Vertex this[int index] { get; }
/// <summary>
/// True if the triangle implementation contains neighbor information.
+4 -1
View File
@@ -119,10 +119,13 @@ namespace TriangleNet.IO
{
tri.triangle = item;
corner[0] = triangles[i].P0;
corner[1] = triangles[i].P1;
corner[2] = triangles[i].P2;
// Copy the triangle's three corners.
for (int j = 0; j < 3; j++)
{
corner[j] = triangles[i][j];
if ((corner[j] < 0) || (corner[j] >= mesh.invertices))
{
SimpleLog.Instance.Error("Triangle has an invalid vertex index.", "MeshReader.Reconstruct()");
+3 -2
View File
@@ -9,6 +9,7 @@ namespace TriangleNet.IO
{
using System;
using TriangleNet.Geometry;
using TriangleNet.Data;
/// <summary>
/// Simple triangle class for input.
@@ -61,9 +62,9 @@ namespace TriangleNet.IO
/// <summary>
/// Gets the specified corners vertex id.
/// </summary>
public int this[int index]
public Vertex this[int index]
{
get { return this.vertices[index]; }
get { return null; } // TODO: throw NotSupportedException?
}
public bool SupportsNeighbors
@@ -248,11 +248,11 @@ namespace TriangleNet.Tools
{
for (int j = 0; j < 3; j++)
{
gi = tri[j];
gi = tri[j].id;
for (int k = 0; k < 3; k++)
{
gj = tri[k];
gj = tri[k].id;
mu = Math.Max(mu, gj - gi);
ml = Math.Max(ml, gi - gj);