lixiaojun
8 天以前 0329c48a57f33a4c94e44c5e4d3d3c116184986f
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
using System.Diagnostics;
using System.Windows.Threading;
 
namespace Yw.WpfUI.Hydro
{
    internal class LogicalFlowEffect3D : ModelVisual3D
    {
 
        public LogicalFlowEffect3D(LogicalLink3D link, LogicalMaterialHelper materialHelper)
        {
            _link = link;
            _materialHelper = materialHelper;
            this.Content = new Model3DGroup();
 
            InitializeParticles();
 
            _animationTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(16)
            };
        }
 
        private readonly LogicalMaterialHelper _materialHelper = null;
        private const int _max_particles = 500;//最大粒子数
        private readonly LogicalLink3D _link;//管段
        private readonly Random _random = new();//随机
        private readonly List<LogicalParticle3D> _particles = new(_max_particles);//粒子
        private readonly DispatcherTimer _animationTimer;//动画定时器
        private readonly Stopwatch _stopWatch = new();//秒表
 
        /// <summary>
        /// 流速
        /// </summary>
        public double FlowRate { get; set; } = 1.0;
 
        /// <summary>
        /// 湍流
        /// </summary>
        public double Turbulence { get; set; } = 0.3;
 
        /// <summary>
        /// 是否运行
        /// </summary>
        public bool IsRunning { get; private set; }
 
        #region 基础方法
 
        //计算最优粒子数量
        private int CalculateOptimalParticleCount()
        {
            var diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var length = (_link.EndPosition - _link.StartPosition).Length;
            double volume = Math.PI * Math.Pow(diameter / 2, 2) * length;
            int count = (int)(volume * 0.3);
            return Math.Clamp(count, 20, _max_particles);
        }
 
        //计算粒子尺寸
        private double CalculateParticleSize()
        {
            var diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var length = (_link.EndPosition - _link.StartPosition).Length;
            return diameter * (_random.NextDouble() * 0.3 + 0.2);
        }
 
        //应用湍流
        private Point3D ApplyTurbulence(Point3D position, Vector3D velocity)
        {
            double diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            var normal1 = Vector3D.CrossProduct(velocity, new Vector3D(0, 0, 1));
            var normal2 = Vector3D.CrossProduct(velocity, normal1);
            double turbulence = Turbulence * diameter;
            //position += normal1 * (_random.NextDouble() - 0.5) * turbulence;
            //position += normal2 * (_random.NextDouble() - 0.5) * turbulence;
            return position;
        }
 
        //获取沿着管段的点
        private Point3D GetPointAlongLink(double t)
        {
            return new Point3D(
                _link.EndPosition.X + t * (_link.EndPosition.X - _link.StartPosition.X),
                _link.StartPosition.Y + t * (_link.EndPosition.Y - _link.StartPosition.Y),
                _link.StartPosition.Z + t * (_link.EndPosition.Z - _link.StartPosition.Z));
        }
 
        //获取基础速度
        private Vector3D GetBaseVelocity()
        {
            var direction = _link.EndPosition - _link.StartPosition;
            direction.Normalize();
            return direction;
        }
 
        //是否管段外部
        private bool IsOutsideLink(Point3D point)
        {
            var linkVec = _link.EndPosition - _link.StartPosition;
            var pointVec = point - _link.StartPosition;
 
            double dot = Vector3D.DotProduct(linkVec, pointVec);
            if (dot < 0 || dot > linkVec.LengthSquared)
            {
                return true;
            }
            double diameter = Yw.Settings.HydroL3dParasHelper.HydroL3d.Logical.Link.Normal.Diameter;
            double distance = (pointVec - linkVec * (dot / linkVec.LengthSquared)).Length;
            return distance > diameter * 0.6;
        }
 
        //重置粒子
        private void ResetParticle(LogicalParticle3D particle)
        {
            double t = _random.NextDouble();
            particle.Position = GetPointAlongLink(t);
            particle.Velocity = GetBaseVelocity() * (_random.NextDouble() * 0.4 + 0.8);
            particle.Age = 0;
 
            var position = particle.Position;
            particle.Position = ApplyTurbulence(position, particle.Velocity);
            particle.Update();
        }
 
        #endregion
 
 
        //初始化粒子
        private void InitializeParticles()
        {
            var modelGroup = (Model3DGroup)this.Content;
            modelGroup.Children.Clear();
 
            int particleCount = CalculateOptimalParticleCount();
 
            for (int i = 0; i < particleCount; i++)
            {
                var particle = new LogicalParticle3D(_materialHelper);
                particle.Position = _link.StartPosition;
                particle.Size = CalculateParticleSize();
                particle.Color = Colors.Green;
                particle.Lifetime = _random.NextDouble() * 10 + 5;
                particle.Age = _random.NextDouble() * 10;
                ResetParticle(particle);
                _particles.Add(particle);
                modelGroup.Children.Add(particle.Content);
            }
        }
 
 
        /// <summary>
        /// 开始动画
        /// </summary>
        public void Play()
        {
            if (IsRunning)
            {
                return;
            }
            _animationTimer.Tick += OnAnimationFrame;
            _animationTimer.Start();
            _stopWatch.Start();
            this.IsRunning = true;
        }
 
        /// <summary>
        /// 停止动画
        /// </summary>
        public void Stop()
        {
            if (!IsRunning)
            {
                return;
            }
            _animationTimer.Tick -= OnAnimationFrame;
            _animationTimer.Stop();
            _stopWatch.Stop();
            this.IsRunning = false;
        }
 
        private void OnAnimationFrame(object sender, EventArgs e)
        {
            double deltaTime = _stopWatch.Elapsed.TotalSeconds;
            _stopWatch.Restart();
 
            double speedFactor = this.FlowRate * deltaTime * 2;
 
            foreach (var particle in _particles)
            {
                particle.Age += deltaTime;
                if (particle.Age > particle.Lifetime)
                {
                    ResetParticle(particle);
                    continue;
                }
 
                particle.Position += particle.Velocity * speedFactor;
 
                if (IsOutsideLink(particle.Position))
                {
                    ResetParticle(particle);
                    continue;
                }
 
                if (_random.NextDouble() < 0.1)
                {
                    particle.Position = ApplyTurbulence(particle.Position, particle.Velocity);
                }
 
                particle.Update();
            }
        }
 
    }
 
 
}