using OpenTK.GLControl;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using System.Transactions;
using System.Windows.Forms;
namespace Yw.WinFrmUI.Hydro
{
///
/// 正交相机辅助类
///
internal class OrthoCamera2dHelper
{
///
/// 辅助类
///
public OrthoCamera2dHelper() { }
///
/// 初始化
///
public void Initial(GLControl gl, NetworkL3d nw)
{
_gl = gl;
_nw = nw;
_veccache = new Vector3CacheHelper(nw);
var pts = _veccache.GetAll();
_bx = new BoundingBox3(pts);
_mc = (_bx.Max + _bx.Min) * 0.5f;
_radius = (_bx.Max - _bx.Min).Length / 2f;
UpdateModelMatrix();
UpdateViewMatrix();
UpdateProjectionMatrix();
}
// 基础参数
private GLControl _gl = null;//gl控件
private NetworkL3d _nw = null;//管网模型
private Vector3CacheHelper _veccache = null;//位置辅助类
private BoundingBox3 _bx = null;//包围盒
private Vector3 _mc; //模型中心
private float _radius = 100f;//包围球半径
private float _pw = 10f;//投影宽度
private float _ph = 10f;//投影高度
private Quaternion _rotation = Quaternion.Identity;//旋转四元数
private Vector3 _translation = Vector3.Zero;//平移量
private Matrix4 _modelMatrix;//模型矩阵
private Matrix4 _viewMatrix;//视图矩阵
private Matrix4 _projMatrix;//投影矩阵
private Vector3 _forward;
///
/// 缩放
///
public float Zoom
{
get => _zoom;
set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // 限制缩放范围
}
private float _zoom = 1.0f; // 当前缩放系数(1表示原始大小)
///
/// 是否初始化
///
public bool Initialized
{
get
{
if (_nw == null)
{
return false;
}
if (_gl == null)
{
return false;
}
return true;
}
}
//更新模型矩阵
private void UpdateModelMatrix()
{
_modelMatrix = Matrix4.CreateTranslation(_translation * this.Zoom);
}
//更新视图矩阵
private void UpdateViewMatrix()
{
var eye = new Vector3(_mc.X, _mc.Y, _mc.Z + _radius * 2);
var target = _mc;
var up = Vector3.UnitY;
var matrix = Matrix4.CreateFromQuaternion(_rotation);
matrix.Invert();
eye = Vector3.TransformPosition(eye, matrix);
up = Vector3.TransformPosition(up, matrix);
_viewMatrix = Matrix4.LookAt(eye, target, up);
_forward = target - eye;
_forward.Normalize();
}
//更新投影矩阵
private void UpdateProjectionMatrix()
{
if (!Initialized)
{
return;
}
var aspect = _gl.AspectRatio;
var size = _radius * 2;
_pw = size;
_ph = size;
if (aspect > 1)
{
_pw *= aspect;
}
else
{
_ph /= aspect;
}
_projMatrix = Matrix4.CreateOrthographic(_pw * this.Zoom, _ph * this.Zoom, _radius, _radius * 3);
}
#region 鼠标交互
private bool _isDragging = false;//是否增在拖动
private bool _isRotating = false;//是否正在旋转
private Point _lastMousePos;//最近一次鼠标位置
///
/// 处理大小改变
///
public void HandleResize()
{
if (!Initialized)
{
return;
}
_gl.MakeCurrent();
GL.Viewport(0, 0, _gl.Width, _gl.Height);
UpdateProjectionMatrix();
_gl.Invalidate();
}
///
/// 处理绘制
///
public void HandleRender()
{
if (!Initialized)
{
return;
}
_gl.MakeCurrent();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
//投影矩阵
GL.MatrixMode(MatrixMode.Projection);
GL.LoadMatrix(ref _projMatrix);
//视图矩阵
GL.MatrixMode(MatrixMode.Modelview);
var viewMatrix = _viewMatrix * _modelMatrix;
GL.LoadMatrix(ref viewMatrix);
_nw.Draw2d();
//var code = GL.GetError();
_gl.SwapBuffers();
}
///
/// 处理鼠标滚轮
///
public void HandleMouseWheel(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
this.Zoom *= e.Delta > 0 ? 0.9f : 1.1f;
UpdateModelMatrix();
UpdateViewMatrix();
UpdateProjectionMatrix();
_gl.Invalidate();
}
///
/// 处理鼠标按下
///
public void HandleMouseDown(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
_lastMousePos = e.Location;
if (e.Button == MouseButtons.Right)
{
_isDragging = true;
_gl.Cursor = Cursors.SizeAll; // 修改光标样式
}
else if (e.Button == MouseButtons.Left)
{
_isRotating = true;
_gl.Cursor = Cursors.SizeAll; // 修改光标样式
}
}
///
/// 处理鼠标弹起
///
public void HandleMouseUp(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
_lastMousePos = e.Location;
if (e.Button == MouseButtons.Right)
{
_isDragging = false;
_gl.Cursor = Cursors.Default;
}
else if (e.Button == MouseButtons.Left)
{
_isRotating = false;
_gl.Cursor = Cursors.Default;
}
_gl.Invalidate();
}
///
/// 处理鼠标移动
///
public void HandleMouseMove(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
float dx = e.X - _lastMousePos.X;
float dy = e.Y - _lastMousePos.Y;
if (_isRotating)
{
// 根据鼠标移动量计算旋转角度
Quaternion rotationX = Quaternion.FromAxisAngle(Vector3.UnitX, dy / _radius);
Quaternion rotationY = Quaternion.FromAxisAngle(Vector3.UnitY, dx / _radius);
// 更新四元数
_rotation = rotationY * rotationX * _rotation;
_rotation = Quaternion.Normalize(_rotation);
UpdateModelMatrix();
UpdateViewMatrix();
UpdateProjectionMatrix();
}
else if (_isDragging)
{
float xratio = _pw / _gl.Width;
float yratio = _ph / _gl.Height;
_translation.X += dx * xratio;
_translation.Y -= dy * yratio;
UpdateModelMatrix();
UpdateViewMatrix();
UpdateProjectionMatrix();
}
//var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height);
//var pos = OrthoTransformHelper.ScreenToWorld(e.X, e.Y, depth, _viewMatrix * _modelMatrix, _projMatrix, _gl.Width, _gl.Height);
//_nw.Hover2d(pos, this.Zoom, _veccache);
//var ray = OrthoTransformHelper.CreateRay(e.X, e.Y, depth, _forward, _modelMatrix, _viewMatrix, _projMatrix, _gl.Width, _gl.Height);
var ray = OrthoTransformHelper.CreateRay2(e.X, e.Y, _modelMatrix, _viewMatrix, _projMatrix, _gl.Width, _gl.Height);
if (ray != null)
{
_nw.Hover2d(ray, this.Zoom, _veccache);
//_gl.Invalidate();
}
_lastMousePos = e.Location;
_gl.Invalidate();
}
public void HandleMouseHover()
{
if (!Initialized)
{
return;
}
//var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height);
//var pos = OrthoTransformHelper.ScreenToWorld(e.X, e.Y, depth, _viewMatrix * _modelMatrix, _projMatrix, _gl.Width, _gl.Height);
//_nw.Hover2d(pos, this.Zoom, _veccache);
//var ray = OrthoTransformHelper.CreateRay(e.X, e.Y, depth, _forward, _modelMatrix, _viewMatrix, _projMatrix, _gl.Width, _gl.Height);
//var ray = OrthoTransformHelper.CreateRay2(_lastMousePos.X, _lastMousePos.Y, _modelMatrix, _viewMatrix, _projMatrix, _gl.Width, _gl.Height);
//if (ray != null)
//{
// _nw.Hover2d(ray, this.Zoom, _veccache);
// _gl.Invalidate();
//}
}
///
/// 处理鼠标点击
///
public void HandleMouseClick(MouseEventArgs e)
{
}
///
/// 处理鼠标双击
///
public void HandleMouseDoubleClick(MouseEventArgs e)
{
var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height);
var world = OrthoTransformHelper.ScreenToWorld(e.X, e.Y, depth, _viewMatrix * _modelMatrix, _projMatrix, _gl.Width, _gl.Height);
MessageBox.Show($"x:{world.X},y:{world.Y},z:{world.Z}");
}
#endregion
}
}