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