lixiaojun
2025-03-17 85fc43aa549bbe24c4d867a055c0d90d21deba8b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
using OpenTK.GLControl;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
 
namespace Yw.WinFrmUI.Hydro
{
    /// <summary>
    /// 正交相机
    /// </summary>
    internal class Ortho2dCamera
    {
 
        // 基础参数
        private List<Vector3> _pts = null; //所有坐标  
        private BoundingBox3 _wbx;//世界包围盒
        private BoundingBox3 _vbx;//视图包围盒
        private float _baseSize = 10f;//基础尺寸
        private float _orthoWidth = 10f;//正交宽度
        private float _orthoHeight = 10f;//正交高度
        private float _orthoNear = 0.1f;//正交近截面
        private float _orthoFar = 10f;//正交远截面
        private float _aspect = 1f;//视口宽高比
        private Vector3 _rotation = Vector3.Zero;//旋转量
        private Vector3 _translation = Vector3.Zero;//平移量
 
        /// <summary>
        /// 投影矩阵
        /// </summary>
        public Matrix4 ProjectionMatrix => _projectionMatrix;
        private Matrix4 _projectionMatrix;
 
        /// <summary>
        /// 视图模型
        /// </summary>
        public Matrix4 ViewMatrix
        {
            get
            {
                return _viewMatrix;
            }
        }
        private Matrix4 _viewMatrix;
 
        /// <summary>
        /// 模型矩阵
        /// </summary>
        public Matrix4 ModelMatrix => _modelMatrix;
        private Matrix4 _modelMatrix;
 
        public Vector3 Translation => _translation;
        public Vector3 Rotation => _rotation;
 
        /// <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 void Initial(List<Vector3> pts)
        {
            _pts = pts;
            if (pts != null && pts.Count > 0)
            {
                _wbx = new BoundingBox3(pts);
                _vbx = TransformBoundsToViewSpace(_wbx);
                _baseSize = CalcuBaseSize(_vbx);
            }
        }
 
 
        //世界包围盒=>视图包围盒
        private BoundingBox3 TransformBoundsToViewSpace(BoundingBox3 worldBounds)
        {
            var corners = worldBounds.GetCorners();
            Vector3 min = new(float.MaxValue);
            Vector3 max = new(float.MinValue);
            var qua = new Quaternion(_rotation);
 
            foreach (var corner in corners)
            {
                Vector3 viewPos = Vector3.Transform(corner, qua);
                min = Vector3.ComponentMin(min, viewPos);
                max = Vector3.ComponentMax(max, viewPos);
            }
 
            return new BoundingBox3(min, max);
        }
 
        //计算基础尺寸
        private float CalcuBaseSize(BoundingBox3 vbx)
        {
            var halfX = Math.Max(Math.Abs(vbx.Max.X), Math.Abs(vbx.Min.X));
            var halfY = Math.Max(Math.Abs(vbx.Max.Y), Math.Abs(vbx.Min.Y));
            var halfZ = Math.Max(Math.Abs(vbx.Max.Z), Math.Abs(vbx.Min.Z));
            var baseSize = Math.Max(halfX, Math.Max(halfY, halfZ));
            return baseSize * 2f;
        }
 
        //更新视口
        public void UpdateViewport(int width, int height)
        {
            var w = width < 1 ? 1 : width;
            var h = height < 1 ? 1 : height;
            _aspect = w / (float)h;
            GL.Viewport(0, 0, w, h);
        }
 
        /// <summary>
        /// 更新模型矩阵
        /// </summary>
        public void UpdateModelMatrix()
        {
            var center = (_vbx.Min + _vbx.Max) * 0.5f;
            _modelMatrix = Matrix4.CreateTranslation(-center);
        }
 
        /// <summary>
        /// 更新视图矩阵
        /// </summary>
        public void UpdateViewMatrix()
        {
            var center = (_vbx.Min + _vbx.Max) * 0.5f;
            var eye = center + new Vector3(0, 0, _baseSize + 0.1f);
 
            // 视图矩阵:将场景中心对齐到视口中心
            _viewMatrix = Matrix4.LookAt(
                eye,  // 摄像机位置
                Vector3.Zero,// 观察目标                   
                Vector3.UnitY); // 上方向               
        }
 
        //更新投影矩阵
        public void UpdateProjectionMatrix()
        {
            float width = _baseSize;
            float height = _baseSize;
            if (_aspect > 1)
            {
                width = _baseSize * _aspect;
            }
            else
            {
                height = _baseSize / _aspect;
            }
            width *= this.Zoom;
            height *= this.Zoom;
 
 
            // 设置正交投影矩阵
            _projectionMatrix = Matrix4.CreateOrthographic(
                width,
                height,
                0.1f,     // zNear
                _baseSize + 0.1f  // zFar (包含模型高度)
            );
        }
 
        #region 鼠标交互
 
        private Vector2 _lastMousePos;//最后一次鼠标位置
        private bool _isDragging = false;//是否增在拖动
        private bool _isRotating = false;//是否正在旋转
 
        /// <summary>
        /// 处理鼠标滚轮
        /// </summary>
        public void HandleMouseWheel(GLControl gl, MouseEventArgs e)
        {
            this.Zoom *= e.Delta > 0 ? 0.9f : 1.1f;
            UpdateProjectionMatrix();
            gl.Invalidate();
        }
 
        /// <summary>
        /// 处理鼠标按下
        /// </summary>
        public void HandleMouseDown(GLControl gl, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                _isDragging = true;
                _lastMousePos = new Vector2(e.X, e.Y);
                gl.Cursor = Cursors.SizeAll; // 修改光标样式
            }
            else if (e.Button == MouseButtons.Left)
            {
                _isRotating = true;
                _lastMousePos = new Vector2(e.X, e.Y);
                gl.Cursor = Cursors.SizeAll; // 修改光标样式
            }
        }
 
        /// <summary>
        /// 处理鼠标弹起
        /// </summary>
        public void HandleMouseUp(GLControl gl, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                _isDragging = false;
                gl.Cursor = Cursors.Default;
            }
            else if (e.Button == MouseButtons.Left)
            {
                _isRotating = false;
                gl.Cursor = Cursors.Default;
            }
        }
 
        /// <summary>
        /// 处理鼠标移动
        /// </summary>
        public void HandleMouseMove(GLControl gl, MouseEventArgs e)
        {
            if (_isDragging)
            {
                Vector2 currentPos = new Vector2(e.X, e.Y);
                Vector2 delta = currentPos - _lastMousePos;
                _lastMousePos = currentPos;
                // 计算平移量(Y轴方向需要反转)
                _translation.X += delta.X / this.Zoom;
                _translation.Y -= delta.Y / this.Zoom;
 
                gl.Invalidate();
            }
            else if (_isRotating)
            {
                Vector2 currentPos = new Vector2(e.X, e.Y);
                Vector2 delta = currentPos - _lastMousePos;
                _lastMousePos = currentPos;
                _rotation.X -= delta.Y;
                _rotation.Y += delta.X;
                _vbx = TransformBoundsToViewSpace(_wbx);
                _baseSize = CalcuBaseSize(_vbx);
                // UpdateModelMatrix();
                //UpdateViewMatrix();
                //UpdateProjectionMatrix();
                gl.Invalidate();
            }
        }
 
 
        #endregion
 
 
    }
}