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 } }