using OpenTK.Mathematics;
namespace Yw.WinFrmUI.Hydro
{
///
/// 2d正交相机
///
internal class OrthoCamera2d
{
///
/// 辅助类
///
public OrthoCamera2d() { }
///
/// 旋转
///
public Vector3 Rotation
{
get => _rotation;
set => _rotation = value;
}
private Vector3 _rotation = Vector3.Zero;
///
/// 平移
///
public Vector3 Translation
{
get => _translation;
set => _translation = value;
}
private Vector3 _translation = Vector3.Zero;
///
/// 投影矩阵
///
public Matrix4 ProjectionMatrix
{
get => _projectionMatrix;
set => _projectionMatrix = value;
}
private Matrix4 _projectionMatrix = Matrix4.Identity;
///
/// 视图矩阵
///
public Matrix4 ViewMatrix
{
get => _viewMatrix;
set => _viewMatrix = value;
}
private Matrix4 _viewMatrix = Matrix4.Identity;
///
/// 模型矩阵
///
public Matrix4 ModelMatrix
{
get => _modelMatrix;
set => _modelMatrix = value;
}
private Matrix4 _modelMatrix = Matrix4.Identity;
///
/// 缩放
///
public float Zoom
{
get => _zoom;
set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // 限制缩放范围
}
private float _zoom = 1.0f; // 当前缩放系数(1表示原始大小)
private BoundingBox3 _bx = null;
private Vector3 _center = Vector3.Zero;
private float _radius = 100f;//包围球半径
private float _width, _height, _aspect;//视口宽度和高度与宽高比
private float _pw, _ph;//投影宽度和高度
///
/// 初始化
///
public void Initial(List vers, int width, int height)
{
UpdateViewPort(width, height);
if (vers == null || vers.Count < 1)
{
vers = new List()
{
new Vector3(-_width/2f,-_height/2f,-100f),
new Vector3(width/2f,height/2f,100f)
};
}
_bx = new BoundingBox3(vers);
_center = _bx.Center;
_radius = _bx.Size.Length / 2f * 1.2f;
UpdateMatrices();
}
///
/// 更新视口
///
public void UpdateViewPort(int width, int height)
{
_width = width < 1 ? 1f : width;
_height = height < 1 ? 1f : height;
_aspect = _width / _height;
}
///
/// 更新缩放
///
public void UpdateZoom(float scale)
{
this.Zoom *= scale;
}
///
/// 更新平移
///
public void UpdateTranslation(float dx, float dy)
{
float xratio = _pw / _width;
float yratio = _ph / _height;
_translation.X += dx * xratio;
_translation.Y -= dy * yratio;
}
///
/// 更新旋转
///
public void UpdateRotation(float dx, float dy)
{
_rotation.X += dy / _radius;
_rotation.Y += dx / _radius;
_rotation.X = NormalizeAngle(_rotation.X);
_rotation.Y = NormalizeAngle(_rotation.Y);
}
///
/// 更新模型矩阵
///
public void UpdateModelMatrix()
{
_modelMatrix = Matrix4.CreateRotationX(_rotation.X) *
Matrix4.CreateRotationY(_rotation.Y) *
Matrix4.CreateTranslation(_translation * this.Zoom);
}
///
/// 更新视图矩阵
///
public void UpdateViewMatrix()
{
var eye = new Vector3(_center.X, _center.Y, _center.Z + 2f * _radius);
var target = _center;
var up = Vector3.UnitY;
_viewMatrix = Matrix4.LookAt(eye, target, up);
}
///
/// 更新投影矩阵
///
public void UpdateProjectionMatrix()
{
_pw = _ph = _radius * 2f;
if (_aspect > 1)
{
_pw *= _aspect;
}
else
{
_ph /= _aspect;
}
_projectionMatrix = Matrix4.CreateOrthographic(_pw * this.Zoom, _ph * this.Zoom, _radius, _radius * 3f);
}
///
/// 更新举证
///
public void UpdateMatrices()
{
UpdateModelMatrix();
UpdateViewMatrix();
UpdateProjectionMatrix();
}
//标准化旋转弧度
private static float NormalizeAngle(float angle)
{
// 取余操作
angle %= 2 * MathF.PI;
// 如果结果为负数,加上 2π 使其处于 [0, 2π) 区间
if (angle < 0)
{
angle += 2 * MathF.PI;
}
return angle;
}
}
}