Moved mesh rendering code to a seperate assembly. This will allow other rendering implementations (like OpenGL) through IMeshRenderer interface.
git-svn-id: https://triangle.svn.codeplex.com/svn@69965 0e2699bc-83d4-4a8f-98e7-55e24ab8c7a5
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
public struct 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(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 bounding box
|
||||
if (this.Left > x) this.Left = (float)x;
|
||||
if (this.Right < x) this.Right = (float)x;
|
||||
if (this.Bottom > y) this.Bottom = (float)y;
|
||||
if (this.Top < y) this.Top = (float)y;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.Left = float.MaxValue;
|
||||
this.Right = -float.MaxValue;
|
||||
this.Bottom = float.MaxValue;
|
||||
this.Top = -float.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
public class ColorManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a color scheme with black background.
|
||||
/// </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.Triangle = new SolidBrush(Color.Black);
|
||||
colors.Line = new Pen(Color.FromArgb(30, 30, 30));
|
||||
colors.Segment = new Pen(Color.DarkBlue);
|
||||
colors.VoronoiLine = new Pen(Color.FromArgb(40, 50, 60));
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a color scheme with white background.
|
||||
/// </summary>
|
||||
public static 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.Triangle = new SolidBrush(Color.FromArgb(230, 240, 250));
|
||||
colors.Line = new Pen(Color.FromArgb(150, 150, 150));
|
||||
colors.Segment = new Pen(Color.SteelBlue);
|
||||
colors.VoronoiLine = new Pen(Color.FromArgb(160, 170, 180));
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
internal Color background;
|
||||
internal SolidBrush point;
|
||||
internal SolidBrush steinerPoint;
|
||||
internal SolidBrush triangle;
|
||||
internal Pen line;
|
||||
internal Pen segment;
|
||||
internal Pen voronoiLine;
|
||||
|
||||
#region Public properties
|
||||
|
||||
public Color Background
|
||||
{
|
||||
get { return background; }
|
||||
set { background = value; }
|
||||
}
|
||||
|
||||
public SolidBrush Point
|
||||
{
|
||||
get { return point; }
|
||||
set
|
||||
{
|
||||
if (point != null) point.Dispose();
|
||||
point = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SolidBrush SteinerPoint
|
||||
{
|
||||
get { return steinerPoint; }
|
||||
set
|
||||
{
|
||||
if (steinerPoint != null) steinerPoint.Dispose();
|
||||
steinerPoint = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SolidBrush Triangle
|
||||
{
|
||||
get { return triangle; }
|
||||
set
|
||||
{
|
||||
if (triangle != null) triangle.Dispose();
|
||||
triangle = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Pen Line
|
||||
{
|
||||
get { return line; }
|
||||
set
|
||||
{
|
||||
if (line != null) line.Dispose();
|
||||
line = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Pen Segment
|
||||
{
|
||||
get { return segment; }
|
||||
set
|
||||
{
|
||||
if (segment != null) segment.Dispose();
|
||||
segment = value;
|
||||
}
|
||||
}
|
||||
|
||||
public Pen VoronoiLine
|
||||
{
|
||||
get { return voronoiLine; }
|
||||
set
|
||||
{
|
||||
if (voronoiLine != null) voronoiLine.Dispose();
|
||||
voronoiLine = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="ExtensionMethods.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods.
|
||||
/// </summary>
|
||||
public static class ExtensionMethods
|
||||
{
|
||||
#region Color extention methods
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Color to a float array containing normalized R, G ,B, A values.
|
||||
/// </summary>
|
||||
public static float[] ToFloatArray4(this Color color)
|
||||
{
|
||||
return new float[] {
|
||||
((float)color.R) / 255.0f,
|
||||
((float)color.G) / 255.0f,
|
||||
((float)color.B) / 255.0f,
|
||||
((float)color.A) / 255.0f
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="MeshRenderer.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using TriangleNet;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh.
|
||||
/// </summary>
|
||||
public class MeshRenderer
|
||||
{
|
||||
Zoom zoom;
|
||||
RenderData data;
|
||||
ColorManager renderColors;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MeshRenderer" /> class.
|
||||
/// </summary>
|
||||
public MeshRenderer(RenderData data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the mesh.
|
||||
/// </summary>
|
||||
public void Render(Graphics g, Zoom zoom, ColorManager renderColors)
|
||||
{
|
||||
this.renderColors = renderColors;
|
||||
this.zoom = zoom;
|
||||
|
||||
if (data.MeshEdges != null)
|
||||
{
|
||||
this.RenderEdges(g);
|
||||
}
|
||||
else if (data.Triangles != null)
|
||||
{
|
||||
this.RenderTriangles(g);
|
||||
}
|
||||
|
||||
if (data.Segments != null)
|
||||
{
|
||||
this.RenderSegments(g);
|
||||
}
|
||||
|
||||
if (data.Points != null)
|
||||
{
|
||||
this.RenderPoints(g);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders only the mesh edges (no points or segments).
|
||||
/// </summary>
|
||||
public void RenderMesh(Graphics g, Zoom zoom, ColorManager renderColors)
|
||||
{
|
||||
this.renderColors = renderColors;
|
||||
this.zoom = zoom;
|
||||
|
||||
if (data.MeshEdges != null)
|
||||
{
|
||||
this.RenderEdges(g);
|
||||
}
|
||||
else if (data.Triangles != null)
|
||||
{
|
||||
this.RenderTriangles(g);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders only points and segments (no mesh triangles).
|
||||
/// </summary>
|
||||
public void RenderGeometry(Graphics g, Zoom zoom, ColorManager renderColors)
|
||||
{
|
||||
this.renderColors = renderColors;
|
||||
this.zoom = zoom;
|
||||
|
||||
if (data.Segments != null)
|
||||
{
|
||||
this.RenderSegments(g);
|
||||
}
|
||||
|
||||
if (data.Points != null)
|
||||
{
|
||||
this.RenderPoints(g);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderPoints(Graphics g)
|
||||
{
|
||||
int i, k, n;
|
||||
PointF pt;
|
||||
float[] pts = data.Points;
|
||||
|
||||
// Draw input points
|
||||
n = data.NumberOfInputPoints;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
k = 2 * i;
|
||||
if (zoom.ViewportContains(pts[k], pts[k + 1]))
|
||||
{
|
||||
pt = zoom.WorldToScreen(pts[k], pts[k + 1]);
|
||||
g.FillEllipse(renderColors.Point, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Steiner points
|
||||
n = pts.Length / 2;
|
||||
for (; i < n; i++)
|
||||
{
|
||||
k = 2 * i;
|
||||
if (zoom.ViewportContains(pts[k], pts[k + 1]))
|
||||
{
|
||||
pt = zoom.WorldToScreen(pts[k], pts[k + 1]);
|
||||
g.FillEllipse(renderColors.SteinerPoint, pt.X - 1.5f, pt.Y - 1.5f, 3, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderTriangles(Graphics g)
|
||||
{
|
||||
int n = data.Triangles.Length / 3;
|
||||
uint k0, k1, k2;
|
||||
PointF p0, p1, p2;
|
||||
float[] pts = data.Points;
|
||||
|
||||
// Draw triangles
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * data.Triangles[3 * i];
|
||||
k1 = 2 * data.Triangles[3 * i + 1];
|
||||
k2 = 2 * data.Triangles[3 * i + 2];
|
||||
|
||||
if (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
|
||||
zoom.ViewportContains(pts[k1], pts[k1 + 1]) ||
|
||||
zoom.ViewportContains(pts[k2], pts[k2 + 1]))
|
||||
{
|
||||
p0 = zoom.WorldToScreen(pts[k0], pts[k0 + 1]);
|
||||
p1 = zoom.WorldToScreen(pts[k1], pts[k1 + 1]);
|
||||
p2 = zoom.WorldToScreen(pts[k2], pts[k2 + 1]);
|
||||
|
||||
g.DrawLine(renderColors.Line, p0, p1);
|
||||
g.DrawLine(renderColors.Line, p1, p2);
|
||||
g.DrawLine(renderColors.Line, p2, p0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderEdges(Graphics g)
|
||||
{
|
||||
int n = data.MeshEdges.Length / 2;
|
||||
uint k0, k1;
|
||||
PointF p0, p1;
|
||||
float[] pts = data.Points;
|
||||
|
||||
// Draw edges
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * data.MeshEdges[2 * i];
|
||||
k1 = 2 * data.MeshEdges[2 * i + 1];
|
||||
|
||||
if (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
|
||||
zoom.ViewportContains(pts[k1], pts[k1 + 1]))
|
||||
{
|
||||
p0 = zoom.WorldToScreen(pts[k0], pts[k0 + 1]);
|
||||
p1 = zoom.WorldToScreen(pts[k1], pts[k1 + 1]);
|
||||
|
||||
g.DrawLine(renderColors.Line, p0, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderSegments(Graphics g)
|
||||
{
|
||||
int n = data.Segments.Length / 2;
|
||||
uint k0, k1;
|
||||
PointF p0, p1;
|
||||
float[] pts = data.Points;
|
||||
|
||||
// Draw edges
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
k0 = 2 * data.Segments[2 * i];
|
||||
k1 = 2 * data.Segments[2 * i + 1];
|
||||
|
||||
if (zoom.ViewportContains(pts[k0], pts[k0 + 1]) ||
|
||||
zoom.ViewportContains(pts[k1], pts[k1 + 1]))
|
||||
{
|
||||
p0 = zoom.WorldToScreen(pts[k0], pts[k0 + 1]);
|
||||
p1 = zoom.WorldToScreen(pts[k1], pts[k1 + 1]);
|
||||
|
||||
g.DrawLine(renderColors.Segment, p0, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="RendererControl.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.Windows.Forms;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Geometry;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a mesh using GDI.
|
||||
/// </summary>
|
||||
public class RenderControl : Control, IMeshRenderer
|
||||
{
|
||||
// Rendering stuff
|
||||
private BufferedGraphics buffer;
|
||||
private BufferedGraphicsContext context;
|
||||
|
||||
Zoom zoom;
|
||||
RenderData data;
|
||||
|
||||
MeshRenderer meshRenderer;
|
||||
VoronoiRenderer voronoiRenderer;
|
||||
|
||||
ColorManager renderColors;
|
||||
|
||||
bool initialized = false;
|
||||
bool showVoronoi = false;
|
||||
|
||||
string coordinate = String.Empty;
|
||||
|
||||
Timer timer;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently displayed <see cref="RenderData"/>.
|
||||
/// </summary>
|
||||
public RenderData Data
|
||||
{
|
||||
get { return data; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenderControl" /> class.
|
||||
/// </summary>
|
||||
public RenderControl()
|
||||
{
|
||||
SetStyle(ControlStyles.ResizeRedraw, true);
|
||||
|
||||
renderColors = ColorManager.Default();
|
||||
|
||||
this.BackColor = renderColors.Background;
|
||||
|
||||
zoom = new Zoom(true);
|
||||
context = new BufferedGraphicsContext();
|
||||
data = new RenderData();
|
||||
|
||||
timer = new Timer();
|
||||
timer.Interval = 3000;
|
||||
timer.Tick += (sender, e) =>
|
||||
{
|
||||
timer.Stop();
|
||||
coordinate = String.Empty;
|
||||
this.Invalidate();
|
||||
};
|
||||
}
|
||||
|
||||
/// <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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the displayed input data.
|
||||
/// </summary>
|
||||
public void SetData(RenderData data)
|
||||
{
|
||||
this.data = data;
|
||||
|
||||
meshRenderer = new MeshRenderer(data);
|
||||
|
||||
this.showVoronoi = data.VoronoiPoints != null;
|
||||
|
||||
if (showVoronoi)
|
||||
{
|
||||
voronoiRenderer = new VoronoiRenderer(data);
|
||||
}
|
||||
|
||||
// Reset the zoom on new data
|
||||
zoom.Initialize(this.ClientRectangle, data.Bounds);
|
||||
|
||||
initialized = true;
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
/// <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 Zoom(float x, float y, int delta)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
if (zoom.ZoomUpdate(delta, x, y))
|
||||
{
|
||||
// Redraw
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update graphics buffer and zoom after a resize.
|
||||
/// </summary>
|
||||
public void HandleResize()
|
||||
{
|
||||
zoom.Initialize(this.ClientRectangle, data.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);
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
this.Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
coordinate = String.Empty;
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics g = buffer.Graphics;
|
||||
g.Clear(this.BackColor);
|
||||
|
||||
if (!initialized || data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
if (voronoiRenderer != null && this.showVoronoi)
|
||||
{
|
||||
meshRenderer.RenderMesh(g, zoom, renderColors);
|
||||
voronoiRenderer.Render(g, zoom, renderColors);
|
||||
meshRenderer.RenderGeometry(g, zoom, renderColors);
|
||||
}
|
||||
else if (meshRenderer != null)
|
||||
{
|
||||
meshRenderer.Render(g, zoom, renderColors);
|
||||
}
|
||||
|
||||
this.Invalidate();
|
||||
}
|
||||
|
||||
#region Control overrides
|
||||
|
||||
protected override void OnPaint(PaintEventArgs pe)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaint(pe);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.Render();
|
||||
|
||||
if (!String.IsNullOrEmpty(coordinate) && data.Points != null)
|
||||
{
|
||||
Graphics g = pe.Graphics;
|
||||
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
|
||||
g.DrawString(coordinate, this.Font, Brushes.White, 10, 10);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseClick(MouseEventArgs e)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
if (e.Button == MouseButtons.Middle)
|
||||
{
|
||||
zoom.ZoomReset();
|
||||
this.Render();
|
||||
}
|
||||
else if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
/*
|
||||
// Just in case ...
|
||||
timer.Stop();
|
||||
|
||||
PointF c = zoom.ScreenToWorld((float)e.X / this.Width, (float)e.Y / this.Height);
|
||||
coordinate = String.Format("X:{0} Y:{1}",
|
||||
c.X.ToString(Util.Nfi),
|
||||
c.Y.ToString(Util.Nfi));
|
||||
|
||||
this.Invalidate();
|
||||
|
||||
timer.Start();
|
||||
* */
|
||||
}
|
||||
|
||||
base.OnMouseClick(e);
|
||||
}
|
||||
|
||||
protected override void OnPaintBackground(PaintEventArgs pevent)
|
||||
{
|
||||
// Do nothing
|
||||
if (!initialized)
|
||||
{
|
||||
base.OnPaintBackground(pevent);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="VoronoiRenderer.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core.GDI
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Renders a (bounded) Voronoi diagram.
|
||||
/// </summary>
|
||||
public class VoronoiRenderer
|
||||
{
|
||||
RenderData data;
|
||||
ColorManager renderColors;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VoronoiRenderer" /> class.
|
||||
/// </summary>
|
||||
public VoronoiRenderer(RenderData data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders the voronoi diagram.
|
||||
/// </summary>
|
||||
public void Render(Graphics g, Zoom zoom, ColorManager renderColors)
|
||||
{
|
||||
this.renderColors = renderColors;
|
||||
|
||||
var points = data.VoronoiPoints;
|
||||
var edges = data.VoronoiEdges;
|
||||
|
||||
if (points != null && edges != null)
|
||||
{
|
||||
uint k;
|
||||
PointF p0, p1;
|
||||
int n = edges.Length / 2;
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
// First endpoint of voronoi edge
|
||||
k = edges[2 * i];
|
||||
p0 = new PointF(points[2 * k], points[2 * k + 1]);
|
||||
|
||||
// Second endpoint of voronoi edge
|
||||
k = edges[2 * i + 1];
|
||||
p1 = new PointF(points[2 * k], points[2 * k + 1]);
|
||||
|
||||
// Render the edge
|
||||
if (zoom.ViewportContains(p0.X, p0.Y) ||
|
||||
zoom.ViewportContains(p1.X, p1.Y))
|
||||
{
|
||||
p0 = zoom.WorldToScreen(p0.X, p0.Y);
|
||||
p1 = zoom.WorldToScreen(p1.X, p1.Y);
|
||||
|
||||
g.DrawLine(renderColors.VoronoiLine, p0, p1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="IMeshRenderer.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: Update summary.
|
||||
/// </summary>
|
||||
public interface IMeshRenderer
|
||||
{
|
||||
void Zoom(float x, float y, int delta);
|
||||
void HandleResize();
|
||||
|
||||
void Initialize();
|
||||
|
||||
void SetData(RenderData data);
|
||||
|
||||
//void SetPoints(float[] points, int inputPoints);
|
||||
//void SetTriangles(uint[] triangles);
|
||||
//void SetSegments(uint[] segments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{9C5040DA-C739-43A1-8540-E6BD3ED6DB55}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MeshRenderer.Core</RootNamespace>
|
||||
<AssemblyName>MeshRenderer.Core</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.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BoundingBox.cs" />
|
||||
<Compile Include="ColorManager.cs" />
|
||||
<Compile Include="ExtensionMethods.cs" />
|
||||
<Compile Include="GDI\MeshRenderer.cs" />
|
||||
<Compile Include="GDI\RenderControl.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GDI\VoronoiRenderer.cs" />
|
||||
<Compile Include="IMeshRenderer.cs" />
|
||||
<Compile Include="RenderData.cs" />
|
||||
<Compile Include="RenderManager.cs" />
|
||||
<Compile Include="Zoom.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.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,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("MeshRenderer.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MeshRenderer.Core")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[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("99ca6350-3202-47b0-9645-d07b1ac4a294")]
|
||||
|
||||
// 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,185 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="RenderData.cs" company="">
|
||||
// Christian Woltering, Triangle.NET, http://triangle.codeplex.com/
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Drawing;
|
||||
using TriangleNet;
|
||||
using TriangleNet.Data;
|
||||
using TriangleNet.Geometry;
|
||||
using TriangleNet.Tools;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the current mesh in a rendering friendly data structure.
|
||||
/// </summary>
|
||||
public class RenderData
|
||||
{
|
||||
public float[] Points;
|
||||
public uint[] Segments;
|
||||
public uint[] Triangles;
|
||||
public uint[] MeshEdges;
|
||||
public float[] VoronoiPoints;
|
||||
public uint[] VoronoiEdges;
|
||||
|
||||
public int NumberOfInputPoints;
|
||||
public BoundingBox Bounds;
|
||||
|
||||
/// <summary>
|
||||
/// Copy input geometry data.
|
||||
/// </summary>
|
||||
public void SetInputGeometry(InputGeometry data)
|
||||
{
|
||||
// Clear unused buffers
|
||||
this.Segments = null;
|
||||
this.Triangles = null;
|
||||
this.MeshEdges = null;
|
||||
this.VoronoiPoints = null;
|
||||
this.VoronoiEdges = null;
|
||||
|
||||
int n = data.Count;
|
||||
int i = 0;
|
||||
|
||||
this.NumberOfInputPoints = n;
|
||||
|
||||
// Copy points
|
||||
this.Points = new float[2 * n];
|
||||
foreach (var pt in data.Points)
|
||||
{
|
||||
this.Points[2 * i] = (float)pt.X;
|
||||
this.Points[2 * i + 1] = (float)pt.Y;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Copy segments
|
||||
n = data.Segments.Count;
|
||||
if (n > 0)
|
||||
{
|
||||
var segments = new List<uint>(2 * n);
|
||||
foreach (var seg in data.Segments)
|
||||
{
|
||||
segments.Add((uint)seg.P0);
|
||||
segments.Add((uint)seg.P1);
|
||||
}
|
||||
this.Segments = segments.ToArray();
|
||||
}
|
||||
|
||||
this.Bounds = new BoundingBox(
|
||||
(float)data.Bounds.Xmin,
|
||||
(float)data.Bounds.Xmax,
|
||||
(float)data.Bounds.Ymin,
|
||||
(float)data.Bounds.Ymax);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy mesh data.
|
||||
/// </summary>
|
||||
public void SetMesh(Mesh mesh)
|
||||
{
|
||||
// Clear unused buffers
|
||||
this.Segments = null;
|
||||
this.VoronoiPoints = null;
|
||||
this.VoronoiEdges = null;
|
||||
|
||||
int n = mesh.Vertices.Count;
|
||||
int i = 0;
|
||||
|
||||
this.NumberOfInputPoints = mesh.NumberOfInputPoints;
|
||||
|
||||
// Linear numbering of mesh
|
||||
mesh.Renumber();
|
||||
|
||||
// Copy points
|
||||
this.Points = new float[2 * n];
|
||||
foreach (var pt in mesh.Vertices)
|
||||
{
|
||||
this.Points[2 * i] = (float)pt.X;
|
||||
this.Points[2 * i + 1] = (float)pt.Y;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Copy segments
|
||||
n = mesh.Segments.Count;
|
||||
if (n > 0)
|
||||
{
|
||||
var segments = new List<uint>(2 * n);
|
||||
foreach (var seg in mesh.Segments)
|
||||
{
|
||||
segments.Add((uint)seg.P0);
|
||||
segments.Add((uint)seg.P1);
|
||||
}
|
||||
this.Segments = segments.ToArray();
|
||||
}
|
||||
|
||||
// Copy edges
|
||||
var edges = new List<uint>(2 * mesh.NumberOfEdges);
|
||||
|
||||
EdgeEnumerator e = new EdgeEnumerator(mesh);
|
||||
while (e.MoveNext())
|
||||
{
|
||||
edges.Add((uint)e.Current.P0);
|
||||
edges.Add((uint)e.Current.P1);
|
||||
}
|
||||
this.MeshEdges = edges.ToArray();
|
||||
|
||||
// Copy Triangles
|
||||
var triangles = new List<uint>(3 * mesh.Triangles.Count);
|
||||
foreach (var tri in mesh.Triangles)
|
||||
{
|
||||
triangles.Add((uint)tri.P0);
|
||||
triangles.Add((uint)tri.P1);
|
||||
triangles.Add((uint)tri.P2);
|
||||
}
|
||||
this.Triangles = triangles.ToArray();
|
||||
|
||||
this.Bounds = new BoundingBox(
|
||||
(float)mesh.Bounds.Xmin,
|
||||
(float)mesh.Bounds.Xmax,
|
||||
(float)mesh.Bounds.Ymin,
|
||||
(float)mesh.Bounds.Ymax);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy voronoi data.
|
||||
/// </summary>
|
||||
public void SetVoronoi(IVoronoi voro)
|
||||
{
|
||||
SetVoronoi(voro, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy voronoi data.
|
||||
/// </summary>
|
||||
public void SetVoronoi(IVoronoi voro, int infCount)
|
||||
{
|
||||
/*
|
||||
int i, n = voro.VertexList.Count;
|
||||
|
||||
// Copy points
|
||||
this.VoronoiPoints = new float[2 * n + infCount];
|
||||
foreach (var v in voro.VertexList)
|
||||
{
|
||||
i = v.Id;
|
||||
this.VoronoiPoints[2 * i] = (float)v.X;
|
||||
this.VoronoiPoints[2 * i + 1] = (float)v.Y;
|
||||
}
|
||||
|
||||
// Copy edges
|
||||
var edges = new List<uint>(voro.HalfEdgeList.Count);
|
||||
foreach (var edge in voro.Edges)
|
||||
{
|
||||
if (edge.P0 >= 0 && edge.P1 >= 0)
|
||||
{
|
||||
edges.Add((uint)edge.P0);
|
||||
edges.Add((uint)edge.P1);
|
||||
}
|
||||
}
|
||||
this.VoronoiEdges = edges.ToArray();
|
||||
* */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="RenderManager.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// This is a proxy to an actual IMeshRenderer instance.
|
||||
/// </summary>
|
||||
public class RenderManager : IMeshRenderer
|
||||
{
|
||||
IMeshRenderer renderer;
|
||||
|
||||
public Control RenderControl
|
||||
{
|
||||
get { return (Control)renderer; }
|
||||
set
|
||||
{
|
||||
if (value is IMeshRenderer)
|
||||
{
|
||||
renderer = (IMeshRenderer)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
renderer.Initialize();
|
||||
}
|
||||
|
||||
public void Zoom(float x, float y, int delta)
|
||||
{
|
||||
renderer.Zoom(x, y, delta);
|
||||
}
|
||||
|
||||
public void HandleResize()
|
||||
{
|
||||
renderer.HandleResize();
|
||||
}
|
||||
|
||||
public void SetData(RenderData data)
|
||||
{
|
||||
renderer.SetData(data);
|
||||
}
|
||||
|
||||
public void CreateDefaultControl()
|
||||
{
|
||||
this.RenderControl = new MeshRenderer.Core.GDI.RenderControl();
|
||||
}
|
||||
|
||||
public bool CreateControl(string assemblyName)
|
||||
{
|
||||
return CreateControl(assemblyName, null);
|
||||
}
|
||||
|
||||
public bool CreateControl(string assemblyName, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
|
||||
|
||||
// Try creating renderer instance.
|
||||
try
|
||||
{
|
||||
// Load the assembly into the current application domain.
|
||||
Assembly assembly = Assembly.Load(assemblyName);
|
||||
|
||||
// Get all types implementing the IMeshRenderer interface.
|
||||
var type = typeof(IMeshRenderer);
|
||||
var types = assembly.GetTypes().Where(s => type.IsAssignableFrom(s)).ToArray();
|
||||
|
||||
if (types.Length > 0)
|
||||
{
|
||||
// Create an instance.
|
||||
renderer = (IMeshRenderer)Activator.CreateInstance(types[0]);
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if render control was successfully created.
|
||||
return (renderer != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// <copyright file="Zoom.cs" company="">
|
||||
// TODO: Update copyright text.
|
||||
// </copyright>
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
namespace MeshRenderer.Core
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Manages the current world to screen transformation
|
||||
/// </summary>
|
||||
public class Zoom
|
||||
{
|
||||
// The complete mesh
|
||||
Rectangle Screen;
|
||||
|
||||
// The complete mesh
|
||||
RectangleF World { get; set; }
|
||||
|
||||
// The current viewport (visible mesh)
|
||||
public RectangleF Viewport { get; set; }
|
||||
|
||||
// Current scale (zoom level)
|
||||
public float Scale
|
||||
{
|
||||
get { return Screen.Width / Viewport.Width; }
|
||||
}
|
||||
|
||||
// Current scale (zoom level)
|
||||
public int Level { get; private set; }
|
||||
|
||||
// Add a margin to clip region (5% of viewport width on each side)
|
||||
public float ClipMargin { get; set; }
|
||||
|
||||
bool invertY = false;
|
||||
|
||||
public Zoom()
|
||||
: this(false)
|
||||
{
|
||||
}
|
||||
|
||||
public Zoom(bool invertY)
|
||||
{
|
||||
Level = -1;
|
||||
this.invertY = invertY;
|
||||
}
|
||||
|
||||
public void Initialize(Rectangle screen)
|
||||
{
|
||||
this.Screen = screen;
|
||||
|
||||
this.Level = 1;
|
||||
|
||||
this.Viewport = screen;
|
||||
|
||||
this.ClipMargin = this.Viewport.Width * 0.05f;
|
||||
|
||||
this.World = screen;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void Update(BoundingBox world)
|
||||
{
|
||||
if (this.Screen != null)
|
||||
{
|
||||
Initialize(this.Screen, world);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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 ZoomUpdate(int amount, float focusX, float focusY)
|
||||
{
|
||||
float width, height;
|
||||
|
||||
if (invertY)
|
||||
{
|
||||
focusY = 1 - focusY;
|
||||
}
|
||||
|
||||
if (amount > 0) // Zoom in
|
||||
{
|
||||
this.Level++;
|
||||
|
||||
if (this.Level > 50)
|
||||
{
|
||||
this.Level = 50;
|
||||
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 ZoomReset()
|
||||
{
|
||||
this.Viewport = this.World;
|
||||
this.Level = 1;
|
||||
}
|
||||
|
||||
public bool ViewportContains(float x, float y)
|
||||
{
|
||||
return (x > Viewport.X && x < Viewport.Right
|
||||
&& y > Viewport.Y && y < Viewport.Bottom);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public PointF ScreenToWorld(float x, float y)
|
||||
{
|
||||
return new PointF(Viewport.X + Viewport.Width * x,
|
||||
Viewport.Y + Viewport.Height * (1 - y));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user