New rendering code check-in
git-svn-id: https://triangle.svn.codeplex.com/svn@75033 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class BoundingBox
|
||||
{
|
||||
public float Left;
|
||||
public float Right;
|
||||
public float Bottom;
|
||||
public float Top;
|
||||
|
||||
public float Width
|
||||
{
|
||||
get { return this.Right - this.Left; }
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get { return this.Top - this.Bottom; }
|
||||
}
|
||||
|
||||
public BoundingBox()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public BoundingBox(float left, float right, float bottom, float top)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Right = right;
|
||||
this.Bottom = bottom;
|
||||
this.Top = top;
|
||||
}
|
||||
|
||||
public void Update(Point pt)
|
||||
{
|
||||
this.Update(pt.X, pt.Y);
|
||||
}
|
||||
|
||||
public void Update(PointF pt)
|
||||
{
|
||||
this.Update(pt.X, pt.Y);
|
||||
}
|
||||
|
||||
public void Update(double x, double y)
|
||||
{
|
||||
Update((float)x, (float)y);
|
||||
}
|
||||
|
||||
public void Update(float x, float y)
|
||||
{
|
||||
// Update bounding box
|
||||
if (this.Left > x) this.Left = x;
|
||||
if (this.Right < x) this.Right = x;
|
||||
if (this.Bottom > y) this.Bottom = y;
|
||||
if (this.Top < y) this.Top = y;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.Left = float.MaxValue;
|
||||
this.Right = -float.MaxValue;
|
||||
this.Bottom = float.MaxValue;
|
||||
this.Top = -float.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public abstract class BufferBase<T> : IBuffer<T> where T : struct
|
||||
{
|
||||
protected T[] data;
|
||||
protected int size;
|
||||
|
||||
public BufferBase(int capacity, int size)
|
||||
{
|
||||
this.data = new T[capacity];
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public BufferBase(T[] data, int size)
|
||||
{
|
||||
this.data = data;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public T[] Data
|
||||
{
|
||||
get { return data; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return data == null ? 0 : data.Length; }
|
||||
}
|
||||
|
||||
public abstract int Size
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public abstract BufferTarget Target
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
public class ColorBuffer : BufferBase<Color>
|
||||
{
|
||||
public ColorBuffer(int capacity, int size)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
public ColorBuffer(Color[] data, int size)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
public override int Size
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
public override BufferTarget Target
|
||||
{
|
||||
get { return BufferTarget.ColorBuffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public enum BufferTarget : byte
|
||||
{
|
||||
ColorBuffer,
|
||||
IndexBuffer,
|
||||
VertexBuffer
|
||||
}
|
||||
|
||||
public interface IBuffer<T> where T : struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the contents of the buffer.
|
||||
/// </summary>
|
||||
T[] Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the buffer.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of one element in the buffer (i.e. 2 for 2D points
|
||||
/// or 3 for triangles).
|
||||
/// </summary>
|
||||
int Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer target (vertices or indices).
|
||||
/// </summary>
|
||||
BufferTarget Target { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public class IndexBuffer : BufferBase<int>
|
||||
{
|
||||
public IndexBuffer(int capacity, int size)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
public IndexBuffer(int[] data, int size)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of indices for one element (i.e. 2 for segments
|
||||
/// or 3 for triangles).
|
||||
/// </summary>
|
||||
public override int Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override BufferTarget Target
|
||||
{
|
||||
get { return BufferTarget.IndexBuffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Buffer
|
||||
{
|
||||
public class VertexBuffer : BufferBase<float>
|
||||
{
|
||||
public VertexBuffer(int capacity, int size = 2)
|
||||
: base(capacity, size)
|
||||
{
|
||||
}
|
||||
|
||||
public VertexBuffer(float[] data, int size = 2)
|
||||
: base(data, size)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of coordinates of one vertex in the buffer (i.e. 2 for
|
||||
/// 2D points or 3D points).
|
||||
/// </summary>
|
||||
public override int Size
|
||||
{
|
||||
get { return size; }
|
||||
}
|
||||
|
||||
public override BufferTarget Target
|
||||
{
|
||||
get { return BufferTarget.VertexBuffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
public class ColorManager
|
||||
{
|
||||
Color background;
|
||||
SolidBrush point;
|
||||
SolidBrush steinerPoint;
|
||||
Pen line;
|
||||
Pen segment;
|
||||
Pen voronoiLine;
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color.
|
||||
/// </summary>
|
||||
public Color Background
|
||||
{
|
||||
get { return background; }
|
||||
set { background = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for points.
|
||||
/// </summary>
|
||||
public SolidBrush Point
|
||||
{
|
||||
get { return point; }
|
||||
set
|
||||
{
|
||||
if (point != null) point.Dispose();
|
||||
point = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brush used for steiner points.
|
||||
/// </summary>
|
||||
public SolidBrush SteinerPoint
|
||||
{
|
||||
get { return steinerPoint; }
|
||||
set
|
||||
{
|
||||
if (steinerPoint != null) steinerPoint.Dispose();
|
||||
steinerPoint = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for mesh edges.
|
||||
/// </summary>
|
||||
public Pen Line
|
||||
{
|
||||
get { return line; }
|
||||
set
|
||||
{
|
||||
if (line != null) line.Dispose();
|
||||
line = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for mesh segments.
|
||||
/// </summary>
|
||||
public Pen Segment
|
||||
{
|
||||
get { return segment; }
|
||||
set
|
||||
{
|
||||
if (segment != null) segment.Dispose();
|
||||
segment = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pen used for Voronoi edges.
|
||||
/// </summary>
|
||||
public Pen VoronoiLine
|
||||
{
|
||||
get { return voronoiLine; }
|
||||
set
|
||||
{
|
||||
if (voronoiLine != null) voronoiLine.Dispose();
|
||||
voronoiLine = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a dictionary which maps region ids (or partition indices) to a color.
|
||||
/// </summary>
|
||||
public Dictionary<int, Color> ColorDictionary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a colormap which is used for function plotting.
|
||||
/// </summary>
|
||||
public ColorMap ColorMap { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the <see cref="ColorManager"/> class with default (dark) color scheme.
|
||||
/// </summary>
|
||||
public static ColorManager Default()
|
||||
{
|
||||
var colors = new ColorManager();
|
||||
|
||||
colors.Background = Color.FromArgb(0, 0, 0);
|
||||
colors.Point = new SolidBrush(Color.Green);
|
||||
colors.SteinerPoint = new SolidBrush(Color.Peru);
|
||||
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;
|
||||
}
|
||||
|
||||
public void CreateColorDictionary(int length)
|
||||
{
|
||||
var keys = new int[length];
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
keys[i] = i;
|
||||
}
|
||||
|
||||
CreateColorDictionary(keys, length);
|
||||
}
|
||||
|
||||
public void CreateColorDictionary(IEnumerable<int> keys, int length)
|
||||
{
|
||||
this.ColorDictionary = new Dictionary<int, Color>();
|
||||
|
||||
int i = 0, n = regionColors.Length;
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
this.ColorDictionary.Add(key, regionColors[i]);
|
||||
|
||||
i = (i + 1) % n;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Dispose(Dictionary<int, Brush> brushes)
|
||||
{
|
||||
foreach (var brush in brushes.Values)
|
||||
{
|
||||
brush.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal Dictionary<int, Brush> GetBrushDictionary()
|
||||
{
|
||||
var brushes = new Dictionary<int, Brush>();
|
||||
|
||||
foreach (var item in ColorDictionary)
|
||||
{
|
||||
brushes.Add(item.Key, new SolidBrush(item.Value));
|
||||
}
|
||||
|
||||
return brushes;
|
||||
}
|
||||
|
||||
// Change or add as many colors as you like...
|
||||
private static Color[] regionColors = {
|
||||
Color.FromArgb(200, 0, 0, 255),
|
||||
Color.FromArgb(200, 255, 0, 0),
|
||||
Color.FromArgb(200, 0, 255, 255),
|
||||
Color.FromArgb(200, 255, 255, 0),
|
||||
Color.FromArgb(200, 255, 0, 255),
|
||||
Color.FromArgb(200, 0, 255, 0),
|
||||
Color.FromArgb(200, 127, 0, 255),
|
||||
Color.FromArgb(200, 0, 127, 255)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// Check if segment (a, b) intersects rectangle.
|
||||
/// </summary>
|
||||
public static bool Intersects(this RectangleF rect, PointF a, PointF b)
|
||||
{
|
||||
// TODO: implement intersection.
|
||||
return rect.Contains(a) || rect.Contains(b);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if triangle (a, b, c) intersects rectangle.
|
||||
/// </summary>
|
||||
public static bool Intersects(this RectangleF rect, PointF a, PointF b, PointF c)
|
||||
{
|
||||
// TODO: implement intersection.
|
||||
return rect.Contains(a) || rect.Contains(b) || rect.Contains(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.GDI.Native;
|
||||
|
||||
public class FunctionRenderer
|
||||
{
|
||||
TriVertex[] points;
|
||||
GradientTriangle[] elements;
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public void Render(IRenderLayer layer)
|
||||
{
|
||||
Create(layer);
|
||||
|
||||
var hdc = RenderTarget.GetHdc();
|
||||
|
||||
NativeMethods.GradientFill(hdc,
|
||||
points, (uint)points.Length, elements, (uint)elements.Length,
|
||||
GradientFillMode.GRADIENT_FILL_TRIANGLE);
|
||||
|
||||
RenderTarget.ReleaseHdc(hdc);
|
||||
}
|
||||
|
||||
private void Create(IRenderLayer layer)
|
||||
{
|
||||
var zoom = Context.Zoom;
|
||||
var colors = layer.Colors.Data;
|
||||
|
||||
int length = colors.Length;
|
||||
|
||||
int size = layer.Points.Size;
|
||||
var data = layer.Points.Data;
|
||||
|
||||
if (length != data.Length / size)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
this.points = new TriVertex[length];
|
||||
|
||||
TriVertex vertex;
|
||||
Color color;
|
||||
PointF p = new PointF((float)data[0], (float)data[1]);
|
||||
|
||||
zoom.WorldToScreen(ref p);
|
||||
|
||||
// Get correction distance
|
||||
float dx = (p.X - (int)p.X) * 2.0f;
|
||||
float dy = (p.Y - (int)p.Y) * 2.0f;
|
||||
|
||||
// Create vertices.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
p.X = (float)data[size * i];
|
||||
p.Y = (float)data[size * i + 1];
|
||||
|
||||
zoom.WorldToScreen(ref p);
|
||||
|
||||
color = colors[i];
|
||||
|
||||
vertex = new TriVertex();
|
||||
|
||||
vertex.x = (int)(p.X + dx);
|
||||
vertex.y = (int)(p.Y + dy);
|
||||
|
||||
vertex.Red = (ushort)(color.R << 8);
|
||||
vertex.Green = (ushort)(color.G << 8);
|
||||
vertex.Blue = (ushort)(color.B << 8);
|
||||
vertex.Alpha = (ushort)(color.A << 8);
|
||||
|
||||
this.points[i] = vertex;
|
||||
}
|
||||
|
||||
var triangles = layer.Indices.Data;
|
||||
|
||||
length = triangles.Length / 3;
|
||||
|
||||
this.elements = new GradientTriangle[length];
|
||||
|
||||
GradientTriangle e;
|
||||
|
||||
// Create triangles.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
e = new GradientTriangle();
|
||||
|
||||
e.Vertex1 = (uint)triangles[3 * i];
|
||||
e.Vertex2 = (uint)triangles[3 * i + 1];
|
||||
e.Vertex3 = (uint)triangles[3 * i + 2];
|
||||
|
||||
this.elements[i] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
|
||||
public class LayerRenderer : IRenderer
|
||||
{
|
||||
MeshRenderer meshRenderer;
|
||||
FunctionRenderer functionRenderer;
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public LayerRenderer()
|
||||
{
|
||||
meshRenderer = new MeshRenderer();
|
||||
functionRenderer = new FunctionRenderer();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
meshRenderer.Context = Context;
|
||||
meshRenderer.RenderTarget = RenderTarget;
|
||||
|
||||
functionRenderer.Context = Context;
|
||||
functionRenderer.RenderTarget = RenderTarget;
|
||||
|
||||
// 0 = mesh (filled)
|
||||
// 1 = mesh (wireframe)
|
||||
// 2 = polygon
|
||||
// 3 = points
|
||||
// 4 = voronoi overlay
|
||||
// 5 = vector field
|
||||
// 6 = contour lines
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var layer in this.Context.RenderLayers)
|
||||
{
|
||||
if (!layer.IsEmpty && layer.IsActive)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
RenderFilledMesh(layer);
|
||||
break;
|
||||
case 1:
|
||||
RenderMesh(layer);
|
||||
break;
|
||||
case 2:
|
||||
RenderPolygon(layer);
|
||||
break;
|
||||
case 3:
|
||||
RenderPoints(layer);
|
||||
break;
|
||||
case 4:
|
||||
RenderVoronoi(layer);
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderFilledMesh(IRenderLayer layer)
|
||||
{
|
||||
if (layer.Partition != null)
|
||||
{
|
||||
meshRenderer.RenderElements(layer.Points.Data, layer.Indices.Data, 3, layer.Partition.Data);
|
||||
}
|
||||
else if (layer.Colors != null)
|
||||
{
|
||||
functionRenderer.Render(layer);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderMesh(IRenderLayer layer)
|
||||
{
|
||||
if (layer.Indices.Size == 3)
|
||||
{
|
||||
meshRenderer.RenderElements(layer.Points.Data, layer.Indices.Data, 3, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, Context.ColorManager.Line);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderPolygon(IRenderLayer layer)
|
||||
{
|
||||
meshRenderer.RenderSegments(layer.Points.Data, layer.Indices.Data, Context.ColorManager.Segment);
|
||||
}
|
||||
|
||||
private void RenderPoints(IRenderLayer layer)
|
||||
{
|
||||
meshRenderer.RenderPoints(layer.Points.Data, layer.Points.Size, layer.Count);
|
||||
}
|
||||
|
||||
private void RenderVoronoi(IRenderLayer layer)
|
||||
{
|
||||
meshRenderer.RenderEdges(layer.Points.Data, layer.Indices.Data, Context.ColorManager.VoronoiLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="MeshRenderer.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System.Drawing;
|
||||
using TriangleNet.Rendering.GDI.Native;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh.
|
||||
/// </summary>
|
||||
public class MeshRenderer
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
|
||||
/// </summary>
|
||||
public MeshRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
public Graphics RenderTarget { get; set; }
|
||||
|
||||
public IRenderContext Context { get; set; }
|
||||
|
||||
public void RenderPoints(float[] points, int size, int limit = 0)
|
||||
{
|
||||
int n = points.Length / size;
|
||||
int m = limit > 0 ? limit : n;
|
||||
|
||||
// Draw unchanged points
|
||||
RenderPoints(points, size, 0, m, Context.ColorManager.Point);
|
||||
|
||||
// Draw new (Steiner) points
|
||||
if (limit > 0)
|
||||
{
|
||||
RenderPoints(points, size, m, n, Context.ColorManager.SteinerPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderPoints(float[] points, int size, int start, int end, Brush brush)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int i, k, n = points.Length / size;
|
||||
PointF p = new PointF();
|
||||
|
||||
// Render points
|
||||
for (i = start; i < end; i++)
|
||||
{
|
||||
k = size * i;
|
||||
|
||||
p.X = points[k];
|
||||
p.Y = points[k + 1];
|
||||
|
||||
if (zoom.Viewport.Contains(p))
|
||||
{
|
||||
zoom.WorldToScreen(ref p);
|
||||
g.FillEllipse(brush, p.X - 1.5f, p.Y - 1.5f, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderSegments(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
RenderLines(points, indices, pen);
|
||||
}
|
||||
|
||||
public void RenderEdges(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
RenderLines(points, indices, pen);
|
||||
}
|
||||
|
||||
public void RenderElements(float[] points, int[] indices, int size, int[] partition)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int n = indices.Length / size;
|
||||
int k0, k1, k2;
|
||||
|
||||
var tri = new PointF[size];
|
||||
|
||||
bool filled = partition != null;
|
||||
|
||||
var brushes = filled ? Context.ColorManager.GetBrushDictionary() : null;
|
||||
|
||||
// TODO: remove hardcoded color
|
||||
var pen = new Pen(Color.FromArgb(20, 20, 20));
|
||||
|
||||
// Draw triangles
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * indices[3 * i];
|
||||
k1 = 2 * indices[3 * i + 1];
|
||||
k2 = 2 * indices[3 * i + 2];
|
||||
|
||||
tri[0].X = points[k0];
|
||||
tri[0].Y = points[k0 + 1];
|
||||
|
||||
tri[1].X = points[k1];
|
||||
tri[1].Y = points[k1 + 1];
|
||||
|
||||
tri[2].X = points[k2];
|
||||
tri[2].Y = points[k2 + 1];
|
||||
|
||||
if (zoom.Viewport.Intersects(tri[0], tri[1], tri[2]))
|
||||
{
|
||||
zoom.WorldToScreen(ref tri[0]);
|
||||
zoom.WorldToScreen(ref tri[1]);
|
||||
zoom.WorldToScreen(ref tri[2]);
|
||||
|
||||
if (filled)
|
||||
{
|
||||
g.FillPolygon(brushes[partition[i]], tri);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.DrawPolygon(pen, tri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pen.Dispose();
|
||||
|
||||
if (filled)
|
||||
{
|
||||
Context.ColorManager.Dispose(brushes);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderLines(float[] points, int[] indices, Pen pen)
|
||||
{
|
||||
var g = this.RenderTarget;
|
||||
var zoom = this.Context.Zoom;
|
||||
|
||||
int n = indices.Length / 2;
|
||||
int k0, k1;
|
||||
|
||||
PointF p0 = new PointF();
|
||||
PointF p1 = new PointF();
|
||||
|
||||
// Draw edges
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * indices[2 * i];
|
||||
k1 = 2 * indices[2 * i + 1];
|
||||
|
||||
p0.X = points[k0];
|
||||
p0.Y = points[k0 + 1];
|
||||
|
||||
p1.X = points[k1];
|
||||
p1.Y = points[k1 + 1];
|
||||
|
||||
if (zoom.Viewport.Intersects(p0, p1))
|
||||
{
|
||||
zoom.WorldToScreen(ref p0);
|
||||
zoom.WorldToScreen(ref p1);
|
||||
|
||||
g.DrawLine(pen, p0, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies gradient fill mode
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum GradientFillMode : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// In this mode, two endpoints describe a rectangle. The rectangle is defined
|
||||
/// to have a constant color (specified by the TRIVERTEX structure) for the
|
||||
/// left and right edges. GDI interpolates the color from the left to right
|
||||
/// edge and fills the interior
|
||||
/// </summary>
|
||||
GRADIENT_FILL_RECT_H = 0,
|
||||
/// <summary>
|
||||
/// In this mode, two endpoints describe a rectangle. The rectangle is
|
||||
/// defined to have a constant color (specified by the TRIVERTEX structure)
|
||||
/// for the top and bottom edges. GDI interpolates the color from the top
|
||||
/// to bottom edge and fills the interior
|
||||
/// </summary>
|
||||
GRADIENT_FILL_RECT_V = 1,
|
||||
/// <summary>
|
||||
/// In this mode, an array of TRIVERTEX structures is passed to GDI
|
||||
/// along with a list of array indexes that describe separate triangles.
|
||||
/// GDI performs linear interpolation between triangle vertices and fills
|
||||
/// the interior. Drawing is done directly in 24- and 32-bpp modes.
|
||||
/// Dithering is performed in 16-, 8-, 4-, and 1-bpp mode
|
||||
/// </summary>
|
||||
GRADIENT_FILL_TRIANGLE = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The GRADIENT_RECT structure specifies the index of two vertices in the
|
||||
/// pVertex array in the GradientFill function. These two vertices form the
|
||||
/// upper-left and lower-right boundaries of a rectangle.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144958.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct GradientRect
|
||||
{
|
||||
/// <summary>
|
||||
/// The upper-left corner of a rectangle.
|
||||
/// </summary>
|
||||
public uint UpperLeft;
|
||||
|
||||
/// <summary>
|
||||
/// The lower-right corner of a rectangle.
|
||||
/// </summary>
|
||||
public uint LowerRight;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The GRADIENT_TRIANGLE structure specifies the index of three
|
||||
/// vertices in the pVertex array in the GradientFill function.
|
||||
/// These three vertices form one triangle
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144959.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct GradientTriangle
|
||||
{
|
||||
/// <summary>
|
||||
/// The first point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex1;
|
||||
|
||||
/// <summary>
|
||||
/// The second point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex2;
|
||||
|
||||
/// <summary>
|
||||
/// The third point of the triangle where sides intersect.
|
||||
/// </summary>
|
||||
public uint Vertex3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// PInvoke signatures for GradientFill methods.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Minimum requirements: Windows 2000 Professional
|
||||
///
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd144957.aspx
|
||||
/// </remarks>
|
||||
internal static class NativeMethods
|
||||
{
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device contex</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">Array of elements</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, uint[] pMesh, uint nMesh,
|
||||
GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device contex</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">Array of GRADIENT_TRIANGLE structures in triangle mode</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientTriangle[] pMesh,
|
||||
uint nMesh, GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GradientFill function fills rectangle and triangle structures
|
||||
/// </summary>
|
||||
/// <param name="hdc">Handle to the destination device contex</param>
|
||||
/// <param name="pVertex">Array of TRIVERTEX structures that each define a triangle vertex</param>
|
||||
/// <param name="nVertex">The number of vertices in pVertex</param>
|
||||
/// <param name="pMesh">an array of GRADIENT_RECT structures in rectangle mode</param>
|
||||
/// <param name="nMesh">The number of elements in pMesh</param>
|
||||
/// <param name="ulMode">Specifies gradient fill mode</param>
|
||||
/// <returns>If the function succeeds, the return value is true, false</returns>
|
||||
public static bool GradientFill([In] IntPtr hdc, TriVertex[] pVertex, uint nVertex, GradientRect[] pMesh,
|
||||
uint nMesh, GradientFillMode ulMode)
|
||||
{
|
||||
return Native.GradientFill(hdc, pVertex, nVertex, pMesh, nMesh, ulMode);
|
||||
}
|
||||
|
||||
#region Nested type: Native
|
||||
|
||||
internal class Native
|
||||
{
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, uint[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, GradientRect[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
|
||||
[DllImport("msimg32.dll", EntryPoint = "GradientFill", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GradientFill([In] IntPtr hdc,
|
||||
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Struct, SizeParamIndex = 2)] TriVertex[] pVertex,
|
||||
uint nVertex, GradientTriangle[] pMesh, uint nMesh, GradientFillMode ulMode);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
namespace TriangleNet.Rendering.GDI.Native
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// The TRIVERTEX structure contains color information and position information.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// http://msdn.microsoft.com/en-us/library/windows/desktop/dd145142.aspx
|
||||
/// </remarks>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct TriVertex
|
||||
{
|
||||
/// <summary>
|
||||
/// The x-coordinate, in logical units, of the upper-left corner of the rectangle
|
||||
/// </summary>
|
||||
public int x;
|
||||
|
||||
/// <summary>
|
||||
/// The y-coordinate, in logical units, of the upper-left corner of the rectangle
|
||||
/// </summary>
|
||||
public int y;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Red;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Green;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Blue;
|
||||
|
||||
/// <summary>
|
||||
/// The color information at the point of x, y
|
||||
/// </summary>
|
||||
public ushort Alpha;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="RendererControl.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh using GDI.
|
||||
/// </summary>
|
||||
public class RenderControl : Control, IRenderControl
|
||||
{
|
||||
// Rendering stuff
|
||||
private BufferedGraphics buffer;
|
||||
private BufferedGraphicsContext context;
|
||||
|
||||
//ColorManager renderColors;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
string coordinate = String.Empty;
|
||||
|
||||
Timer timer;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenderControl" /> class.
|
||||
/// </summary>
|
||||
public RenderControl()
|
||||
{
|
||||
//this.SetStyle(ControlStyles.UserPaint, true);
|
||||
//this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
|
||||
this.SetStyle(ControlStyles.ResizeRedraw, true);
|
||||
|
||||
//renderColors = ColorManager.Default();
|
||||
|
||||
this.BackColor = Color.Black;
|
||||
|
||||
context = BufferedGraphicsManager.Current;// new BufferedGraphicsContext();
|
||||
|
||||
timer = new Timer();
|
||||
timer.Interval = 3000;
|
||||
timer.Tick += (sender, e) =>
|
||||
{
|
||||
timer.Stop();
|
||||
coordinate = String.Empty;
|
||||
this.Invalidate();
|
||||
};
|
||||
}
|
||||
|
||||
public IRenderer Renderer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the graphics buffer (should be called in the forms load event).
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
//zoom.Initialize(this.ClientRectangle);
|
||||
InitializeBuffer();
|
||||
|
||||
initialized = true;
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void HandleMouseClick(float x, float y, MouseButtons button)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (button == MouseButtons.Middle)
|
||||
{
|
||||
zoom.Reset();
|
||||
this.Render();
|
||||
}
|
||||
else if (button == MouseButtons.Left)
|
||||
{
|
||||
timer.Stop();
|
||||
|
||||
var nfi = System.Globalization.CultureInfo.InvariantCulture.NumberFormat;
|
||||
|
||||
PointF c = new PointF(x / this.Width, y / this.Height);
|
||||
zoom.ScreenToWorld(ref c);
|
||||
coordinate = String.Format(nfi, "X:{0} Y:{1}", c.X, c.Y);
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom to the given location.
|
||||
/// </summary>
|
||||
/// <param name="location">The zoom focus.</param>
|
||||
/// <param name="delta">Indicates whether to zoom in or out.</param>
|
||||
public void HandleMouseWheel(float x, float y, int delta)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
|
||||
if (zoom.Zoom(delta, x, y))
|
||||
{
|
||||
// Redraw
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update graphics buffer and zoom after a resize.
|
||||
/// </summary>
|
||||
public void HandleResize()
|
||||
{
|
||||
var zoom = this.Renderer.Context.Zoom;
|
||||
var bounds = this.Renderer.Context.Bounds;
|
||||
|
||||
zoom.Initialize(this.ClientRectangle, bounds);
|
||||
InitializeBuffer();
|
||||
}
|
||||
|
||||
private void InitializeBuffer()
|
||||
{
|
||||
if (this.Width > 0 && this.Height > 0)
|
||||
{
|
||||
if (buffer != null)
|
||||
{
|
||||
if (this.ClientRectangle == buffer.Graphics.VisibleClipBounds)
|
||||
{
|
||||
this.Invalidate();
|
||||
|
||||
// Bounds didn't change. Probably we just restored the
|
||||
// window from minimized state.
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Dispose();
|
||||
}
|
||||
|
||||
//buffer = context.Allocate(Graphics.FromHwnd(this.Handle), this.ClientRectangle);
|
||||
buffer = context.Allocate(this.CreateGraphics(), this.ClientRectangle);
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
coordinate = String.Empty;
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var g = buffer.Graphics;
|
||||
var renderer = this.Renderer as LayerRenderer;
|
||||
|
||||
g.Clear(renderer.Context.ColorManager.Background);
|
||||
|
||||
if (!initialized || renderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
renderer.RenderTarget = g;
|
||||
renderer.Render();
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
#region Protected overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaint(e);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Render();
|
||||
|
||||
if (!String.IsNullOrEmpty(coordinate) && Renderer.Context.HasData)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
g.DrawString(coordinate, this.Font, Brushes.White, 10, 10);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
// Do nothing
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaintBackground(pevent);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
public interface IRenderContext
|
||||
{
|
||||
ColorManager ColorManager { get; }
|
||||
|
||||
BoundingBox Bounds { get; }
|
||||
|
||||
IList<IRenderLayer> RenderLayers { get; }
|
||||
|
||||
Projection Zoom { get; }
|
||||
|
||||
IMesh Mesh { get; }
|
||||
|
||||
bool HasData { get; }
|
||||
|
||||
void Add(IPolygon data);
|
||||
void Add(IMesh data, bool reset);
|
||||
void Add(IVoronoi voronoi, bool reset);
|
||||
|
||||
void Add(float[] values);
|
||||
void Add(int[] partition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="IMeshRenderer.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </summary>
|
||||
public interface IRenderControl
|
||||
{
|
||||
IRenderer Renderer { get; set; }
|
||||
Rectangle ClientRectangle { get; }
|
||||
|
||||
void Initialize();
|
||||
void Refresh();
|
||||
|
||||
void HandleMouseClick(float x, float y, MouseButtons button);
|
||||
void HandleMouseWheel(float x, float y, int delta);
|
||||
void HandleResize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
using TriangleNet.Rendering.Util;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
public interface IRenderLayer
|
||||
{
|
||||
int Count { get; }
|
||||
|
||||
// Points can be set, because layers may share vertices.
|
||||
IBuffer<float> Points { get; }
|
||||
IBuffer<int> Indices { get; }
|
||||
|
||||
bool IsActive { get; set; }
|
||||
bool IsEmpty { get; }
|
||||
|
||||
void Reset(bool clear);
|
||||
|
||||
// TODO: add boolean: reset
|
||||
BoundingBox SetPoints(IBuffer<float> buffer);
|
||||
BoundingBox SetPoints(IPolygon poly);
|
||||
BoundingBox SetPoints(IMesh mesh);
|
||||
BoundingBox SetPoints(IVoronoi voronoi);
|
||||
void SetPolygon(IPolygon poly);
|
||||
void SetPolygon(IMesh mesh);
|
||||
void SetMesh(IMesh mesh, bool elements);
|
||||
void SetMesh(IVoronoi voronoi);
|
||||
|
||||
|
||||
// TODO: better put these into a subclass.
|
||||
IBuffer<int> Partition { get; }
|
||||
IBuffer<Color> Colors { get; }
|
||||
|
||||
void AttachLayerData(float[] values, ColorMap colormap);
|
||||
void AttachLayerData(int[] partition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
public interface IRenderer
|
||||
{
|
||||
IRenderContext Context { get; set; }
|
||||
|
||||
void Render();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Projection.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Manages a world to screen transformation (2D orthographic projection).
|
||||
/// </summary>
|
||||
public class Projection
|
||||
{
|
||||
// The screen.
|
||||
Rectangle screen;
|
||||
|
||||
// The complete mesh.
|
||||
RectangleF world;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current viewport (visible mesh).
|
||||
/// </summary>
|
||||
public RectangleF Viewport { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current scale.
|
||||
/// </summary>
|
||||
public float Scale
|
||||
{
|
||||
get { return screen.Width / Viewport.Width; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the zoom level.
|
||||
/// </summary>
|
||||
public int Level { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a clip margin (default is 5% of viewport width on each side).
|
||||
/// </summary>
|
||||
public float ClipMargin { get; set; }
|
||||
|
||||
// The y-direction of windows screen coordinates is upside down,
|
||||
// so inverY must be set to true.
|
||||
bool invertY = false;
|
||||
|
||||
int maxZoomLevel = 50;
|
||||
|
||||
public Projection(Rectangle screen, bool invertY = true)
|
||||
{
|
||||
this.screen = screen;
|
||||
this.world = screen;
|
||||
this.Viewport = screen;
|
||||
|
||||
this.Level = 1;
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
this.invertY = invertY;
|
||||
}
|
||||
|
||||
public void Initialize(BoundingBox world)
|
||||
{
|
||||
Initialize(this.screen, world);
|
||||
}
|
||||
|
||||
public void Initialize(Rectangle screen, BoundingBox world)
|
||||
{
|
||||
this.screen = screen;
|
||||
|
||||
this.Level = 1;
|
||||
|
||||
// Add a margin so there's some space around the border
|
||||
float worldMargin = (world.Width < world.Height) ? world.Height * 0.05f : world.Width * 0.05f;
|
||||
|
||||
// Get the initial viewport (complete mesh centered on the screen)
|
||||
float screenRatio = screen.Width / (float)screen.Height;
|
||||
float worldRatio = world.Width / world.Height;
|
||||
|
||||
float scale = (world.Width + worldMargin) / screen.Width;
|
||||
|
||||
if (screenRatio > worldRatio)
|
||||
{
|
||||
scale = (world.Height + worldMargin) / screen.Height;
|
||||
}
|
||||
|
||||
float centerX = world.Left + world.Width / 2;
|
||||
float centerY = world.Bottom + world.Height / 2;
|
||||
|
||||
// TODO: Add initial margin
|
||||
this.Viewport = new RectangleF(centerX - screen.Width * scale / 2,
|
||||
centerY - screen.Height * scale / 2,
|
||||
screen.Width * scale,
|
||||
screen.Height * scale);
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
this.world = this.Viewport;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zoom in or out of the viewport.
|
||||
/// </summary>
|
||||
/// <param name="amount">Zoom amount</param>
|
||||
/// <param name="focusX">Relative x point position</param>
|
||||
/// <param name="focusY">Relative y point position</param>
|
||||
public bool Zoom(int amount, float focusX, float focusY)
|
||||
{
|
||||
float width, height;
|
||||
|
||||
if (invertY)
|
||||
{
|
||||
focusY = 1 - focusY;
|
||||
}
|
||||
|
||||
if (amount > 0) // Zoom in
|
||||
{
|
||||
this.Level++;
|
||||
|
||||
if (this.Level > maxZoomLevel)
|
||||
{
|
||||
this.Level = maxZoomLevel;
|
||||
return false;
|
||||
}
|
||||
|
||||
width = Viewport.Width / 1.1f;
|
||||
height = Viewport.Height / 1.1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Level--;
|
||||
|
||||
if (this.Level < 1)
|
||||
{
|
||||
this.Level = 1;
|
||||
this.Viewport = this.world;
|
||||
return false;
|
||||
}
|
||||
|
||||
width = Viewport.Width * 1.1f;
|
||||
height = Viewport.Height * 1.1f;
|
||||
}
|
||||
|
||||
// Current focus on viewport
|
||||
float x = Viewport.X + Viewport.Width * focusX;
|
||||
float y = Viewport.Y + Viewport.Height * focusY;
|
||||
|
||||
// New left and top positions
|
||||
x = x - width * focusX;
|
||||
y = y - height * focusY;
|
||||
|
||||
// Check if outside of world
|
||||
if (x < world.X)
|
||||
{
|
||||
x = world.X;
|
||||
}
|
||||
else if (x + width > world.Right)
|
||||
{
|
||||
x = world.Right - width;
|
||||
}
|
||||
|
||||
if (y < world.Y)
|
||||
{
|
||||
y = world.Y;
|
||||
}
|
||||
else if (y + height > world.Bottom)
|
||||
{
|
||||
y = world.Bottom - height;
|
||||
}
|
||||
|
||||
// Set new viewport
|
||||
this.Viewport = new RectangleF(x, y, width, height);
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.Viewport = this.world;
|
||||
this.Level = 1;
|
||||
}
|
||||
|
||||
public void WorldToScreen(ref PointF pt)
|
||||
{
|
||||
pt.X = (pt.X - Viewport.X) / Viewport.Width * screen.Width;
|
||||
pt.Y = (1 - (pt.Y - Viewport.Y) / Viewport.Height) * screen.Height;
|
||||
}
|
||||
|
||||
public void ScreenToWorld(ref PointF pt)
|
||||
{
|
||||
pt.X = Viewport.X + Viewport.Width * pt.X;
|
||||
pt.Y = Viewport.Y + Viewport.Height * (1 - pt.Y);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public PointF WorldToScreen(float x, float y)
|
||||
{
|
||||
return new PointF((x - Viewport.X) / Viewport.Width * screen.Width,
|
||||
(1 - (y - Viewport.Y) / Viewport.Height) * screen.Height);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public PointF ScreenToWorld(float x, float y)
|
||||
{
|
||||
return new PointF(Viewport.X + Viewport.Width * x,
|
||||
Viewport.Y + Viewport.Height * (1 - y));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Triangle.Rendering")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Triangle.Rendering")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("14f2491b-ee62-41e4-ab93-206540302ece")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// The RenderContext class brings all the rendering parts together.
|
||||
/// </summary>
|
||||
public class RenderContext : IRenderContext
|
||||
{
|
||||
private ColorManager colorManager;
|
||||
private BoundingBox bounds;
|
||||
private Projection zoom;
|
||||
private IMesh mesh;
|
||||
|
||||
private List<IRenderLayer> renderLayers;
|
||||
|
||||
public RenderContext(Projection zoom, ColorManager colorManager)
|
||||
{
|
||||
bounds = new BoundingBox();
|
||||
|
||||
renderLayers = new List<IRenderLayer>(6);
|
||||
|
||||
renderLayers.Add(new RenderLayer()); // 0 = mesh (filled)
|
||||
renderLayers.Add(new RenderLayer()); // 1 = mesh (wireframe)
|
||||
renderLayers.Add(new RenderLayer()); // 2 = polygon
|
||||
renderLayers.Add(new RenderLayer()); // 3 = points
|
||||
renderLayers.Add(new RenderLayer()); // 4 = voronoi overlay
|
||||
renderLayers.Add(new RenderLayer()); // 5 = vector field
|
||||
renderLayers.Add(new RenderLayer()); // 6 = contour lines
|
||||
|
||||
this.zoom = zoom;
|
||||
this.colorManager = colorManager;
|
||||
}
|
||||
|
||||
public ColorManager ColorManager
|
||||
{
|
||||
get { return colorManager; }
|
||||
}
|
||||
|
||||
public BoundingBox Bounds
|
||||
{
|
||||
get { return bounds; }
|
||||
}
|
||||
|
||||
public IList<IRenderLayer> RenderLayers
|
||||
{
|
||||
get { return renderLayers; }
|
||||
}
|
||||
|
||||
public Projection Zoom
|
||||
{
|
||||
get { return zoom; }
|
||||
}
|
||||
|
||||
public IMesh Mesh
|
||||
{
|
||||
get { return mesh; }
|
||||
}
|
||||
|
||||
public bool HasData
|
||||
{
|
||||
get
|
||||
{
|
||||
return renderLayers.Any(layer => !layer.IsEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(IPolygon data)
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(true);
|
||||
}
|
||||
|
||||
this.bounds = RenderLayers[2].SetPoints(data);
|
||||
this.zoom.Initialize(bounds);
|
||||
|
||||
RenderLayers[2].SetPolygon(data);
|
||||
RenderLayers[2].IsActive = true;
|
||||
|
||||
RenderLayers[3].SetPoints(RenderLayers[2].Points);
|
||||
RenderLayers[3].IsActive = true;
|
||||
}
|
||||
|
||||
public void Add(IMesh data, bool reset)
|
||||
{
|
||||
foreach (var layer in RenderLayers)
|
||||
{
|
||||
layer.Reset(reset);
|
||||
}
|
||||
|
||||
// Save reference to mesh.
|
||||
this.mesh = data;
|
||||
|
||||
this.bounds = RenderLayers[1].SetPoints(data);
|
||||
this.zoom.Initialize(bounds);
|
||||
|
||||
RenderLayers[1].SetMesh(data, false);
|
||||
RenderLayers[1].IsActive = true;
|
||||
|
||||
RenderLayers[2].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[2].SetPolygon(data);
|
||||
RenderLayers[2].IsActive = true;
|
||||
|
||||
RenderLayers[3].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[3].IsActive = true;
|
||||
}
|
||||
|
||||
// Voronoi
|
||||
public void Add(IVoronoi voronoi, bool reset)
|
||||
{
|
||||
RenderLayers[4].SetPoints(voronoi);
|
||||
RenderLayers[4].SetMesh(voronoi);
|
||||
RenderLayers[4].IsActive = true;
|
||||
}
|
||||
|
||||
public void Add(float[] data)
|
||||
{
|
||||
// Add function values for filled mesh.
|
||||
RenderLayers[0].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[0].SetMesh(this.mesh, true);
|
||||
RenderLayers[0].AttachLayerData(data, colorManager.ColorMap);
|
||||
|
||||
RenderLayers[0].IsActive = true;
|
||||
}
|
||||
|
||||
public void Add(int[] data)
|
||||
{
|
||||
// Add partition data for filled mesh.
|
||||
RenderLayers[0].SetPoints(RenderLayers[1].Points);
|
||||
RenderLayers[0].SetMesh(this.mesh, true);
|
||||
RenderLayers[0].AttachLayerData(data);
|
||||
|
||||
RenderLayers[0].IsActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Drawing;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
using TriangleNet.Rendering.Util;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
public class RenderLayer : IRenderLayer
|
||||
{
|
||||
int count;
|
||||
|
||||
protected IBuffer<float> points;
|
||||
protected IBuffer<int> indices;
|
||||
|
||||
protected IBuffer<int> partition;
|
||||
protected IBuffer<Color> colors;
|
||||
|
||||
public RenderLayer()
|
||||
{
|
||||
this.IsActive = false;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return count; }
|
||||
}
|
||||
|
||||
public IBuffer<float> Points
|
||||
{
|
||||
get { return points; }
|
||||
set { points = value; }
|
||||
}
|
||||
|
||||
public IBuffer<int> Indices
|
||||
{
|
||||
get { return indices; }
|
||||
}
|
||||
|
||||
public IBuffer<int> Partition
|
||||
{
|
||||
get { return partition; }
|
||||
}
|
||||
|
||||
public IBuffer<Color> Colors
|
||||
{
|
||||
get { return colors; }
|
||||
}
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return (points == null || points.Count == 0); }
|
||||
}
|
||||
|
||||
public void Reset(bool clear)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
count = 0;
|
||||
points = null;
|
||||
}
|
||||
|
||||
indices = null;
|
||||
partition = null;
|
||||
colors = null;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IBuffer<float> buffer)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
if (points != null && points.Count < buffer.Count)
|
||||
{
|
||||
count = points.Count / points.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = buffer.Count / buffer.Size;
|
||||
}
|
||||
|
||||
this.points = buffer;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IPolygon poly)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
points = BufferHelper.CreateVertexBuffer(poly.Points, ref bounds);
|
||||
count = points.Count / points.Size;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IMesh mesh)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
points = BufferHelper.CreateVertexBuffer(mesh.Vertices, ref bounds);
|
||||
count = points.Count / points.Size;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BoundingBox SetPoints(IVoronoi voronoi)
|
||||
{
|
||||
BoundingBox bounds = new BoundingBox();
|
||||
|
||||
points = BufferHelper.CreateVertexBuffer(voronoi.Points, ref bounds);
|
||||
count = points.Count / points.Size;
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public void SetPolygon(IPolygon poly)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(poly.Segments, 2);
|
||||
}
|
||||
|
||||
public void SetPolygon(IMesh mesh)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(mesh.Segments, 2);
|
||||
}
|
||||
|
||||
public void SetMesh(IVoronoi voronoi)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(voronoi.Edges, 2);
|
||||
}
|
||||
|
||||
public void SetMesh(IMesh mesh, bool elements)
|
||||
{
|
||||
mesh.Renumber();
|
||||
|
||||
if (!elements)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(mesh.Edges, 2);
|
||||
}
|
||||
|
||||
if (elements || indices.Count == 0)
|
||||
{
|
||||
indices = BufferHelper.CreateIndexBuffer(mesh.Triangles, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove colormap argument
|
||||
public void AttachLayerData(float[] values, ColorMap colormap)
|
||||
{
|
||||
int length = values.Length;
|
||||
|
||||
Color[] data = new Color[length];
|
||||
|
||||
double min = double.MaxValue;
|
||||
double max = double.MinValue;
|
||||
|
||||
// Find min and max of given values.
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (values[i] < min)
|
||||
{
|
||||
min = values[i];
|
||||
}
|
||||
|
||||
if (values[i] > max)
|
||||
{
|
||||
max = values[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
data[i] = colormap.GetColor(values[i], min, max);
|
||||
}
|
||||
|
||||
colors = new ColorBuffer(data, 1);
|
||||
}
|
||||
|
||||
public void AttachLayerData(int[] partition)
|
||||
{
|
||||
this.partition = new IndexBuffer(partition, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
|
||||
namespace TriangleNet.Rendering
|
||||
{
|
||||
using System.Windows.Forms;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Meshing;
|
||||
using TriangleNet.Rendering.GDI;
|
||||
using TriangleNet.Tools;
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Rendering.Util;
|
||||
|
||||
public class RenderManager
|
||||
{
|
||||
IRenderControl control;
|
||||
IRenderContext context;
|
||||
IRenderer renderer;
|
||||
Projection zoom;
|
||||
|
||||
public IRenderControl Control
|
||||
{
|
||||
get { return control; }
|
||||
}
|
||||
|
||||
public IRenderContext Context
|
||||
{
|
||||
get { return context; }
|
||||
}
|
||||
|
||||
public RenderManager()
|
||||
{
|
||||
}
|
||||
|
||||
public RenderManager(IRenderControl control)
|
||||
{
|
||||
Initialize(control);
|
||||
}
|
||||
|
||||
public RenderManager(IRenderControl control, IRenderer renderer)
|
||||
{
|
||||
Initialize(control, renderer);
|
||||
}
|
||||
|
||||
public void Initialize(IRenderControl control)
|
||||
{
|
||||
Initialize(control, new LayerRenderer());
|
||||
}
|
||||
|
||||
public void Initialize(IRenderControl control, IRenderer renderer)
|
||||
{
|
||||
this.zoom = new Projection(control.ClientRectangle);
|
||||
|
||||
this.context = new RenderContext(zoom, ColorManager.Default());
|
||||
|
||||
this.renderer = renderer;
|
||||
this.renderer.Context = context;
|
||||
|
||||
this.control = control;
|
||||
this.control.Initialize();
|
||||
this.control.Renderer = renderer;
|
||||
}
|
||||
|
||||
public bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
out IRenderControl control)
|
||||
{
|
||||
if (!ReflectionHelper.TryCreateControl(assemblyName, dependencies, out control))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return control is Control;
|
||||
}
|
||||
|
||||
public void Resize()
|
||||
{
|
||||
control.HandleResize();
|
||||
}
|
||||
|
||||
public void Click(float x, float y, MouseButtons button)
|
||||
{
|
||||
control.HandleMouseClick(x, y, button);
|
||||
}
|
||||
|
||||
public void Zoom(float x, float y, int delta)
|
||||
{
|
||||
control.HandleMouseWheel(x, y, delta);
|
||||
}
|
||||
|
||||
public void Set(IPolygon data, bool refresh = true)
|
||||
{
|
||||
context.Add(data);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(IMesh data, bool reset, bool refresh = true)
|
||||
{
|
||||
context.Add(data, reset);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// Voronoi
|
||||
public void Set(IVoronoi voronoi, bool reset, bool refresh = true)
|
||||
{
|
||||
context.Add(voronoi, reset);
|
||||
|
||||
if (refresh)
|
||||
{
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float[] values)
|
||||
{
|
||||
context.Add(values);
|
||||
control.Refresh();
|
||||
}
|
||||
|
||||
public void Update(int[] partition)
|
||||
{
|
||||
context.Add(partition);
|
||||
control.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{41022E0E-BD0F-439E-BC3A-AABB1B43471B}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>TriangleNet.Rendering</RootNamespace>
|
||||
<AssemblyName>Triangle.Rendering</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<SccProjectName>SAK</SccProjectName>
|
||||
<SccLocalPath>SAK</SccLocalPath>
|
||||
<SccAuxPath>SAK</SccAuxPath>
|
||||
<SccProvider>SAK</SccProvider>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BoundingBox.cs" />
|
||||
<Compile Include="Buffer\BufferBase.cs" />
|
||||
<Compile Include="Buffer\ColorBuffer.cs" />
|
||||
<Compile Include="Buffer\IBuffer.cs" />
|
||||
<Compile Include="Buffer\IndexBuffer.cs" />
|
||||
<Compile Include="Buffer\VertexBuffer.cs" />
|
||||
<Compile Include="ColorManager.cs" />
|
||||
<Compile Include="ExtensionMethods.cs" />
|
||||
<Compile Include="GDI\FunctionRenderer.cs" />
|
||||
<Compile Include="GDI\LayerRenderer.cs" />
|
||||
<Compile Include="GDI\MeshRenderer.cs" />
|
||||
<Compile Include="GDI\Native\GradientFillMode.cs" />
|
||||
<Compile Include="GDI\Native\GradientRect.cs" />
|
||||
<Compile Include="GDI\Native\GradientTriangle.cs" />
|
||||
<Compile Include="GDI\Native\NativeMethods.cs" />
|
||||
<Compile Include="GDI\Native\TriVertex.cs" />
|
||||
<Compile Include="GDI\RenderControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="IRenderContext.cs" />
|
||||
<Compile Include="IRenderControl.cs" />
|
||||
<Compile Include="IRenderer.cs" />
|
||||
<Compile Include="IRenderLayer.cs" />
|
||||
<Compile Include="Projection.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="RenderContext.cs" />
|
||||
<Compile Include="RenderLayer.cs" />
|
||||
<Compile Include="RenderManager.cs" />
|
||||
<Compile Include="Util\BufferHelper.cs" />
|
||||
<Compile Include="Util\ColorMap.cs" />
|
||||
<Compile Include="Util\ReflectionHelper.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Triangle\Triangle.csproj">
|
||||
<Project>{f7907a0a-b75f-400b-9e78-bfad00db4d6b}</Project>
|
||||
<Name>Triangle</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -0,0 +1,10 @@
|
||||
""
|
||||
{
|
||||
"FILE_VERSION" = "9237"
|
||||
"ENLISTMENT_CHOICE" = "NEVER"
|
||||
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Rendering.Buffer;
|
||||
|
||||
internal static class BufferHelper
|
||||
{
|
||||
public static IBuffer<float> CreateVertexBuffer(double[] points, ref BoundingBox bounds)
|
||||
{
|
||||
int length = points.Length;
|
||||
|
||||
var buffer = new VertexBuffer(length);
|
||||
|
||||
bounds.Reset();
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
float x, y;
|
||||
|
||||
length = length >> 1;
|
||||
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
x = (float)points[2 * i];
|
||||
y = (float)points[2 * i + 1];
|
||||
|
||||
data[2 * i] = x;
|
||||
data[2 * i + 1] = y;
|
||||
|
||||
bounds.Update(x, y);
|
||||
}
|
||||
|
||||
return buffer as IBuffer<float>;
|
||||
}
|
||||
|
||||
public static IBuffer<float> CreateVertexBuffer(Point[] points, ref BoundingBox bounds)
|
||||
{
|
||||
var buffer = new VertexBuffer(2 * points.Length);
|
||||
|
||||
bounds.Reset();
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
float x, y;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
x = (float)p.X;
|
||||
y = (float)p.Y;
|
||||
|
||||
data[2 * i] = x;
|
||||
data[2 * i + 1] = y;
|
||||
|
||||
bounds.Update(x, y);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<float>;
|
||||
}
|
||||
|
||||
public static IBuffer<float> CreateVertexBuffer(ICollection<Vertex> points, ref BoundingBox bounds)
|
||||
{
|
||||
var buffer = new VertexBuffer(2 * points.Count);
|
||||
|
||||
bounds.Reset();
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
data[2 * i] = (float)p.X;
|
||||
data[2 * i + 1] = (float)p.Y;
|
||||
|
||||
bounds.Update(p.X, p.Y);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<float>;
|
||||
}
|
||||
|
||||
public static IBuffer<int> CreateIndexBuffer(IList<IEdge> segments, int size)
|
||||
{
|
||||
var buffer = new IndexBuffer(size * segments.Count, size);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var e in segments)
|
||||
{
|
||||
data[size * i + 0] = e.P0;
|
||||
data[size * i + 1] = e.P1;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<int>;
|
||||
}
|
||||
|
||||
public static IBuffer<int> CreateIndexBuffer(IEnumerable<IEdge> edges, int size)
|
||||
{
|
||||
var data = new List<int>();
|
||||
|
||||
foreach (var e in edges)
|
||||
{
|
||||
data.Add(e.P0);
|
||||
data.Add(e.P1);
|
||||
}
|
||||
|
||||
return new IndexBuffer(data.ToArray(), size) as IBuffer<int>;
|
||||
}
|
||||
|
||||
public static IBuffer<int> CreateIndexBuffer(ICollection<Triangle> elements, int size)
|
||||
{
|
||||
var buffer = new IndexBuffer(size * elements.Count, size);
|
||||
|
||||
var data = buffer.Data;
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (var e in elements)
|
||||
{
|
||||
data[size * i + 0] = e.P0;
|
||||
data[size * i + 1] = e.P1;
|
||||
data[size * i + 2] = e.P2;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return buffer as IBuffer<int>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
public class ColorMap
|
||||
{
|
||||
#region Colormap definitions
|
||||
|
||||
public static ColorMap Jet(int size)
|
||||
{
|
||||
ColorMap map = new ColorMap(size);
|
||||
float v, step = 1.0f / (size - 1);
|
||||
float[] rgb = new float[3];
|
||||
|
||||
for (int i = 0; i < size; i += 1)
|
||||
{
|
||||
v = 4 * i * step;
|
||||
|
||||
rgb[0] = Math.Min(v - 1.5f, 4.5f - v);
|
||||
rgb[1] = Math.Min(v - 0.5f, 3.5f - v);
|
||||
rgb[2] = Math.Min(v + 0.5f, 2.5f - v);
|
||||
|
||||
Clamp(rgb, 0.0f, 1.0f);
|
||||
|
||||
map.colors[size - i - 1] = ColorFromRgb(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public static ColorMap Hot(int size)
|
||||
{
|
||||
ColorMap map = new ColorMap(size);
|
||||
float v, step = 1.0f / (size - 1);
|
||||
float[] rgb = new float[3];
|
||||
|
||||
for (int i = 0; i < size; i += 1)
|
||||
{
|
||||
v = 2.5f * i * step;
|
||||
|
||||
rgb[0] = v;
|
||||
rgb[1] = v - 1;
|
||||
rgb[2] = 2 * v - 4;
|
||||
|
||||
Clamp(rgb, 0.0f, 1.0f);
|
||||
|
||||
map.colors[i] = ColorFromRgb(rgb[0], rgb[1], rgb[2]);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helper
|
||||
|
||||
private static Color ColorFromRgb(float r, float g, float b)
|
||||
{
|
||||
byte max = byte.MaxValue;
|
||||
|
||||
return Color.FromArgb((byte)(r * max), (byte)(g * max), (byte)(b * max));
|
||||
}
|
||||
|
||||
private static void Clamp(float[] values, float min, float max)
|
||||
{
|
||||
int n = values.Length;
|
||||
|
||||
for (int i = 0; i < n; i += 1)
|
||||
{
|
||||
values[i] = Math.Min(max, Math.Max(min, values[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private static int Clamp(int index, int max)
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
else if (index > max)
|
||||
{
|
||||
index = max;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Color[] colors;
|
||||
|
||||
private ColorMap(int size)
|
||||
{
|
||||
this.colors = new Color[size];
|
||||
}
|
||||
|
||||
public ColorMap(Color[] colors)
|
||||
{
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
public Color GetColor(double value, double min, double max)
|
||||
{
|
||||
int n = this.colors.Length;
|
||||
int i = (int)Math.Floor(n * (max - value) / (max - min));
|
||||
|
||||
return this.colors[Clamp(i, n - 1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
|
||||
namespace TriangleNet.Rendering.Util
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
internal static class ReflectionHelper
|
||||
{
|
||||
public static bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
out IRenderControl control)
|
||||
{
|
||||
return TryCreateControl(assemblyName, dependencies, null, out control);
|
||||
}
|
||||
|
||||
public static bool TryCreateControl(string assemblyName, IEnumerable<string> dependencies,
|
||||
string className, out IRenderControl control)
|
||||
{
|
||||
control = null;
|
||||
|
||||
if (!FilesExist(assemblyName, dependencies))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
|
||||
|
||||
// Try create render control instance.
|
||||
try
|
||||
{
|
||||
// Load the assembly into the current application domain.
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
|
||||
// Get all types implementing the IRenderControl interface.
|
||||
var type = typeof(IRenderControl);
|
||||
var matches = assembly.GetTypes().Where(s => type.IsAssignableFrom(s));
|
||||
|
||||
var match = string.IsNullOrEmpty(className) ? matches.FirstOrDefault()
|
||||
: matches.Where(s => s.Name == className).FirstOrDefault();
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
// Create an instance.
|
||||
control = (IRenderControl)Activator.CreateInstance(match);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if render control was successfully created.
|
||||
return (control != null);
|
||||
}
|
||||
|
||||
private static bool FilesExist(string assemblyName, IEnumerable<string> dependencies)
|
||||
{
|
||||
// Check if assembly exists
|
||||
if (!File.Exists(assemblyName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if dependencies exists
|
||||
if (dependencies != null)
|
||||
{
|
||||
foreach (var item in dependencies)
|
||||
{
|
||||
if (!File.Exists(item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle", "Triangle\Triangle.csproj", "{F7907A0A-B75F-400B-9E78-BFAD00DB4D6B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mesh Explorer", "TestApp\Mesh Explorer.csproj", "{336AAF8A-5316-4303-9E73-5E38BD0B28AF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeshRenderer.Core", "MeshRenderer.Core\MeshRenderer.Core.csproj", "{9C5040DA-C739-43A1-8540-E6BD3ED6DB55}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle.Rendering", "Triangle.Rendering\Triangle.Rendering.csproj", "{41022E0E-BD0F-439E-BC3A-AABB1B43471B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||
SccNumberOfProjects = 4
|
||||
SccNumberOfProjects = 5
|
||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||
SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs06
|
||||
SccLocalPath0 = .
|
||||
@@ -22,6 +24,9 @@ Global
|
||||
SccProjectUniqueName3 = MeshRenderer.Core\\MeshRenderer.Core.csproj
|
||||
SccProjectName3 = MeshRenderer.Core
|
||||
SccLocalPath3 = MeshRenderer.Core
|
||||
SccProjectUniqueName4 = Triangle.Rendering\\Triangle.Rendering.csproj
|
||||
SccProjectName4 = Triangle.Rendering
|
||||
SccLocalPath4 = Triangle.Rendering
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -62,6 +67,16 @@ Global
|
||||
{9C5040DA-C739-43A1-8540-E6BD3ED6DB55}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{9C5040DA-C739-43A1-8540-E6BD3ED6DB55}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{9C5040DA-C739-43A1-8540-E6BD3ED6DB55}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{41022E0E-BD0F-439E-BC3A-AABB1B43471B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="BoundingBox.cs" company="">
|
||||
// <copyright file="Rectangle.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -150,7 +150,7 @@ namespace TriangleNet.Geometry
|
||||
/// <returns>Return true, if bounding box contains given point.</returns>
|
||||
public bool Contains(Point pt)
|
||||
{
|
||||
return ((pt.x >= xmin) && (pt.x <= xmax) && (pt.y >= ymin) && (pt.y <= ymax));
|
||||
return ((pt.X >= xmin) && (pt.X <= xmax) && (pt.Y >= ymin) && (pt.Y <= ymax));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="SimpleLog.cs" company="">
|
||||
// <copyright file="Log.cs" company="">
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace TriangleNet.Meshing.Algorithm
|
||||
if (Log.Verbose)
|
||||
{
|
||||
Log.Instance.Warning("A duplicate vertex appeared and was ignored.",
|
||||
"Incremental.IncrementalDelaunay()");
|
||||
"Incremental.Triangulate()");
|
||||
}
|
||||
v.type = VertexType.UndeadVertex;
|
||||
mesh.undeads++;
|
||||
|
||||
@@ -78,6 +78,19 @@ namespace TriangleNet.Meshing
|
||||
return mesh;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a structured mesh with bounds (0, 0, width, height).
|
||||
/// </summary>
|
||||
/// <param name="width">Width of the mesh (must be > 0).</param>
|
||||
/// <param name="height">Height of the mesh (must be > 0).</param>
|
||||
/// <param name="nx">Number of segments in x direction.</param>
|
||||
/// <param name="ny">Number of segments in y direction.</param>
|
||||
/// <returns>Mesh</returns>
|
||||
public IMesh StructurdMesh(double width, double height, int nx, int ny)
|
||||
{
|
||||
return StructurdMesh(new Rectangle(0.0, 0.0, width, height), nx, ny);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a structured mesh.
|
||||
/// </summary>
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace TriangleNet.Meshing
|
||||
|
||||
Rectangle Bounds { get; }
|
||||
|
||||
void Renumber();
|
||||
void Refine(QualityOptions quality);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Primitives.cs">
|
||||
// <copyright file="RobustPredicates.cs">
|
||||
// Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
|
||||
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
|
||||
@@ -70,6 +70,11 @@ namespace TriangleNet.Tools
|
||||
get { return regions; }
|
||||
}
|
||||
|
||||
public IEnumerable<IEdge> Edges
|
||||
{
|
||||
get { return EnumerateEdges(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the bounded voronoi diagram.
|
||||
/// </summary>
|
||||
@@ -644,5 +649,41 @@ namespace TriangleNet.Tools
|
||||
// Success.
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Voronoi enumerate edges
|
||||
|
||||
private IEnumerable<IEdge> EnumerateEdges()
|
||||
{
|
||||
// Copy edges
|
||||
Point first, last;
|
||||
var edges = new List<IEdge>(this.Regions.Count * 2);
|
||||
foreach (var region in this.Regions)
|
||||
{
|
||||
first = null;
|
||||
last = null;
|
||||
|
||||
foreach (var pt in region.Vertices)
|
||||
{
|
||||
if (first == null)
|
||||
{
|
||||
first = pt;
|
||||
last = pt;
|
||||
}
|
||||
else
|
||||
{
|
||||
edges.Add(new Edge(last.ID, pt.ID));
|
||||
|
||||
last = pt;
|
||||
}
|
||||
}
|
||||
|
||||
if (region.Bounded && first != null)
|
||||
{
|
||||
edges.Add(new Edge(last.ID, first.ID));
|
||||
}
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,5 +23,10 @@ namespace TriangleNet.Tools
|
||||
/// Gets the list of Voronoi regions.
|
||||
/// </summary>
|
||||
ICollection<VoronoiRegion> Regions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of edges.
|
||||
/// </summary>
|
||||
IEnumerable<IEdge> Edges { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,11 @@ namespace TriangleNet.Tools
|
||||
get { return regions.Values; }
|
||||
}
|
||||
|
||||
public IEnumerable<IEdge> Edges
|
||||
{
|
||||
get { return EnumerateEdges(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Voronoi diagram as raw output data.
|
||||
/// </summary>
|
||||
@@ -336,5 +341,41 @@ namespace TriangleNet.Tools
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Voronoi enumerate edges
|
||||
|
||||
private IEnumerable<IEdge> EnumerateEdges()
|
||||
{
|
||||
// Copy edges
|
||||
Point first, last;
|
||||
var edges = new List<IEdge>(this.Regions.Count * 2);
|
||||
foreach (var region in this.Regions)
|
||||
{
|
||||
first = null;
|
||||
last = null;
|
||||
|
||||
foreach (var pt in region.Vertices)
|
||||
{
|
||||
if (first == null)
|
||||
{
|
||||
first = pt;
|
||||
last = pt;
|
||||
}
|
||||
else
|
||||
{
|
||||
edges.Add(new Edge(last.ID, pt.ID));
|
||||
|
||||
last = pt;
|
||||
}
|
||||
}
|
||||
|
||||
if (region.Bounded && first != null)
|
||||
{
|
||||
edges.Add(new Edge(last.ID, first.ID));
|
||||
}
|
||||
}
|
||||
|
||||
return edges;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,9 +108,7 @@
|
||||
<Compile Include="Tools\VoronoiRegion.cs" />
|
||||
<Compile Include="TriangleLocator.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Algorithm\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
Reference in New Issue
Block a user