source: 2014/24/EemeliK/Zombieland/Jypeli/Physics2DDotNet/PhysicsLogics/LineFluidLogic.cs @ 5974

Revision 5974, 9.9 KB checked in by empaheik, 5 years ago (diff)
Line 
1#region MIT License
2/*
3 * Copyright (c) 2005-2008 Jonathan Mark Porter. http://physics2d.googlepages.com/
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
17 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22#endregion
23
24
25#if UseDouble
26using Scalar = System.Double;
27#else
28using Scalar = System.Single;
29#endif
30using System;
31using System.Collections.Generic;
32
33using AdvanceMath;
34using AdvanceMath.Geometry2D;
35using Physics2DDotNet.Shapes;
36
37namespace Physics2DDotNet.PhysicsLogics
38{
39    /// <summary>
40    /// Applys drag and buoyancy to items on one side of a line;
41    /// </summary>
42    public sealed class LineFluidLogic : PhysicsLogic
43    {
44        sealed class Wrapper : IDisposable
45        {
46            public Body body;
47            public ILineFluidAffectable affectable;
48            public Wrapper(Body body)
49            {
50                this.body = body;
51                this.body.ShapeChanged += OnShapeChanged;
52                this.Calculate();
53            }
54            void Calculate()
55            {
56                affectable = body.Shape as ILineFluidAffectable;
57            }
58            void OnShapeChanged(object sender, EventArgs e)
59            {
60                Calculate();
61            }
62            public void Dispose()
63            {
64                this.body.ShapeChanged -= OnShapeChanged;
65            }
66        }
67        static bool IsRemoved(Wrapper wrapper)
68        {
69            if (!wrapper.body.IsAdded)
70            {
71                wrapper.Dispose();
72                return true;
73            }
74            return false;
75        }
76        Scalar dragCoefficient;
77        Scalar density;
78        Vector2D fluidVelocity;
79        Line line;
80
81        List<Wrapper> items;
82
83
84        public LineFluidLogic(
85            Line line,
86            Scalar dragCoefficient,
87            Scalar density,
88            Vector2D fluidVelocity,
89            Lifespan lifetime)
90            : base(lifetime)
91        {
92            this.line = line;
93            this.dragCoefficient = dragCoefficient;
94            this.density = density;
95            this.fluidVelocity = fluidVelocity;
96            this.Order = 1;
97            this.items = new List<Wrapper>();
98        }
99
100        public Scalar DragCoefficient
101        {
102            get { return dragCoefficient; }
103            set { dragCoefficient = value; }
104        }
105        public Scalar Density
106        {
107            get { return density; }
108            set { density = value; }
109        }
110        public Vector2D FluidVelocity
111        {
112            get { return fluidVelocity; }
113            set { fluidVelocity = value; }
114        }
115
116        protected internal override void RunLogic(TimeStep step)
117        {
118            for (int index = 0; index < items.Count; ++index)
119            {
120                Wrapper wrapper = items[index];
121                Body body = wrapper.body;
122
123                if (wrapper.affectable == null ||
124                     body.IgnoresPhysicsLogics ||
125                   Scalar.IsPositiveInfinity(body.Mass.Mass))
126                {
127                    continue;
128                }
129                IShape shape = body.Shape;
130                int isInsideCount = 0;
131                foreach (Vector2D corner in body.Rectangle.Corners())
132                {
133                    Scalar distance = line.GetDistance(corner);
134                    if (distance <= 0)
135                    {
136                        isInsideCount++;
137                    }
138                }
139                if (isInsideCount == 0) { continue; }
140
141                if (isInsideCount != 4)
142                {
143                    Vector2D relativeVelocity = Vector2D.Zero;
144                    Vector2D velocityDirection  = Vector2D.Zero;
145                    Vector2D dragDirection = Vector2D.Zero;
146                    Vector2D centroid = Vector2D.Zero;
147                   
148                   
149                    Line bodyLine;
150                    Line.Transform(ref body.Matrices.ToBody, ref line, out bodyLine);
151
152
153                    GetTangentCallback callback = delegate(Vector2D centTemp)
154                    {
155                        centroid = body.Matrices.ToWorldNormal * centTemp;
156                        PhysicsHelper.GetRelativeVelocity(ref body.State.Velocity, ref centroid, out relativeVelocity);
157                        relativeVelocity = FluidVelocity - relativeVelocity;
158                        velocityDirection = relativeVelocity.Normalized;
159                        dragDirection = body.Matrices.ToBodyNormal * velocityDirection.LeftHandNormal;
160                        return dragDirection;
161                    };
162
163                    FluidInfo lineInfo = wrapper.affectable.GetFluidInfo(callback, bodyLine);
164                    if (lineInfo == null) { continue; }
165                  //  Vector2D centTemp = lineInfo.Centroid;
166                    Scalar areaTemp = lineInfo.Area;
167                  //  Vector2D centroid = body.Matrices.ToWorldNormal * centTemp;
168                    Vector2D buoyancyForce = body.State.Acceleration.Linear * areaTemp * -Density;
169                    body.ApplyForce(buoyancyForce, centroid);
170
171
172/*
173                    PhysicsHelper.GetRelativeVelocity(ref body.State.Velocity, ref centroid, out relativeVelocity);
174                    relativeVelocity =  FluidVelocity-relativeVelocity;
175                    velocityDirection = relativeVelocity.Normalized;
176                    dragDirection = body.Matrices.ToBodyNormal * velocityDirection.LeftHandNormal;
177
178                    lineInfo = wrapper.affectable.GetFluidInfo(dragDirection, bodyLine);
179                    if (lineInfo == null) { continue; }*/
180
181                    Scalar speedSq = relativeVelocity.MagnitudeSq;
182                    Scalar dragForceMag = -.5f * Density * speedSq * lineInfo.DragArea * DragCoefficient;
183                    Scalar maxDrag = -MathHelper.Sqrt(speedSq) * body.Mass.Mass * step.DtInv;
184                    if (dragForceMag < maxDrag)
185                    {
186                        dragForceMag = maxDrag;
187                    }
188
189                    Vector2D dragForce = dragForceMag * velocityDirection;
190                    body.ApplyForce(dragForce, body.Matrices.ToWorldNormal * lineInfo.DragCenter);
191
192                    body.ApplyTorque(
193                       -body.Mass.MomentOfInertia *
194                       (body.Coefficients.DynamicFriction + Density + DragCoefficient) *
195                       body.State.Velocity.Angular);
196                }
197                else
198                {
199
200                    Vector2D relativeVelocity = body.State.Velocity.Linear - FluidVelocity;
201                    Vector2D velocityDirection = relativeVelocity.Normalized;
202                    Vector2D dragDirection = body.Matrices.ToBodyNormal * velocityDirection.LeftHandNormal;
203
204                    Vector2D centroid = wrapper.body.Matrices.ToWorldNormal * wrapper.affectable.Centroid;
205                    Vector2D buoyancyForce = body.State.Acceleration.Linear * wrapper.affectable.Area * -Density;
206                    wrapper.body.ApplyForce(buoyancyForce, centroid);
207                    if (velocityDirection == Vector2D.Zero) { continue; }
208
209                    DragInfo dragInfo = wrapper.affectable.GetFluidInfo(dragDirection);
210                    if (dragInfo.DragArea < .01f) { continue; }
211                    Scalar speedSq = relativeVelocity.MagnitudeSq;
212                    Scalar dragForceMag = -.5f * Density * speedSq * dragInfo.DragArea * DragCoefficient;
213                    Scalar maxDrag = -MathHelper.Sqrt(speedSq) * body.Mass.Mass * step.DtInv;
214                    if (dragForceMag < maxDrag)
215                    {
216                        dragForceMag = maxDrag;
217                    }
218
219                    Vector2D dragForce = dragForceMag * velocityDirection;
220                    wrapper.body.ApplyForce(dragForce, body.Matrices.ToWorldNormal * dragInfo.DragCenter);
221
222                    wrapper.body.ApplyTorque(
223                       -body.Mass.MomentOfInertia *
224                       (body.Coefficients.DynamicFriction + Density + DragCoefficient) *
225                       body.State.Velocity.Angular);
226                }
227            }
228        }
229
230        protected internal override void RemoveExpiredBodies()
231        {
232            items.RemoveAll(IsRemoved);
233        }
234        protected internal override void AddBodyRange(List<Body> collection)
235        {
236            int newCapacity = collection.Count + items.Count;
237            if (items.Capacity < newCapacity)
238            {
239                items.Capacity = newCapacity;
240            }
241            for (int index = 0; index < collection.Count; ++index)
242            {
243                items.Add(new Wrapper(collection[index]));
244            }
245        }
246        protected internal override void Clear()
247        {
248            for (int index = 0; index < items.Count; ++index)
249            {
250                items[index].Dispose();
251            }
252            items.Clear();
253        }
254    }
255
256}
Note: See TracBrowser for help on using the repository browser.