using OpenTK.GLControl;
|
using OpenTK.Graphics.OpenGL;
|
using OpenTK.Mathematics;
|
using System.Transactions;
|
using System.Windows.Forms;
|
|
namespace Yw.WinFrmUI.Hydro
|
{
|
/// <summary>
|
/// 正交相机辅助类
|
/// </summary>
|
internal class OrthoCamera2dHelper
|
{
|
|
/// <summary>
|
/// 辅助类
|
/// </summary>
|
public OrthoCamera2dHelper() { }
|
|
/// <summary>
|
/// 初始化
|
/// </summary>
|
public void Initial(GLControl gl, NetworkL3d nw)
|
{
|
_gl = gl;
|
_nw = nw;
|
_veccache = new Vector32dCacheHelper(nw);
|
var pts = _veccache.GetPositions();
|
_bx = new BoundingBox3(pts);
|
_bxcache = new BoundingBox32dCacheHelper(nw, _veccache);
|
_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 Vector32dCacheHelper _veccache = null;//位置辅助类
|
private BoundingBox3 _bx = null;//包围盒
|
private BoundingBox32dCacheHelper _bxcache = 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;
|
|
/// <summary>
|
/// 缩放
|
/// </summary>
|
public float Zoom
|
{
|
get => _zoom;
|
set => _zoom = MathHelper.Clamp(value, 0.01f, 100.0f); // 限制缩放范围
|
}
|
private float _zoom = 1.0f; // 当前缩放系数(1表示原始大小)
|
|
/// <summary>
|
/// 是否初始化
|
/// </summary>
|
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;//最近一次鼠标位置
|
|
/// <summary>
|
/// 处理大小改变
|
/// </summary>
|
public void HandleResize()
|
{
|
if (!Initialized)
|
{
|
return;
|
}
|
_gl.MakeCurrent();
|
GL.Viewport(0, 0, _gl.Width, _gl.Height);
|
UpdateProjectionMatrix();
|
_gl.Invalidate();
|
}
|
|
/// <summary>
|
/// 处理绘制
|
/// </summary>
|
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();
|
}
|
|
/// <summary>
|
/// 处理鼠标滚轮
|
/// </summary>
|
public void HandleMouseWheel(MouseEventArgs e)
|
{
|
if (!Initialized)
|
{
|
return;
|
}
|
this.Zoom *= e.Delta > 0 ? 0.9f : 1.1f;
|
UpdateModelMatrix();
|
UpdateViewMatrix();
|
UpdateProjectionMatrix();
|
_gl.Invalidate();
|
}
|
|
/// <summary>
|
/// 处理鼠标按下
|
/// </summary>
|
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; // 修改光标样式
|
}
|
}
|
|
/// <summary>
|
/// 处理鼠标弹起
|
/// </summary>
|
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();
|
}
|
|
/// <summary>
|
/// 处理鼠标移动
|
/// </summary>
|
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);
|
UpdateViewMatrix();
|
}
|
else if (_isDragging)
|
{
|
float xratio = _pw / _gl.Width;
|
float yratio = _ph / _gl.Height;
|
_translation.X += dx * xratio;
|
_translation.Y -= dy * yratio;
|
UpdateModelMatrix();
|
}
|
else
|
{
|
var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height);
|
var ray = OrthoTransformHelper.CreateRay(e.X, e.Y, depth, _forward, _modelMatrix, _viewMatrix, _projMatrix, _gl.Width, _gl.Height);
|
if (ray != null)
|
{
|
_nw.Hover2d(ray, _bxcache);
|
}
|
}
|
|
_lastMousePos = e.Location;
|
_gl.Invalidate();
|
}
|
|
/// <summary>
|
/// 处理鼠标点击
|
/// </summary>
|
public void HandleMouseClick(MouseEventArgs e)
|
{
|
|
}
|
|
/// <summary>
|
/// 处理鼠标双击
|
/// </summary>
|
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
|
|
|
|
|
|
|
|
|
|
}
|
}
|