Move EPS and SVG writer to Triangle.Rendering project.

git-svn-id: https://triangle.svn.codeplex.com/svn@79411 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
SND\wo80_cp
2016-08-08 23:56:03 +00:00
parent f7dba8af41
commit 3f10f86307
11 changed files with 670 additions and 555 deletions
+4 -3
View File
@@ -11,6 +11,7 @@ using TriangleNet.Meshing.Algorithm;
using TriangleNet.Rendering;
using TriangleNet.Smoothing;
using TriangleNet.Voronoi;
using TriangleNet.Rendering.Text;
namespace MeshExplorer
{
@@ -704,17 +705,17 @@ namespace MeshExplorer
if (format == 1)
{
EpsImage eps = new EpsImage();
var eps = new EpsImage();
eps.Export(this.mesh, export.ImageName, size);
}
else if (format == 2)
{
SvgImage svg = new SvgImage();
var svg = new SvgImage();
svg.Export(this.mesh, export.ImageName, size);
}
else
{
RasterImage img = new RasterImage();
var img = new RasterImage();
img.Export(this.mesh, export.ImageName, size);
}
}
-423
View File
@@ -1,423 +0,0 @@
// -----------------------------------------------------------------------
// <copyright file="EpsImage.cs" company="">
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
// Original Matlab code by John Burkardt, Florida State University
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.IO
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using TriangleNet;
using TriangleNet.Geometry;
using IntPoint = System.Drawing.Point;
/// <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;
/// <summary>
/// Export the mesh to EPS format.
/// </summary>
/// <param name="mesh">The current mesh.</param>
/// <param name="filename">The EPS filename.</param>
/// <param name="width">The desired width of the image (currently ignored).</param>
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 (var eps = new FormattingStreamWriter(filename))
{
WriteHeader(filename, eps);
DrawClip(eps);
DrawEdges(eps, mesh);
DrawSegments(eps, mesh);
DrawPoints(eps, mesh);
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: 2");
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 DrawEdges(StreamWriter eps, Mesh mesh)
{
IntPoint a, b;
eps.WriteLine("%");
eps.WriteLine("% Draw the triangles (mesh edges).");
eps.WriteLine("%");
SetStroke(eps, 0.6f, 0.6f, 0.6f, 0.4f);
eps.WriteLine(@"/L {
2 dict begin
/y2 exch def
/x2 exch def
/y1 exch def
/x1 exch def
gsave
newpath x1 y1 moveto x2 y2 lineto stroke
grestore
end
} def");
foreach (var e in EnumerateEdges(mesh))
{
a = Transform(e.GetVertex(0));
b = Transform(e.GetVertex(1));
eps.WriteLine("{0} {1} {2} {3} L", a.X, a.Y, b.X, b.Y);
}
}
private void DrawSegments(StreamWriter eps, Mesh mesh)
{
IntPoint a, b;
eps.WriteLine("%");
eps.WriteLine("% Draw the segments.");
eps.WriteLine("%");
SetStroke(eps, 0.27f, 0.5f, 0.7f, 0.8f);
foreach (var s in mesh.Segments)
{
a = Transform(s.GetVertex(0));
b = Transform(s.GetVertex(1));
eps.WriteLine("{0} {1} {2} {3} L", a.X, a.Y, b.X, b.Y);
}
}
private void DrawPoints(StreamWriter eps, Mesh mesh)
{
IntPoint p;
int n = mesh.Vertices.Count;
// Size of the points.
int size = (n < 100) ? 3 : ((n < 500) ? 2 : 1);
eps.WriteLine("%");
eps.WriteLine("% Draw the vertices.");
eps.WriteLine("%");
SetColor(eps, 0.0f, 0.4f, 0.0f);
eps.WriteLine(@"/P {
2 dict begin
/y exch def
/x exch def
gsave
newpath x y 1 0 360 arc fill
grestore
end
} def");
// TODO: EPS point size.
// newpath x y {size} 0 360 arc fill
foreach (var node in mesh.Vertices)
{
p = Transform(node);
eps.WriteLine("{0} {1} P", p.X, p.Y);
}
}
/*
private void DrawPointLabels(StreamWriter eps, Mesh mesh)
{
int n = mesh.Vertices.Count;
IntPoint p;
StringBuilder labels = new StringBuilder();
foreach (var node in mesh.Vertices)
{
p = Transform(node);
labels.AppendFormat(" {0} {1} moveto ({2}) show", p.X, p.Y + 5, node.ID);
labels.AppendLine();
}
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.WriteLine(labels.ToString());
}
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("%");
IntPoint a, b, c;
foreach (var t in mesh.Triangles)
{
a = Transform(t.GetVertex(0));
b = Transform(t.GetVertex(1));
c = Transform(t.GetVertex(2));
eps.WriteLine("newpath");
eps.WriteLine(" {0} {1} moveto", a.X, a.Y);
eps.WriteLine(" {0} {1} lineto", b.X, b.Y);
eps.WriteLine(" {0} {1} lineto", c.X, c.Y);
eps.WriteLine(" {0} {1} lineto", a.X, a.Y);
eps.WriteLine("stroke");
}
}
private void DrawTriangleLabels(StreamWriter eps, Mesh mesh)
{
var labels = new StringBuilder();
IntPoint a, b, c;
foreach (var t in mesh.Triangles)
{
a = Transform(t.GetVertex(0));
b = Transform(t.GetVertex(1));
c = Transform(t.GetVertex(2));
eps.WriteLine("newpath");
a = Transform((a.X + b.X + c.X) / 3.0, (a.Y + b.Y + c.Y) / 3.0);
labels.AppendFormat(" {0} {1} moveto ({2}) show", a.X, a.Y, t.ID);
labels.AppendLine();
eps.WriteLine("stroke");
}
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.WriteLine(labels.ToString());
}
//*/
private void SetColor(StreamWriter eps, float r, float g, float b)
{
eps.WriteLine("{0} {1} {2} setrgbcolor", r, g, b);
eps.WriteLine("%");
}
private void SetStroke(StreamWriter eps, float r, float g, float b, float width)
{
eps.WriteLine("{0} {1} {2} setrgbcolor", r, g, b);
eps.WriteLine("{0} setlinewidth", width);
eps.WriteLine("%");
}
private IntPoint Transform(Point p)
{
return Transform(p.X, p.Y);
}
private IntPoint Transform(double x, double y)
{
return new IntPoint(
(int)Math.Floor(((x_max - x) * x_ps_min + (x - x_min) * x_ps_max) / (x_max - x_min)),
(int)Math.Floor(((y_max - y) * y_ps_min + (y - y_min) * y_ps_max) / (y_max - y_min))
);
}
private void UpdateMetrics(Rectangle bounds)
{
x_max = bounds.Right;
x_min = bounds.Left;
y_max = bounds.Top;
y_min = bounds.Bottom;
// 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;
}
}
public IEnumerable<ISegment> EnumerateEdges(Mesh mesh, bool segments = false)
{
foreach (var t in mesh.Triangles)
{
for (int i = 0; i < 3; i++)
{
int nid = t.GetNeighborID(i);
if ((t.ID < nid) || (nid < 0))
{
if (segments || t.GetSegment(i) == null)
{
yield return new Segment(
t.GetVertex((i + 1) % 3),
t.GetVertex((i + 2) % 3));
}
}
}
}
}
}
}
@@ -1,32 +0,0 @@
using System;
using System.Globalization;
using System.IO;
namespace MeshExplorer.IO
{
// From http://stackoverflow.com/questions/12011789/streamwriter-and-iformatprovider
public class FormattingStreamWriter : StreamWriter
{
private readonly IFormatProvider formatProvider;
public FormattingStreamWriter(string path)
: this(path, CultureInfo.InvariantCulture)
{
}
public FormattingStreamWriter(string path, IFormatProvider formatProvider)
: base(path)
{
this.formatProvider = formatProvider;
}
public override IFormatProvider FormatProvider
{
get
{
return this.formatProvider;
}
}
}
}
+1 -79
View File
@@ -7,12 +7,7 @@
namespace MeshExplorer.IO
{
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using TriangleNet;
using TriangleNet.Rendering;
using TriangleNet.Rendering.GDI;
/// <summary>
@@ -20,14 +15,6 @@ namespace MeshExplorer.IO
/// </summary>
public class RasterImage
{
ColorManager colors = RasterImage.LightScheme();
public ColorManager ColorScheme
{
get { return colors; }
set { colors = value; }
}
/// <summary>
/// Export the mesh to PNG format.
/// </summary>
@@ -42,72 +29,7 @@ namespace MeshExplorer.IO
filename = String.Format("mesh-{0}.png", DateTime.Now.ToString("yyyy-M-d-hh-mm-ss"));
}
Bitmap bitmap;
// Check if the specified width is reasonable
if (width < 2 * Math.Sqrt(mesh.Vertices.Count))
{
bitmap = new Bitmap(400, 200);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(Color.White);
string message = String.Format("Sorry, I won't render {0} points on such a small image!", mesh.Vertices.Count);
SizeF sz = g.MeasureString(message, SystemFonts.DefaultFont);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawString(message, SystemFonts.DefaultFont, Brushes.Black,
200 - sz.Width / 2, 100 - sz.Height / 2);
g.Dispose();
}
else
{
var bounds = mesh.Bounds;
// World margin on each side
float margin = (float)bounds.Height * 0.05f;
float scale = width / ((float)bounds.Width + 2 * margin);
var target = new Rectangle(0, 0, width, (int)((bounds.Height + 2 * margin) * scale));
bitmap = new Bitmap(width, target.Height, PixelFormat.Format32bppPArgb);
Graphics g = Graphics.FromImage(bitmap);
g.Clear(colors.Background);
g.SmoothingMode = SmoothingMode.HighQuality;
var context = new RenderContext(new Projection(target), colors);
context.Add(mesh, true);
var renderer = new LayerRenderer();
renderer.Context = context;
renderer.RenderTarget = g;
renderer.Render();
g.Dispose();
}
if (Path.GetExtension(filename) != ".png")
{
filename += ".png";
}
bitmap.Save(filename, ImageFormat.Png);
}
public static ColorManager LightScheme()
{
var colors = new ColorManager();
colors.Background = Color.White;
colors.Point = new SolidBrush(Color.FromArgb(60, 80, 120));
colors.SteinerPoint = new SolidBrush(Color.DarkGreen);
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;
ImageRenderer.Save(mesh, filename, width);
}
}
}
@@ -109,15 +109,12 @@
<Compile Include="Generators\RingPolygon.cs" />
<Compile Include="Generators\StarInBox.cs" />
<Compile Include="GenericEventArgs.cs" />
<Compile Include="IO\EpsImage.cs" />
<Compile Include="IO\FileProcessor.cs" />
<Compile Include="IO\Formats\JsonFile.cs" />
<Compile Include="IO\Formats\TriangleFile.cs" />
<Compile Include="IO\FormattingStreamWriter.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="Settings.cs" />
@@ -0,0 +1,197 @@
namespace TriangleNet.Rendering.Text
{
using System;
using System.Drawing;
using System.IO;
public class EpsDocument : IDisposable
{
// Constant to convert from millimeters to PostScript units (1/72th inch).
private const double UNITS_PER_MM = 72.0 / 25.4;
private FormattingStreamWriter _w;
private PageSize _size;
/// <summary>
/// Gets or sets the document name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the default point size (default = 1).
/// </summary>
public int DefaultPointSize { get; set; }
public EpsDocument(string filename, PageSize pageSize)
: this(File.Create(filename), pageSize)
{
Name = Path.GetFileName(filename);
}
public EpsDocument(Stream stream, PageSize pageSize)
{
_w = new FormattingStreamWriter(stream);
_w.NewLine = "\n";
_size = pageSize;
DefaultPointSize = 1;
}
//public void Append(string ps)
//{
// _w.WriteLine(ps);
//}
public void DrawPoint(Point p)
{
_w.WriteLine("{0} {1} P", p.X, p.Y);
}
public void DrawLine(Point p1, Point p2)
{
_w.WriteLine("{0} {1} {2} {3} L", p1.X, p1.Y, p2.X, p2.Y);
}
public void DrawRectangle(Rectangle rect)
{
_w.WriteLine("newpath");
_w.WriteLine(" {0} {1} moveto", rect.X, rect.Y);
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Y);
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Bottom);
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Bottom);
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Y);
_w.WriteLine("stroke");
}
public void SetClip(Rectangle rect)
{
_w.WriteLine("newpath");
_w.WriteLine(" {0} {1} moveto", rect.X, rect.Y);
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Y);
_w.WriteLine(" {0} {1} lineto", rect.Right, rect.Bottom);
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Bottom);
_w.WriteLine(" {0} {1} lineto", rect.X, rect.Y);
_w.WriteLine("clip newpath");
}
public void SetColor(Color color)
{
_w.WriteLine("{0:0.###} {1:0.###} {2:0.###} setrgbcolor",
((float)color.R) / 255f,
((float)color.G) / 255f,
((float)color.B) / 255f);
}
public void SetStroke(float width)
{
_w.WriteLine("{0:0.###} setlinewidth", width);
}
public void SetStroke(float width, Color color)
{
SetColor(color);
SetStroke(width);
}
public void WriteHeader()
{
var x = _size.X; // * UNITS_PER_MM
var y = _size.Y;
var right = _size.Right;
var bottom = _size.Bottom;
// Write document header.
_w.WriteLine("%!PS-Adobe-3.0 EPSF-3.0");
_w.WriteLine("%%Creator: Triangle.NET");
_w.WriteLine("%%Title: {0}", Name);
_w.WriteLine("%%Pages: 1");
_w.WriteLine("%%BoundingBox: {0} {1} {2} {3}", (int)x, (int)y, (int)right, (int)bottom);
_w.WriteLine("%%HiResBoundingBox: {0:0.#####} {1:0.#####} {2:0.#####} {3:0.#####}", x, y, right, bottom);
_w.WriteLine("%%Document-Fonts: Times-Roman");
_w.WriteLine("%%LanguageLevel: 3");
_w.WriteLine("%%EndComments");
_w.WriteLine("%%BeginProlog");
_w.WriteLine("/inch {72 mul} def");
_w.WriteLine("%%EndProlog");
_w.WriteLine("%%Page: 1 1");
_w.WriteLine("save");
// Define points.
_w.WriteLine("/P {");
_w.WriteLine("2 dict begin");
_w.WriteLine("/y exch def");
_w.WriteLine("/x exch def");
_w.WriteLine("gsave");
_w.WriteLine("newpath x y {0} 0 360 arc fill", DefaultPointSize);
_w.WriteLine("grestore");
_w.WriteLine("end");
_w.WriteLine("} def");
// Define lines.
_w.WriteLine("/L {");
_w.WriteLine("2 dict begin");
_w.WriteLine("/y2 exch def");
_w.WriteLine("/x2 exch def");
_w.WriteLine("/y1 exch def");
_w.WriteLine("/x1 exch def");
_w.WriteLine("gsave");
_w.WriteLine("newpath x1 y1 moveto x2 y2 lineto stroke");
_w.WriteLine("grestore");
_w.WriteLine("end");
_w.WriteLine("} def");
}
private void Close()
{
_w.WriteLine("%");
_w.WriteLine("restore showpage");
_w.WriteLine("%");
_w.WriteLine("% End of page.");
_w.WriteLine("%");
_w.WriteLine("%%Trailer");
_w.WriteLine("%%EOF");
}
#region IDisposable implementation
// Has Dispose already been called?
bool disposed = false;
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
Close();
if (disposing)
{
_w.Dispose();
_w = null;
}
// Free any unmanaged objects here.
//
disposed = true;
}
~EpsDocument()
{
Dispose(false);
}
#endregion
}
}
@@ -0,0 +1,297 @@
// -----------------------------------------------------------------------
// <copyright file="EpsImage.cs" company="">
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
// Original Matlab code by John Burkardt, Florida State University
// </copyright>
// -----------------------------------------------------------------------
namespace TriangleNet.Rendering.Text
{
using System;
using System.Collections.Generic;
using System.IO;
using TriangleNet;
using TriangleNet.Geometry;
using Color = System.Drawing.Color;
using IntPoint = System.Drawing.Point;
using IntRectangle = System.Drawing.Rectangle;
/// <summary>
/// Writes a mesh to an EPS file.
/// </summary>
public class EpsImage
{
// EPS page metrics
PageSize ps = new PageSize(36, 126, 576, 666);
PageSize clip = new PageSize(18, 108, 594, 684);
// Mesh metrics
double x_max, x_min;
double y_max, y_min;
//double x_scale, y_scale;
// TODO: use color manager
private static Color ColorPoints = Color.FromArgb(0, 100, 0);
private static Color ColorLines = Color.FromArgb(150, 150, 150);
private static Color ColorSegments = Color.FromArgb(70, 130, 180);
private static Color ColorBorder = Color.FromArgb(230, 230, 230);
/// <summary>
/// Export the mesh to EPS format.
/// </summary>
/// <param name="mesh">The current mesh.</param>
/// <param name="filename">The EPS filename.</param>
/// <param name="width">The desired width of the image (currently ignored).</param>
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 (var eps = new EpsDocument(filename, ps))
{
int n = mesh.Vertices.Count;
// Size of the points.
eps.DefaultPointSize = (n < 100) ? 3 : ((n < 500) ? 2 : 1);
eps.WriteHeader();
// Draw a gray border around the page.
eps.SetColor(ColorBorder);
eps.DrawRectangle(GetRectangle(ps));
// Define a clipping polygon.
eps.SetClip(GetRectangle(clip));
// Draw edges.
eps.SetStroke(0.4f, ColorLines);
foreach (var e in EnumerateEdges(mesh))
{
eps.DrawLine(Transform(e.GetVertex(0)), Transform(e.GetVertex(1)));
}
// Draw Segments.
eps.SetStroke(0.8f, ColorSegments);
foreach (var s in mesh.Segments)
{
eps.DrawLine(Transform(s.GetVertex(0)), Transform(s.GetVertex(1)));
}
// Draw points.
eps.SetColor(ColorPoints);
foreach (var node in mesh.Vertices)
{
eps.DrawPoint(Transform(node));
}
}
}
/*
private void DrawTitle(EpsDocument eps)
{
var buffer = new StringBuilder();
buffer.AppendLine("%");
buffer.AppendLine("% Set the RGB color to black.");
buffer.AppendLine("%");
buffer.AppendLine("0.000 0.000 0.000 setrgbcolor");
buffer.AppendLine("%");
buffer.AppendLine("% Set the font and its size.");
buffer.AppendLine("%");
buffer.AppendLine("/Times-Roman findfont");
buffer.AppendLine("0.50 inch scalefont");
buffer.AppendLine("setfont");
buffer.AppendLine("%");
buffer.AppendLine("% Print a title.");
buffer.AppendLine("%");
buffer.AppendLine("%210 702 moveto");
buffer.AppendLine("%(Triangulation) show");
}
private void DrawPointLabels(StreamWriter eps, Mesh mesh)
{
int n = mesh.Vertices.Count;
IntPoint p;
StringBuilder labels = new StringBuilder();
foreach (var node in mesh.Vertices)
{
p = Transform(node);
labels.AppendFormat(" {0} {1} moveto ({2}) show", p.X, p.Y + 5, node.ID);
labels.AppendLine();
}
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.WriteLine(labels.ToString());
}
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("%");
IntPoint a, b, c;
foreach (var t in mesh.Triangles)
{
a = Transform(t.GetVertex(0));
b = Transform(t.GetVertex(1));
c = Transform(t.GetVertex(2));
eps.WriteLine("newpath");
eps.WriteLine(" {0} {1} moveto", a.X, a.Y);
eps.WriteLine(" {0} {1} lineto", b.X, b.Y);
eps.WriteLine(" {0} {1} lineto", c.X, c.Y);
eps.WriteLine(" {0} {1} lineto", a.X, a.Y);
eps.WriteLine("stroke");
}
}
private void DrawTriangleLabels(StreamWriter eps, Mesh mesh)
{
var labels = new StringBuilder();
IntPoint a, b, c;
foreach (var t in mesh.Triangles)
{
a = Transform(t.GetVertex(0));
b = Transform(t.GetVertex(1));
c = Transform(t.GetVertex(2));
eps.WriteLine("newpath");
a = Transform((a.X + b.X + c.X) / 3.0, (a.Y + b.Y + c.Y) / 3.0);
labels.AppendFormat(" {0} {1} moveto ({2}) show", a.X, a.Y, t.ID);
labels.AppendLine();
eps.WriteLine("stroke");
}
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.WriteLine(labels.ToString());
}
//*/
private IntRectangle GetRectangle(PageSize size)
{
return new IntRectangle((int)size.X, (int)size.Y, (int)size.Width, (int)size.Height);
}
private IntPoint Transform(Point p)
{
return Transform(p.X, p.Y);
}
private IntPoint Transform(double x, double y)
{
return new IntPoint(
(int)Math.Floor(((x_max - x) * ps.X + (x - x_min) * ps.Right) / (x_max - x_min)),
(int)Math.Floor(((y_max - y) * ps.Y + (y - y_min) * ps.Bottom) / (y_max - y_min))
);
}
private void UpdateMetrics(Rectangle bounds)
{
x_max = bounds.Right;
x_min = bounds.Left;
y_max = bounds.Top;
y_min = bounds.Bottom;
// Enlarge width 5% on each side
double 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
double 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((ps.Right - ps.X) * (y_scale - x_scale) / (2.0 * y_scale));
ps.Expand(-delta, 0);
clip.Expand(-delta, 0);
}
else
{
int delta = (int)Math.Round((ps.Bottom - ps.Y) * (x_scale - y_scale) / (2.0 * x_scale));
ps.Expand(0, -delta);
clip.Expand(0, -delta);
}
}
public IEnumerable<ISegment> EnumerateEdges(Mesh mesh, bool segments = false)
{
foreach (var t in mesh.Triangles)
{
for (int i = 0; i < 3; i++)
{
int nid = t.GetNeighborID(i);
if ((t.ID < nid) || (nid < 0))
{
if (segments || t.GetSegment(i) == null)
{
yield return new Segment(
t.GetVertex((i + 1) % 3),
t.GetVertex((i + 2) % 3));
}
}
}
}
}
}
}
@@ -0,0 +1,73 @@
namespace TriangleNet.Rendering.Text
{
using System;
using System.Globalization;
using System.IO;
/// <summary>
///
/// </summary>
/// <remarks>
/// From http://stackoverflow.com/questions/12011789/streamwriter-and-iformatprovider
/// </remarks>
public class FormattingStreamWriter : StreamWriter
{
private readonly IFormatProvider formatProvider;
/// <summary>
/// Initializes a new instance of the StreamWriter class for the specified file
/// by using the default encoding and buffer size.
/// </summary>
/// <param name="path">The complete file path to write to.</param>
public FormattingStreamWriter(string path)
: this(path, CultureInfo.InvariantCulture)
{
}
/// <summary>
/// Initializes a new instance of the StreamWriter class for the specified stream
/// by using UTF-8 encoding and the default buffer size.
/// </summary>
/// <param name="stream">The stream to write to.</param>
public FormattingStreamWriter(Stream stream)
: this(stream, CultureInfo.InvariantCulture)
{
}
/// <summary>
/// Initializes a new instance of the StreamWriter class for the specified file
/// by using the default encoding and buffer size.
/// </summary>
/// <param name="path">The complete file path to write to.</param>
/// <param name="formatProvider">The format provider.</param>
public FormattingStreamWriter(string path, IFormatProvider formatProvider)
: base(path)
{
this.formatProvider = formatProvider;
}
/// <summary>
/// Initializes a new instance of the StreamWriter class for the specified stream
/// by using UTF-8 encoding and the default buffer size.
/// </summary>
/// <param name="stream">The stream to write to.</param>
/// <param name="formatProvider">The format provider.</param>
public FormattingStreamWriter(Stream stream, IFormatProvider formatProvider)
: base(stream)
{
this.formatProvider = formatProvider;
}
/// <summary>
/// Gets an object that controls formatting.
/// </summary>
public override IFormatProvider FormatProvider
{
get
{
return this.formatProvider;
}
}
}
}
@@ -0,0 +1,81 @@
namespace TriangleNet.Rendering.Text
{
using System.Drawing;
/// <summary>
/// Page size in millimeters.
/// </summary>
public struct PageSize
{
private const float MM_PER_INCH = 2.54f;
public static readonly PageSize A3 = new PageSize(297.0f, 420.0f);
public static readonly PageSize A4 = new PageSize(210.0f, 297.0f);
public static readonly PageSize A5 = new PageSize(148.0f, 210.0f);
public static readonly PageSize LETTER = new PageSize(8.5f * MM_PER_INCH, 11.0f * MM_PER_INCH);
public static readonly PageSize LEGAL = new PageSize(8.5f * MM_PER_INCH, 14.0f * MM_PER_INCH);
private float left;
private float top;
private float right;
private float bottom;
public float X
{
get { return left; }
}
public float Y
{
get { return top; }
}
public float Width
{
get { return right - left; }
}
public float Height
{
get { return bottom - top; }
}
public float Right
{
get { return right; }
}
public float Bottom
{
get { return bottom; }
}
public PageSize(float left, float top, float right, float bottom)
{
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public PageSize(float width, float height)
: this(0.0f, 0.0f, width, height)
{
}
public PageSize(Rectangle size)
: this(size.Left, size.Right, size.Top, size.Bottom)
{
}
public void Expand(float dx, float dy)
{
left -= dx;
top -= dy;
right += dx;
bottom += dy;
}
}
}
@@ -4,7 +4,7 @@
// </copyright>
// -----------------------------------------------------------------------
namespace MeshExplorer.IO
namespace TriangleNet.Rendering.Text
{
using System;
using System.IO;
@@ -54,7 +54,7 @@ namespace MeshExplorer.IO
int height = (int)((bounds.Height + 2 * margin) * scale);
using (StreamWriter svg = new StreamWriter(filename))
using (var svg = new FormattingStreamWriter(filename))
{
svg.WriteLine("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"");
svg.WriteLine(" width=\"{0}px\" height=\"{1}px\"", width, height);
@@ -96,18 +96,16 @@ namespace MeshExplorer.IO
x3 = scale * v3.X;
y3 = scale * v3.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));
svg.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} {4:0.#},{5:0.#} Z ",
x1, y1, x2, y2, x3, y3);
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.AppendFormat("<text x=\"{0:0.#}\" y=\"{1:0.#}\">{2}</text>",
xa, ya, tri.ID);
labels.AppendLine();
}
@@ -139,9 +137,8 @@ namespace MeshExplorer.IO
x2 = scale * seg.GetVertex(1).X;
y2 = scale * seg.GetVertex(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.Write("M {0:0.#},{1:0.#} L {2:0.#},{3:0.#} ",
x1, y1, x2, y2);
}
svg.WriteLine("\" style=\"stroke:#4682B4; fill:none; stroke-linejoin:bevel; stroke-width:2px;\"/>");
@@ -177,13 +174,13 @@ namespace MeshExplorer.IO
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);
svg.WriteLine(" <circle cx=\"{0:0.#}\" cy=\"{1:0.#}\" r=\"{2:0.#}\" />",
x, y, 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.AppendFormat("<text x=\"{0:0.#}\" y=\"{1:0.#}\">{2}</text>",
x, y, node.ID);
labels.AppendLine();
}
}
@@ -70,6 +70,11 @@
<Compile Include="RenderContext.cs" />
<Compile Include="RenderLayer.cs" />
<Compile Include="RenderManager.cs" />
<Compile Include="Text\EpsDocument.cs" />
<Compile Include="Text\EpsImage.cs" />
<Compile Include="Text\FormattingStreamWriter.cs" />
<Compile Include="Text\PageSize.cs" />
<Compile Include="Text\SvgImage.cs" />
<Compile Include="Util\BufferHelper.cs" />
<Compile Include="Util\ColorMap.cs" />
<Compile Include="Util\ReflectionHelper.cs" />