using OpenTK.GLControl;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
namespace Yw.WinFrmUI.Hydro
{
///
/// 正交2d视图辅助类
///
internal class OrthoViewer2dHelper
{
///
/// 辅助类
///
public OrthoViewer2dHelper() { }
#region 公共事件
///
/// 旋转改变事件
///
public event Action RotationChangedEvent;
#endregion
#region 私有字段
private GLControl _gl = null;//gl控件
private NetworkL3d _nw = null;//管网模型
private Vector3CacheHelper _veccache = null;//位置缓存
private OrthoCamera2d _camera = null;//相机
private Point _lastMos;//最近的鼠标位置
private bool _isTranslation, _isRotation;
#endregion
#region 公共属性
///
/// 是否初始化
///
public bool Initialized
{
get
{
if (_nw == null)
{
return false;
}
if (_gl == null)
{
return false;
}
if (_camera == null)
{
return false;
}
return true;
}
}
#endregion
///
/// 初始化
///
public void Initial(GLControl gl, NetworkL3d nw)
{
_gl = gl;
_nw = nw;
_veccache = new Vector3CacheHelper(nw);
_camera = new OrthoCamera2d();
_camera.Initial(_veccache.GetAll(), gl.Width, gl.Height);
}
#region 辅助方法
//初始化GL状态
private void InitialGLState()
{
GL.ClearColor(Color.Transparent); // 背景颜色
GL.Enable(EnableCap.DepthTest);//深度测试
GL.DepthMask(true); // 允许写入深度缓冲区
GL.Enable(EnableCap.PointSmooth);//启用点平滑
GL.Enable(EnableCap.LineSmooth);//启用线平滑
GL.Enable(EnableCap.Multisample);// 启用反锯齿
GL.ShadeModel(ShadingModel.Smooth);
// 设置混合模式以支持反锯齿
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
Resize();
}
#endregion
#region 交互处理
///
/// 加载
///
public void Load()
{
if (!Initialized)
{
return;
}
_gl.MakeCurrent();
InitialGLState();
}
///
/// 大小改变
///
public void Resize()
{
if (!Initialized)
{
return;
}
_gl.MakeCurrent();
_camera.UpdateViewPort(_gl.Width, _gl.Height);
GL.Viewport(0, 0, _gl.Width, _gl.Height);
_camera.UpdateMatrices();
_gl.Invalidate();
}
///
/// 绘制
///
public void Render()
{
if (!Initialized)
{
return;
}
_gl.MakeCurrent();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
//投影矩阵
GL.MatrixMode(MatrixMode.Projection);
var projectionMatrix = _camera.ProjectionMatrix;
GL.LoadMatrix(ref projectionMatrix);
//视图矩阵
GL.MatrixMode(MatrixMode.Modelview);
var viewMatrix = _camera.ViewMatrix;
GL.LoadMatrix(ref viewMatrix);
var modelMatrix = _camera.ModelMatrix;
GL.MultMatrix(ref modelMatrix);
_nw.Draw2d(_camera.Zoom);
_gl.SwapBuffers();
}
///
/// 鼠标滚轮
///
public void MouseWheel(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
var scale = e.Delta > 0 ? 0.9f : 1.1f;
_camera.UpdateZoom(scale);
_camera.UpdateMatrices();
_gl.Invalidate();
}
///
/// 鼠标按下
///
public void MouseDown(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
_lastMos = e.Location;
if (e.Button == MouseButtons.Right)
{
_isTranslation = true;
_gl.Cursor = Cursors.SizeAll; // 修改光标样式
}
else if (e.Button == MouseButtons.Left)
{
_isRotation = true;
_gl.Cursor = Cursors.SizeAll; // 修改光标样式
}
}
///
/// 鼠标弹起
///
public void MouseUp(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
_lastMos = e.Location;
if (e.Button == MouseButtons.Right)
{
_isTranslation = false;
_gl.Cursor = Cursors.Default;
}
else if (e.Button == MouseButtons.Left)
{
_isRotation = false;
_gl.Cursor = Cursors.Default;
}
_gl.Invalidate();
}
///
/// 鼠标移动
///
public void MouseMove(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
float dx = e.X - _lastMos.X;
float dy = e.Y - _lastMos.Y;
if (_isRotation)
{
_camera.UpdateRotation(dx, dy);
_camera.UpdateMatrices();
this.RotationChangedEvent?.Invoke(_camera.Rotation);
}
else if (_isTranslation)
{
_camera.UpdateTranslation(dx, dy);
_camera.UpdateMatrices();
}
var ray = OrthoTransformHelper.CreateRay(e.X, e.Y, _camera.ModelMatrix, _camera.ViewMatrix, _camera.ProjectionMatrix, _gl.Width, _gl.Height);
if (ray != null)
{
_nw.Hover2d(ray, _camera.Zoom, _veccache);
}
_lastMos = e.Location;
_gl.Invalidate();
}
///
/// 鼠标点击
///
public void MouseClick(MouseEventArgs e)
{
if (!Initialized)
{
return;
}
var ray = OrthoTransformHelper.CreateRay(e.X, e.Y, _camera.ModelMatrix, _camera.ViewMatrix, _camera.ProjectionMatrix, _gl.Width, _gl.Height);
if (ray != null)
{
_nw.Select2d(ray, _camera.Zoom, _veccache);
}
_gl.Invalidate();
}
///
/// 鼠标双击
///
public void MouseDoubleClick(MouseEventArgs e)
{
var depth = OrthoTransformHelper.GetScreenPointDepth(e.X, e.Y, _gl.Height);
var world = OrthoTransformHelper.ScreenToWorld(e.X, e.Y, depth, _camera.ModelMatrix, _camera.ViewMatrix, _camera.ProjectionMatrix, _gl.Width, _gl.Height);
MessageBox.Show($"x:{world.X},y:{world.Y},z:{world.Z}");
}
#endregion
}
}