Files
OpenNest/OpenNest/Controls/DrawControl.cs
2026-03-06 13:02:12 -05:00

249 lines
7.7 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using OpenNest.Geometry;
namespace OpenNest.Controls
{
public abstract class DrawControl : Control
{
protected PointF origin;
protected Point lastPoint;
protected System.Drawing.Size lastSize;
public Vector LastPoint { get; protected set; }
public Vector CurrentPoint { get; protected set; }
public float ViewScale { get; protected set; }
public float ViewScaleMin { get; protected set; }
public float ViewScaleMax { get; protected set; }
internal Matrix Matrix { get; set; }
protected const int BorderWidth = 50;
protected const float ZoomInFactor = 1.15f;
protected const float ZoomOutFactor = 1.0f / ZoomInFactor;
protected DrawControl()
{
ViewScale = 1.0f;
ViewScaleMin = 0.3f;
ViewScaleMax = 3000;
origin = new PointF(100, 100);
}
/// <summary>
/// Returns a point with coordinates relative to the control from the graph.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public Point PointGraphToControl(float x, float y)
{
return new Point((int)(x + origin.X), (int)(y + origin.Y));
}
/// <summary>
/// Returns a point with coordinates relative to the control from the graph.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public Point PointGraphToControl(PointF pt)
{
return PointGraphToControl(pt.X, pt.Y);
}
/// <summary>
/// Returns a point with coordinates relative to the control from the world.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public Point PointWorldToControl(double x, double y)
{
return PointGraphToControl(PointWorldToGraph(x, y));
}
/// <summary>
/// Returns a point with coordinates relative to the control from the world.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public Point PointWorldToControl(Vector pt)
{
return PointGraphToControl(PointWorldToGraph(pt.X, pt.Y));
}
/// <summary>
/// Returns a point with coordinates relative to the graph from the control.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public PointF PointControlToGraph(int x, int y)
{
return new PointF(x - origin.X, y - origin.Y);
}
/// <summary>
/// Returns a point with coordinates relative to the graph from the control.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public PointF PointControlToGraph(Point pt)
{
return PointControlToGraph(pt.X, pt.Y);
}
/// <summary>
/// Returns a point with coordinates relative to the graph from the world.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public PointF PointWorldToGraph(double x, double y)
{
return new PointF(ViewScale * (float)x, -ViewScale * (float)y);
}
/// <summary>
/// Returns a point with coordinates relative to the graph from the world.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public PointF PointWorldToGraph(Vector pt)
{
return PointWorldToGraph(pt.X, pt.Y);
}
/// <summary>
/// Returns a point with coordinates relative to the world from the control.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public Vector PointControlToWorld(int x, int y)
{
return PointGraphToWorld(PointControlToGraph(x, y));
}
/// <summary>
/// Returns a point with coordinates relative to the world from the control.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public Vector PointControlToWorld(Point pt)
{
return PointGraphToWorld(PointControlToGraph(pt.X, pt.Y));
}
/// <summary>
/// Returns a point with coordinates relative to the world from the graph.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public Vector PointGraphToWorld(float x, float y)
{
return new Vector(x / ViewScale, y / -ViewScale);
}
/// <summary>
/// Returns a point with coordinates relative to the world from the graph.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public Vector PointGraphToWorld(PointF pt)
{
return PointGraphToWorld(pt.X, pt.Y);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
origin.X += (Size.Width - lastSize.Width) * 0.5f;
origin.Y += (Size.Height - lastSize.Height) * 0.5f;
lastSize = Size;
}
public float LengthWorldToGui(double length)
{
return ViewScale * (float)length;
}
public double LengthGuiToWorld(float length)
{
return length / ViewScale;
}
public virtual void ZoomToControlPoint(Point pt, float zoomFactor, bool redraw = true)
{
var pt2 = PointControlToWorld(pt);
ZoomToPoint(pt2, zoomFactor, redraw);
}
public virtual void ZoomToPoint(Vector pt, float zoomFactor, bool redraw = true)
{
var newScale = ViewScale * zoomFactor;
if (newScale < ViewScaleMin)
zoomFactor = ViewScaleMin / ViewScale;
else if (newScale > ViewScaleMax)
zoomFactor = ViewScaleMax / ViewScale;
origin.X -= (float)(pt.X * zoomFactor - pt.X) * ViewScale;
origin.Y += (float)(pt.Y * zoomFactor - pt.Y) * ViewScale;
ViewScale *= zoomFactor;
UpdateMatrix();
if (redraw) Invalidate();
}
public virtual void ZoomToArea(Box box, bool redraw = true)
{
ZoomToArea(box.X, box.Y, box.Width, box.Height, redraw);
}
public virtual void ZoomToArea(double x, double y, double width, double height, bool redraw = true)
{
if (width <= 0 || height <= 0)
return;
var a = (Height - BorderWidth) / height;
var b = (Width - BorderWidth) / width;
ViewScale = (float)(a < b ? a : b);
if (ViewScale > ViewScaleMax)
ViewScale = ViewScaleMax;
else if (ViewScale < ViewScaleMin)
ViewScale = ViewScaleMin;
var px = LengthWorldToGui(x);
var py = LengthWorldToGui(y);
var pw = LengthWorldToGui(width);
var ph = LengthWorldToGui(height);
origin.X = (Width - pw) * 0.5f - px;
origin.Y = (Height + ph) * 0.5f + py;
UpdateMatrix();
if (redraw) Invalidate();
}
protected virtual void UpdateMatrix()
{
if (Matrix != null)
Matrix.Dispose();
Matrix = new Matrix();
Matrix.Scale(ViewScale, -ViewScale);
}
}
}