예제 #1
0
        public void Sweep()
        {
            // From issue #447
            Sweep sweep = new Sweep();

            sweep.LocalCenter.SetZero();
            sweep.C0.Set(-2.0f, 4.0f);
            sweep.C.Set(3.0f, 8.0f);
            sweep.A0     = 0.5f;
            sweep.A      = 5.0f;
            sweep.Alpha0 = 0.0f;

            Transform transform;

            sweep.GetTransform(out transform, 0.0f);
            transform.Position.X.ShouldBe(sweep.C0.X);
            transform.Position.Y.ShouldBe(sweep.C0.Y);
            transform.Rotation.Cos.ShouldBe((float)Math.Cos(sweep.A0));
            transform.Rotation.Sin.ShouldBe((float)Math.Sin(sweep.A0));

            sweep.GetTransform(out transform, 1.0f);
            transform.Position.X.ShouldBe(sweep.C.X);
            transform.Position.Y.ShouldBe(sweep.C.Y);
            transform.Rotation.Cos.ShouldBe((float)Math.Cos(sweep.A));
            transform.Rotation.Sin.ShouldBe((float)Math.Sin(sweep.A));
        }
예제 #2
0
        public override void Step(Settings settings)
        {
            settings.pause = 1;
            base.Step(settings);
            settings.pause = 0;

            Sweep sweep1 = new Sweep();

            sweep1.C0.Set(0.0f, 20.0f);
            sweep1.A0          = 0.0f;
            sweep1.C           = sweep1.C0;
            sweep1.A           = sweep1.A0;
            sweep1.T0          = 0.0f;
            sweep1.LocalCenter = _body1.GetLocalCenter();

            Sweep sweep2 = new Sweep();

            sweep2.C0.Set(9.6363468f, 28.050615f);
            sweep2.A0          = 1.6408679f;
            sweep2.C           = sweep2.C0 + new Vec2(-0.075121880f, 0.27358246f);
            sweep2.A           = sweep2.A0 - 10.434675f;
            sweep2.T0          = 0.0f;
            sweep2.LocalCenter = _body2.GetLocalCenter();
            TOIInput input = new TOIInput
            {
                SweepA = sweep1,
                SweepB = sweep2
            };
            float toi = Collision.TimeOfImpact(input, _shape1, _shape2);

            OpenGLDebugDraw.DrawString(5, _textLine, "toi = " + toi.ToString());
            _textLine += 15;

            XForm xf2 = new XForm();

            sweep2.GetTransform(out xf2, toi);
            int vertexCount = _shape2.VertexCount;

            Vec2[] vertices      = new Vec2[Box2DNet.Common.Settings.MaxPolygonVertices];
            Vec2[] localVertices = _shape2.Vertices;
            for (int i = 0; i < vertexCount; ++i)
            {
                vertices[i] = Box2DNet.Common.Math.Mul(xf2, localVertices[i]);
            }
            _debugDraw.DrawPolygon(vertices, vertexCount, new Color(0.5f, 0.7f, 0.9f));

            localVertices = _shape2.CoreVertices;
            for (int i = 0; i < vertexCount; ++i)
            {
                vertices[i] = Box2DNet.Common.Math.Mul(xf2, localVertices[i]);
            }
            _debugDraw.DrawPolygon(vertices, vertexCount, new Color(0.5f, 0.7f, 0.9f));
        }
예제 #3
0
        public void SweepGetTransform()
        {
            // From issue https://github.com/erincatto/box2d/issues/447
            Sweep sweep = new Sweep();

            sweep.LocalCenter = Vector2.Zero;
            sweep.C0          = new Vector2(-2.0f, 4.0f);
            sweep.C           = new Vector2(3.0f, 8.0f);
            sweep.A0          = 0.5f;
            sweep.A           = 5.0f;
            sweep.Alpha0      = 0.0f;

            sweep.GetTransform(out Transform transform, 0.0f);
            Assert.Equal(transform.p.X, sweep.C0.X);
            Assert.Equal(transform.p.Y, sweep.C0.Y);
            Assert.Equal(transform.q.c, (float)Math.Cos(sweep.A0));
            Assert.Equal(transform.q.s, (float)Math.Sin(sweep.A0));

            sweep.GetTransform(out transform, 1.0f);
            Assert.Equal(transform.p.X, sweep.C.X);
            Assert.Equal(transform.p.Y, sweep.C.Y);
            Assert.Equal(transform.q.c, (float)Math.Cos(sweep.A));
            Assert.Equal(transform.q.s, (float)Math.Sin(sweep.A));
        }
예제 #4
0
        public override void Step(TestSettings settings)
        {
            base.Step(settings);

            Sweep sweepA = new Sweep();

            sweepA.c0.Set(24.0f, -60.0f);
            sweepA.a0 = 2.95f;
            sweepA.c  = sweepA.c0;
            sweepA.a  = sweepA.a0;
            sweepA.localCenter.SetZero();

            Sweep sweepB = new Sweep();

            sweepB.c0.Set(53.474274f, -50.252514f);
            sweepB.a0 = 513.36676f;            // - 162.0f * (float)Math.PI;
            sweepB.c.Set(54.595478f, -51.083473f);
            sweepB.a = 513.62781f;             //  - 162.0f * (float)Math.PI;
            sweepB.localCenter.SetZero();

            //sweepB.a0 -= 300.0f * (float)Math.PI;
            //sweepB.a -= 300.0f * (float)Math.PI;

            TOIInput input = new TOIInput();

            input.proxyA.Set(m_shapeA, 0);
            input.proxyB.Set(m_shapeB, 0);
            input.sweepA = sweepA;
            input.sweepB = sweepB;
            input.tMax   = 1.0f;

            TOIOutput output;

            Utilities.TimeOfImpact(out output, input);

            m_debugDraw.DrawString("toi = {0}", output.t);

            m_debugDraw.DrawString("max toi iters = {0}, max root iters = {1}", Utilities._toiMaxIters, Utilities._toiMaxRootIters);

            Vec2[] vertices = new Vec2[Settings._maxPolygonVertices];

            Transform transformA;

            sweepA.GetTransform(out transformA, 0.0f);
            for (int i = 0; i < m_shapeA.m_count; ++i)
            {
                vertices[i] = Utilities.Mul(transformA, m_shapeA.m_vertices[i]);
            }
            m_debugDraw.DrawPolygon(vertices, m_shapeA.m_count, Color.FromArgb(225, 225, 225));

            Transform transformB;

            sweepB.GetTransform(out transformB, 0.0f);

            //Vec2 localPoint(2.0f, -0.1f);

            for (int i = 0; i < m_shapeB.m_count; ++i)
            {
                vertices[i] = Utilities.Mul(transformB, m_shapeB.m_vertices[i]);
            }
            m_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, Color.FromArgb(128, 225, 128));

            sweepB.GetTransform(out transformB, output.t);
            for (int i = 0; i < m_shapeB.m_count; ++i)
            {
                vertices[i] = Utilities.Mul(transformB, m_shapeB.m_vertices[i]);
            }
            m_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, Color.FromArgb(128, 175, 225));

            sweepB.GetTransform(out transformB, 1.0f);
            for (int i = 0; i < m_shapeB.m_count; ++i)
            {
                vertices[i] = Utilities.Mul(transformB, m_shapeB.m_vertices[i]);
            }
            m_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, Color.FromArgb(225, 128, 128));

        #if ZERO
            for (float t = 0.0f; t < 1.0f; t += 0.1f)
            {
                sweepB.GetTransform(out transformB, t);
                for (int i = 0; i < m_shapeB.m_count; ++i)
                {
                    vertices[i] = Utilities.Mul(transformB, m_shapeB.m_vertices[i]);
                }
                m_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, Color.FromArgb(225, 0.5f, 0.5f));
            }
        #endif
        }
예제 #5
0
        public static void Set(ref SimplexCache cache, DistanceProxy proxyA, ref Sweep sweepA, DistanceProxy proxyB, ref Sweep sweepB, float t1)
        {
            _localPoint = Vector2.Zero;
            _proxyA     = proxyA;
            _proxyB     = proxyB;
            int count = cache.Count;

            Debug.Assert(0 < count && count < 3);

            _sweepA = sweepA;
            _sweepB = sweepB;

            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t1);
            _sweepB.GetTransform(out xfB, t1);

            if (count == 1)
            {
                _type = SeparationFunctionType.Points;
                Vector2 localPointA = _proxyA.Vertices[cache.IndexA[0]];
                Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
                Vector2 pointA      = MathUtils.Mul(ref xfA, localPointA);
                Vector2 pointB      = MathUtils.Mul(ref xfB, localPointB);
                _axis = pointB - pointA;
                _axis.Normalize();
            }
            else if (cache.IndexA[0] == cache.IndexA[1])
            {
                // Two points on B and one on A.
                _type = SeparationFunctionType.FaceB;
                Vector2 localPointB1 = proxyB.Vertices[cache.IndexB[0]];
                Vector2 localPointB2 = proxyB.Vertices[cache.IndexB[1]];

                Vector2 a = localPointB2 - localPointB1;
                _axis = new Vector2(a.Y, -a.X);
                _axis.Normalize();
                Vector2 normal = MathUtils.Mul(ref xfB.q, _axis);

                _localPoint = 0.5f * (localPointB1 + localPointB2);
                Vector2 pointB = MathUtils.Mul(ref xfB, _localPoint);

                Vector2 localPointA = proxyA.Vertices[cache.IndexA[0]];
                Vector2 pointA      = MathUtils.Mul(ref xfA, localPointA);

                float s = Vector2.Dot(pointA - pointB, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                }
            }
            else
            {
                // Two points on A and one or two points on B.
                _type = SeparationFunctionType.FaceA;
                Vector2 localPointA1 = _proxyA.Vertices[cache.IndexA[0]];
                Vector2 localPointA2 = _proxyA.Vertices[cache.IndexA[1]];

                Vector2 a = localPointA2 - localPointA1;
                _axis = new Vector2(a.Y, -a.X);
                _axis.Normalize();
                Vector2 normal = MathUtils.Mul(ref xfA.q, _axis);

                _localPoint = 0.5f * (localPointA1 + localPointA2);
                Vector2 pointA = MathUtils.Mul(ref xfA, _localPoint);

                Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
                Vector2 pointB      = MathUtils.Mul(ref xfB, localPointB);

                float s = Vector2.Dot(pointB - pointA, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                }
            }

            //FPE note: the returned value that used to be here has been removed, as it was not used.
        }
예제 #6
0
        public override void Step(Framework.Settings settings)
        {
            base.Step(settings);

            Sweep sweepA = new Sweep();

            sweepA.c0          = new Vector2(24.0f, -60.0f);
            sweepA.a0          = 2.95f;
            sweepA.c           = sweepA.c0;
            sweepA.a           = sweepA.a0;
            sweepA.localCenter = Vector2.Zero;

            Sweep sweepB = new Sweep();

            sweepB.c0          = new Vector2(53.474274f, -50.252514f);
            sweepB.a0          = 513.36676f;
            sweepB.c           = new Vector2(54.595478f, -51.083473f);
            sweepB.a           = 513.62781f;
            sweepB.localCenter = Vector2.Zero;

            TOIInput input = new TOIInput();

            input.proxyA.Set(_shapeA, 0);
            input.proxyB.Set(_shapeB, 0);
            input.sweepA = sweepA;
            input.sweepB = sweepB;
            input.tMax   = 1.0f;

            TOIOutput output;

            Alt.Box2D.TimeOfImpact.CalculateTimeOfImpact(out output, ref input);

            _debugDraw.DrawString(50, _textLine, "toi = {0:n}", output.t);
            _textLine += 15;

            _debugDraw.DrawString(50, _textLine, "max toi iters = {0:n}, max root iters = {1:n}", Alt.Box2D.TimeOfImpact.b2_toiMaxIters, Alt.Box2D.TimeOfImpact.b2_toiMaxRootIters);
            _textLine += 15;

            FixedArray8 <Vector2> vertices = new FixedArray8 <Vector2>();

            Alt.Box2D.Transform transformA;
            sweepA.GetTransform(out transformA, 0.0f);
            for (int i = 0; i < _shapeA._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformA, _shapeA._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeA._vertexCount, new ColorR(0.9, 0.9, 0.9));

            Alt.Box2D.Transform transformB;
            sweepB.GetTransform(out transformB, 0.0f);

            //NoNeed	Vector2 localPoint = new Vector2(2.0f, -0.1f);
            //NoNeed	Vector2 rB = MathUtils.Multiply(ref transformB, localPoint) - sweepB.c0;
            //NoNeed	double wB = sweepB.a - sweepB.a0;
            //NoNeed	Vector2 vB = sweepB.c - sweepB.c0;
            //Vector2 v = vB + MathUtils.Cross(wB, rB);

            for (int i = 0; i < _shapeB._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new ColorR(0.5, 0.9, 0.5));

            sweepB.GetTransform(out transformB, output.t);
            for (int i = 0; i < _shapeB._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new ColorR(0.5f, 0.7f, 0.9f));

            sweepB.GetTransform(out transformB, 1.0f);
            for (int i = 0; i < _shapeB._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new ColorR(0.9, 0.5, 0.5));
        }
예제 #7
0
        public override void Update(GameSettings settings, GameTime gameTime)
        {
            base.Update(settings, gameTime);

            Sweep sweepA = new Sweep();
            sweepA.C0 = new Vector2(24.0f, -60.0f);
            sweepA.A0 = 2.95f;
            sweepA.C = sweepA.C0;
            sweepA.A = sweepA.A0;
            sweepA.LocalCenter = Vector2.Zero;

            Sweep sweepB = new Sweep();
            sweepB.C0 = new Vector2(53.474274f, -50.252514f);
            sweepB.A0 = 513.36676f; // - 162.0f * b2_pi;
            sweepB.C = new Vector2(54.595478f, -51.083473f);
            sweepB.A = 513.62781f; //  - 162.0f * b2_pi;
            sweepB.LocalCenter = Vector2.Zero;

            //sweepB.a0 -= 300.0f * b2_pi;
            //sweepB.a -= 300.0f * b2_pi;

            TOIInput input = new TOIInput();
            input.ProxyA.Set(_shapeA, 0);
            input.ProxyB.Set(_shapeB, 0);
            input.SweepA = sweepA;
            input.SweepB = sweepB;
            input.TMax = 1.0f;

            TOIOutput output;
            TimeOfImpact.CalculateTimeOfImpact(out output, input);

            DrawString("TOI = " + output.T);
            DrawString(string.Format("Max TOI iters = {0:n}, Max root iters = {1:n}", TimeOfImpact.TOIMaxIters, TimeOfImpact.TOIMaxRootIters));

            Vector2[] vertices = new Vector2[Settings.MaxPolygonVertices];

            DebugView.BeginCustomDraw(ref GameInstance.Projection, ref GameInstance.View);
            Transform transformA;
            sweepA.GetTransform(out transformA, 0.0f);
            for (int i = 0; i < _shapeA.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformA, _shapeA.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeA.Vertices.Count, new Color(0.9f, 0.9f, 0.9f));

            Transform transformB;
            sweepB.GetTransform(out transformB, 0.0f);

            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.5f, 0.9f, 0.5f));

            sweepB.GetTransform(out transformB, output.T);
            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.5f, 0.7f, 0.9f));

            sweepB.GetTransform(out transformB, 1.0f);
            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.9f, 0.5f, 0.5f));
            DebugView.EndCustomDraw();
        }
예제 #8
0
        /// <summary>
        /// Compute the upper bound on time before two shapes penetrate. Time is represented as
        /// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
        /// non-tunneling collision. If you change the time interval, you should call this function
        /// again.
        /// Note: use Distance() to compute the contact point and normal at the time of impact.
        /// </summary>
        /// <param name="output">The output.</param>
        /// <param name="input">The input.</param>
        public static void CalculateTimeOfImpact(out TOIOutput output, ref TOIInput input)
        {
            ++TOICalls;

            output       = new TOIOutput();
            output.State = TOIOutputState.Unknown;
            output.T     = input.TMax;

            Sweep sweepA = input.SweepA;
            Sweep sweepB = input.SweepB;

            // Large rotations can make the root finder fail, so we normalize the
            // sweep angles.
            sweepA.Normalize();
            sweepB.Normalize();

            float tMax = input.TMax;

            float       totalRadius = input.ProxyA.Radius + input.ProxyB.Radius;
            float       target      = Math.Max(Settings.LinearSlop, totalRadius - 3.0f * Settings.LinearSlop);
            const float tolerance   = 0.25f * Settings.LinearSlop;

            Debug.Assert(target > tolerance);

            float     t1 = 0.0f;
            const int k_maxIterations = 20;
            int       iter            = 0;

            // Prepare input for distance query.
            SimplexCache  cache;
            DistanceInput distanceInput;

            distanceInput.ProxyA   = input.ProxyA;
            distanceInput.ProxyB   = input.ProxyB;
            distanceInput.UseRadii = false;

            // The outer loop progressively attempts to compute new separating axes.
            // This loop terminates when an axis is repeated (no progress is made).
            for (;;)
            {
                Transform xfA, xfB;
                sweepA.GetTransform(out xfA, t1);
                sweepB.GetTransform(out xfB, t1);

                // Get the distance between shapes. We can also use the results
                // to get a separating axis.
                distanceInput.TransformA = xfA;
                distanceInput.TransformB = xfB;
                DistanceOutput distanceOutput;
                Distance.ComputeDistance(out distanceOutput, out cache, ref distanceInput);

                // If the shapes are overlapped, we give up on continuous collision.
                if (distanceOutput.Distance <= 0.0f)
                {
                    // Failure!
                    output.State = TOIOutputState.Overlapped;
                    output.T     = 0.0f;
                    break;
                }

                if (distanceOutput.Distance < target + tolerance)
                {
                    // Victory!
                    output.State = TOIOutputState.Touching;
                    output.T     = t1;
                    break;
                }

                SeparationFunction fcn = new SeparationFunction(ref cache, ref input.ProxyA, ref sweepA,
                                                                ref input.ProxyB, ref sweepB, t1);

                // Compute the TOI on the separating axis. We do this by successively
                // resolving the deepest point. This loop is bounded by the number of vertices.
                bool  done         = false;
                float t2           = tMax;
                int   pushBackIter = 0;
                for (;;)
                {
                    // Find the deepest point at t2. Store the witness point indices.
                    int   indexA, indexB;
                    float s2 = fcn.FindMinSeparation(out indexA, out indexB, t2);

                    // Is the final configuration separated?
                    if (s2 > target + tolerance)
                    {
                        // Victory!
                        output.State = TOIOutputState.Seperated;
                        output.T     = tMax;
                        done         = true;
                        break;
                    }

                    // Has the separation reached tolerance?
                    if (s2 > target - tolerance)
                    {
                        // Advance the sweeps
                        t1 = t2;
                        break;
                    }

                    // Compute the initial separation of the witness points.
                    float s1 = fcn.Evaluate(indexA, indexB, t1);

                    // Check for initial overlap. This might happen if the root finder
                    // runs out of iterations.
                    if (s1 < target - tolerance)
                    {
                        output.State = TOIOutputState.Failed;
                        output.T     = t1;
                        done         = true;
                        break;
                    }

                    // Check for touching
                    if (s1 <= target + tolerance)
                    {
                        // Victory! t1 should hold the TOI (could be 0.0).
                        output.State = TOIOutputState.Touching;
                        output.T     = t1;
                        done         = true;
                        break;
                    }

                    // Compute 1D root of: f(x) - target = 0
                    int   rootIterCount = 0;
                    float a1 = t1, a2 = t2;
                    for (;;)
                    {
                        // Use a mix of the secant rule and bisection.
                        float t;
                        if ((rootIterCount & 1) != 0)
                        {
                            // Secant rule to improve convergence.
                            t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
                        }
                        else
                        {
                            // Bisection to guarantee progress.
                            t = 0.5f * (a1 + a2);
                        }

                        float s = fcn.Evaluate(indexA, indexB, t);

                        if (Math.Abs(s - target) < tolerance)
                        {
                            // t2 holds a tentative value for t1
                            t2 = t;
                            break;
                        }

                        // Ensure we continue to bracket the root.
                        if (s > target)
                        {
                            a1 = t;
                            s1 = s;
                        }
                        else
                        {
                            a2 = t;
                            s2 = s;
                        }

                        ++rootIterCount;
                        ++TOIRootIters;

                        if (rootIterCount == 50)
                        {
                            break;
                        }
                    }

                    TOIMaxRootIters = Math.Max(TOIMaxRootIters, rootIterCount);

                    ++pushBackIter;

                    if (pushBackIter == Settings.MaxPolygonVertices)
                    {
                        break;
                    }
                }

                ++iter;
                ++TOIIters;

                if (done)
                {
                    break;
                }

                if (iter == k_maxIterations)
                {
                    // Root finder got stuck. Semi-victory.
                    output.State = TOIOutputState.Failed;
                    output.T     = t1;
                    break;
                }
            }

            TOIMaxIters = Math.Max(TOIMaxIters, iter);
        }
예제 #9
0
        // CCD via the secant method.
        /// <summary>
        /// Compute the time when two shapes begin to touch or touch at a closer distance.
        /// TOI considers the shape radii. It attempts to have the radii overlap by the tolerance.
        /// Iterations terminate with the overlap is within 0.5 * tolerance. The tolerance should be
        /// smaller than sum of the shape radii.
        /// Warning the sweeps must have the same time interval.
        /// </summary>
        /// <returns>
        /// The fraction between [0,1] in which the shapes first touch.
        /// fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch.
        /// </returns>
        public static float TimeOfImpact(TOIInput input, Shape shapeA, Shape shapeB)
        {
            Sweep sweepA = input.SweepA;
            Sweep sweepB = input.SweepB;

            Box2DNetDebug.Assert(sweepA.T0 == sweepB.T0);
            Box2DNetDebug.Assert(1.0f - sweepA.T0 > Common.Settings.FLT_EPSILON);

            float radius    = shapeA._radius + shapeB._radius;
            float tolerance = input.Tolerance;

            float alpha = 0.0f;

            const int k_maxIterations = 1000;                   // TODO_ERIN b2Settings
            int       iter            = 0;
            float     target          = 0.0f;

            // Prepare input for distance query.
            SimplexCache cache = new SimplexCache {
                Count = 0
            };
            DistanceInput distanceInput;

            distanceInput.UseRadii = false;

            for (; ;)
            {
                XForm xfA, xfB;
                sweepA.GetTransform(out xfA, alpha);
                sweepB.GetTransform(out xfB, alpha);

                // Get the distance between shapes.
                distanceInput.TransformA = xfA;
                distanceInput.TransformB = xfB;
                DistanceOutput distanceOutput;
                Distance(out distanceOutput, ref cache, ref distanceInput, shapeA, shapeB);

                if (distanceOutput.Distance <= 0.0f)
                {
                    alpha = 1.0f;
                    break;
                }

                SeparationFunction fcn = new SeparationFunction();
                unsafe
                {
                    fcn.Initialize(&cache, shapeA, xfA, shapeB, xfB);
                }

                float separation = fcn.Evaluate(xfA, xfB);
                if (separation <= 0.0f)
                {
                    alpha = 1.0f;
                    break;
                }

                if (iter == 0)
                {
                    // Compute a reasonable target distance to give some breathing room
                    // for conservative advancement. We take advantage of the shape radii
                    // to create additional clearance.
                    target = separation > radius?Common.Math.Max(radius - tolerance, 0.75f *radius) : Common.Math.Max(separation - tolerance, 0.02f * radius);
                }

                if (separation - target < 0.5f * tolerance)
                {
                    if (iter == 0)
                    {
                        alpha = 1.0f;
                        break;
                    }

                    break;
                }

#if _FALSE
                // Dump the curve seen by the root finder
                {
                    const int32 N  = 100;
                    float32     dx = 1.0f / N;
                    float32     xs[N + 1];
예제 #10
0
        public static void Set(ref SimplexCache cache, ref DistanceProxy proxyA, ref Sweep sweepA, ref DistanceProxy proxyB, ref Sweep sweepB, float t1)
        {
            _localPoint = Vector2.Zero;
            _proxyA     = proxyA;
            _proxyB     = proxyB;
            int count = cache.Count;

            Debug.Assert(0 < count && count < 3);

            _sweepA = sweepA;
            _sweepB = sweepB;

            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t1);
            _sweepB.GetTransform(out xfB, t1);

            if (count == 1)
            {
                _type = SeparationFunctionType.Points;
                Vector2 localPointA = _proxyA.Vertices[cache.IndexA[0]];
                Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
                Vector2 pointA      = Transform.Multiply(ref localPointA, ref xfA);
                Vector2 pointB      = Transform.Multiply(ref localPointB, ref xfB);
                _axis = pointB - pointA;
                _axis.Normalize();
            }
            else if (cache.IndexA[0] == cache.IndexA[1])
            {
                // Two points on B and one on A.
                _type = SeparationFunctionType.FaceB;
                Vector2 localPointB1 = proxyB.Vertices[cache.IndexB[0]];
                Vector2 localPointB2 = proxyB.Vertices[cache.IndexB[1]];

                Vector2 a = localPointB2 - localPointB1;
                _axis = new Vector2(a.Y, -a.X);
                _axis.Normalize();
                Vector2 normal = Complex.Multiply(ref _axis, ref xfB.q);

                _localPoint = 0.5f * (localPointB1 + localPointB2);
                Vector2 pointB = Transform.Multiply(ref _localPoint, ref xfB);

                Vector2 localPointA = proxyA.Vertices[cache.IndexA[0]];
                Vector2 pointA      = Transform.Multiply(ref localPointA, ref xfA);

                float s = Vector2.Dot(pointA - pointB, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                }
            }
            else
            {
                // Two points on A and one or two points on B.
                _type = SeparationFunctionType.FaceA;
                Vector2 localPointA1 = _proxyA.Vertices[cache.IndexA[0]];
                Vector2 localPointA2 = _proxyA.Vertices[cache.IndexA[1]];

                Vector2 a = localPointA2 - localPointA1;
                _axis = new Vector2(a.Y, -a.X);
                _axis.Normalize();
                Vector2 normal = Complex.Multiply(ref _axis, ref xfA.q);

                _localPoint = 0.5f * (localPointA1 + localPointA2);
                Vector2 pointA = Transform.Multiply(ref _localPoint, ref xfA);

                Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
                Vector2 pointB      = Transform.Multiply(ref localPointB, ref xfB);

                float s = Vector2.Dot(pointB - pointA, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                }
            }
        }
예제 #11
0
        // TODO_ERIN might not need to return the separation

        public float Initialize(Distance.SimplexCache cache, Distance.DistanceProxy proxyA, Sweep sweepA, Distance.DistanceProxy proxyB, Sweep sweepB, float t1)
        {
            ProxyA = proxyA;
            ProxyB = proxyB;
            int count = cache.Count;

            Debug.Assert(0 < count && count < 3);

            SweepA = sweepA;
            SweepB = sweepB;

            SweepA.GetTransform(xfa, t1);
            SweepB.GetTransform(xfb, t1);

            // log.debug("initializing separation.\n" +
            // "cache: "+cache.count+"-"+cache.metric+"-"+cache.indexA+"-"+cache.indexB+"\n"
            // "distance: "+proxyA.

            if (count == 1)
            {
                Type = Type.Points;

                /*
                 * Vec2 localPointA = m_proxyA.GetVertex(cache.indexA[0]); Vec2 localPointB =
                 * m_proxyB.GetVertex(cache.indexB[0]); Vec2 pointA = Mul(transformA, localPointA); Vec2
                 * pointB = Mul(transformB, localPointB); m_axis = pointB - pointA; m_axis.Normalize();
                 */
                localPointA.Set(ProxyA.GetVertex(cache.IndexA[0]));
                localPointB.Set(ProxyB.GetVertex(cache.IndexB[0]));
                Transform.MulToOutUnsafe(xfa, localPointA, pointA);
                Transform.MulToOutUnsafe(xfb, localPointB, pointB);
                Axis.Set(pointB).SubLocal(pointA);
                float s = Axis.Normalize();
                return(s);
            }
            else if (cache.IndexA[0] == cache.IndexA[1])
            {
                // Two points on B and one on A.
                Type = Type.FaceB;

                localPointB1.Set(ProxyB.GetVertex(cache.IndexB[0]));
                localPointB2.Set(ProxyB.GetVertex(cache.IndexB[1]));

                temp.Set(localPointB2).SubLocal(localPointB1);
                Vec2.CrossToOutUnsafe(temp, 1f, Axis);
                Axis.Normalize();

                Rot.MulToOutUnsafe(xfb.Q, Axis, normal);

                LocalPoint.Set(localPointB1).AddLocal(localPointB2).MulLocal(.5f);
                Transform.MulToOutUnsafe(xfb, LocalPoint, pointB);

                localPointA.Set(proxyA.GetVertex(cache.IndexA[0]));
                Transform.MulToOutUnsafe(xfa, localPointA, pointA);

                temp.Set(pointA).SubLocal(pointB);
                float s = Vec2.Dot(temp, normal);
                if (s < 0.0f)
                {
                    Axis.NegateLocal();
                    s = -s;
                }
                return(s);
            }
            else
            {
                // Two points on A and one or two points on B.
                Type = Type.FaceA;

                localPointA1.Set(ProxyA.GetVertex(cache.IndexA[0]));
                localPointA2.Set(ProxyA.GetVertex(cache.IndexA[1]));

                temp.Set(localPointA2).SubLocal(localPointA1);
                Vec2.CrossToOutUnsafe(temp, 1.0f, Axis);
                Axis.Normalize();

                Rot.MulToOutUnsafe(xfa.Q, Axis, normal);

                LocalPoint.Set(localPointA1).AddLocal(localPointA2).MulLocal(.5f);
                Transform.MulToOutUnsafe(xfa, LocalPoint, pointA);

                localPointB.Set(ProxyB.GetVertex(cache.IndexB[0]));
                Transform.MulToOutUnsafe(xfb, localPointB, pointB);

                temp.Set(pointB).SubLocal(pointA);
                float s = Vec2.Dot(temp, normal);
                if (s < 0.0f)
                {
                    Axis.NegateLocal();
                    s = -s;
                }
                return(s);
            }
        }
예제 #12
0
        /// <summary>
        /// Compute the upper bound on time before two shapes penetrate. Time is represented as a fraction
        /// between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
        /// non-tunneling collision. If you change the time interval, you should call this function again.
        /// Note: use Distance to compute the contact point and normal at the time of impact.
        /// </summary>
        /// <param name="output"></param>
        /// <param name="input"></param>
        public void GetTimeOfImpact(TOIOutput output, TOIInput input)
        {
            // CCD via the local separating axis method. This seeks progression
            // by computing the largest time at which separation is maintained.

            ++ToiCalls;

            output.State = TOIOutputState.Unknown;
            output.T     = input.tMax;

            Distance.DistanceProxy proxyA = input.ProxyA;
            Distance.DistanceProxy proxyB = input.ProxyB;

            sweepA.Set(input.SweepA);
            sweepB.Set(input.SweepB);

            // Large rotations can make the root finder fail, so we normalize the
            // sweep angles.
            sweepA.Normalize();
            sweepB.Normalize();

            float tMax = input.tMax;

            float totalRadius = proxyA.Radius + proxyB.Radius;
            // djm: whats with all these constants?
            float       target    = MathUtils.Max(Settings.LINEAR_SLOP, totalRadius - 3.0f * Settings.LINEAR_SLOP);
            const float tolerance = 0.25f * Settings.LINEAR_SLOP;

            Debug.Assert(target > tolerance);

            float t1   = 0f;
            int   iter = 0;

            cache.Count            = 0;
            distanceInput.ProxyA   = input.ProxyA;
            distanceInput.ProxyB   = input.ProxyB;
            distanceInput.UseRadii = false;

            // The outer loop progressively attempts to compute new separating axes.
            // This loop terminates when an axis is repeated (no progress is made).
            for (; ;)
            {
                sweepA.GetTransform(xfA, t1);
                sweepB.GetTransform(xfB, t1);
                // System.out.printf("sweepA: %f, %f, sweepB: %f, %f\n",
                // sweepA.c.x, sweepA.c.y, sweepB.c.x, sweepB.c.y);
                // Get the distance between shapes. We can also use the results
                // to get a separating axis
                distanceInput.TransformA = xfA;
                distanceInput.TransformB = xfB;
                pool.GetDistance().GetDistance(distanceOutput, cache, distanceInput);

                // System.out.printf("Dist: %f at points %f, %f and %f, %f.  %d iterations\n",
                // distanceOutput.distance, distanceOutput.pointA.x, distanceOutput.pointA.y,
                // distanceOutput.pointB.x, distanceOutput.pointB.y,
                // distanceOutput.iterations);

                // If the shapes are overlapped, we give up on continuous collision.
                if (distanceOutput.Distance <= 0f)
                {
                    // System.out.println("failure, overlapped");
                    // Failure!
                    output.State = TOIOutputState.Overlapped;
                    output.T     = 0f;
                    break;
                }

                if (distanceOutput.Distance < target + tolerance)
                {
                    // System.out.println("touching, victory");
                    // Victory!
                    output.State = TOIOutputState.Touching;
                    output.T     = t1;
                    break;
                }

                // Initialize the separating axis.
                fcn.Initialize(cache, proxyA, sweepA, proxyB, sweepB, t1);

                // Compute the TOI on the separating axis. We do this by successively
                // resolving the deepest point. This loop is bounded by the number of
                // vertices.
                bool  done         = false;
                float t2           = tMax;
                int   pushBackIter = 0;
                for (; ;)
                {
                    // Find the deepest point at t2. Store the witness point indices.
                    float s2 = fcn.FindMinSeparation(indexes, t2);
                    // System.out.printf("s2: %f\n", s2);
                    // Is the final configuration separated?
                    if (s2 > target + tolerance)
                    {
                        // Victory!
                        // System.out.println("separated");
                        output.State = TOIOutputState.Separated;
                        output.T     = tMax;
                        done         = true;
                        break;
                    }

                    // Has the separation reached tolerance?
                    if (s2 > target - tolerance)
                    {
                        // System.out.println("advancing");
                        // Advance the sweeps
                        t1 = t2;
                        break;
                    }

                    // Compute the initial separation of the witness points.
                    float s1 = fcn.Evaluate(indexes[0], indexes[1], t1);
                    // Check for initial overlap. This might happen if the root finder
                    // runs out of iterations.
                    // System.out.printf("s1: %f, target: %f, tolerance: %f\n", s1, target,
                    // tolerance);
                    if (s1 < target - tolerance)
                    {
                        // System.out.println("failed?");
                        output.State = TOIOutputState.Failed;
                        output.T     = t1;
                        done         = true;
                        break;
                    }

                    // Check for touching
                    if (s1 <= target + tolerance)
                    {
                        // System.out.println("touching?");
                        // Victory! t1 should hold the TOI (could be 0.0).
                        output.State = TOIOutputState.Touching;
                        output.T     = t1;
                        done         = true;
                        break;
                    }

                    // Compute 1D root of: f(x) - target = 0
                    int   rootIterCount = 0;
                    float a1 = t1, a2 = t2;
                    for (; ;)
                    {
                        // Use a mix of the secant rule and bisection.
                        float t;
                        if ((rootIterCount & 1) == 1)
                        {
                            // Secant rule to improve convergence.
                            t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
                        }
                        else
                        {
                            // Bisection to guarantee progress.
                            t = 0.5f * (a1 + a2);
                        }

                        float s = fcn.Evaluate(indexes[0], indexes[1], t);

                        if (MathUtils.Abs(s - target) < tolerance)
                        {
                            // t2 holds a tentative value for t1
                            t2 = t;
                            break;
                        }

                        // Ensure we continue to bracket the root.
                        if (s > target)
                        {
                            a1 = t;
                            s1 = s;
                        }
                        else
                        {
                            a2 = t;
                            s2 = s;
                        }

                        ++rootIterCount;
                        ++ToiRootIters;

                        // djm: whats with this? put in settings?
                        if (rootIterCount == 50)
                        {
                            break;
                        }
                    }

                    ToiMaxRootIters = MathUtils.Max(ToiMaxRootIters, rootIterCount);

                    ++pushBackIter;

                    if (pushBackIter == Settings.MAX_POLYGON_VERTICES)
                    {
                        break;
                    }
                }

                ++iter;
                ++ToiIters;

                if (done)
                {
                    // System.out.println("done");
                    break;
                }

                if (iter == MAX_ITERATIONS)
                {
                    // System.out.println("failed, root finder stuck");
                    // Root finder got stuck. Semi-victory.
                    output.State = TOIOutputState.Failed;
                    output.T     = t1;
                    break;
                }
            }

            // System.out.printf("final sweeps: %f, %f, %f; %f, %f, %f", input.s)
            ToiMaxIters = MathUtils.Max(ToiMaxIters, iter);
        }
예제 #13
0
        public static float FindMinSeparation(out int indexA, out int indexB, float t)
        {
            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t);
            _sweepB.GetTransform(out xfB, t);

            switch (_type)
            {
            case SeparationFunctionType.Points:
            {
                var axisA = MathUtils.MulT(ref xfA.Q, _axis);
                var axisB = MathUtils.MulT(ref xfB.Q, -_axis);

                indexA = _proxyA.GetSupport(axisA);
                indexB = _proxyB.GetSupport(axisB);

                var localPointA = _proxyA.vertices[indexA];
                var localPointB = _proxyB.vertices[indexB];

                var pointA = MathUtils.Mul(ref xfA, localPointA);
                var pointB = MathUtils.Mul(ref xfB, localPointB);

                var separation = Vector2.Dot(pointB - pointA, _axis);
                return(separation);
            }

            case SeparationFunctionType.FaceA:
            {
                var normal = MathUtils.Mul(ref xfA.Q, _axis);
                var pointA = MathUtils.Mul(ref xfA, _localPoint);

                var axisB = MathUtils.MulT(ref xfB.Q, -normal);

                indexA = -1;
                indexB = _proxyB.GetSupport(axisB);

                var localPointB = _proxyB.vertices[indexB];
                var pointB      = MathUtils.Mul(ref xfB, localPointB);

                var separation = Vector2.Dot(pointB - pointA, normal);
                return(separation);
            }

            case SeparationFunctionType.FaceB:
            {
                var normal = MathUtils.Mul(ref xfB.Q, _axis);
                var pointB = MathUtils.Mul(ref xfB, _localPoint);

                var axisA = MathUtils.MulT(ref xfA.Q, -normal);

                indexB = -1;
                indexA = _proxyA.GetSupport(axisA);

                var localPointA = _proxyA.vertices[indexA];
                var pointA      = MathUtils.Mul(ref xfA, localPointA);

                var separation = Vector2.Dot(pointA - pointB, normal);
                return(separation);
            }

            default:
                Debug.Assert(false);
                indexA = -1;
                indexB = -1;
                return(0.0f);
            }
        }
예제 #14
0
파일: TimeOfImpact.cs 프로젝트: Bitsits/web
        public override void Step(Framework.Settings settings)
        {
            base.Step(settings);

            Sweep sweepA = new Sweep();

            sweepA.c0          = Vector2.Zero;
            sweepA.a0          = 0.0f;
            sweepA.c           = sweepA.c0;
            sweepA.a           = sweepA.a0;
            sweepA.localCenter = Vector2.Zero;

            Sweep sweepB = new Sweep();

            sweepB.c0          = new Vector2(-0.20382018f, 2.1368704f);
            sweepB.a0          = -3.1664171f;
            sweepB.c           = new Vector2(-0.26699525f, 2.3552670f);
            sweepB.a           = -3.3926492f;
            sweepB.localCenter = Vector2.Zero;

            TOIInput input = new TOIInput();

            input.proxyA.Set(_shapeA);
            input.proxyB.Set(_shapeB);
            input.sweepA = sweepA;
            input.sweepB = sweepB;
            input.tMax   = 1.0f;

            TOIOutput output;

            XNA.TimeOfImpact.CalculateTimeOfImpact(out output, ref input);

            _debugDraw.DrawString(50, _textLine, "toi = {0:n}", output.t);
            _textLine += 15;

            _debugDraw.DrawString(50, _textLine, "max toi iters = {0:n}, max root iters = {1:n}", XNA.TimeOfImpact.b2_toiMaxIters, XNA.TimeOfImpact.b2_toiMaxRootIters);
            _textLine += 15;

            FixedArray8 <Vector2> vertices = new FixedArray8 <Vector2>();

            Transform transformA;

            sweepA.GetTransform(out transformA, 0.0f);
            for (int i = 0; i < _shapeA._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformA, _shapeA._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeA._vertexCount, new Color(0.9f, 0.9f, 0.9f));

            Transform transformB;

            sweepB.GetTransform(out transformB, 0.0f);

            Vector2 localPoint = new Vector2(2.0f, -0.1f);
            Vector2 rB         = MathUtils.Multiply(ref transformB, localPoint) - sweepB.c0;
            float   wB         = sweepB.a - sweepB.a0;
            Vector2 vB         = sweepB.c - sweepB.c0;
            Vector2 v          = vB + MathUtils.Cross(wB, rB);

            for (int i = 0; i < _shapeB._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new Color(0.5f, 0.9f, 0.5f));

            sweepB.GetTransform(out transformB, output.t);
            for (int i = 0; i < _shapeB._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new Color(0.5f, 0.7f, 0.9f));

            sweepB.GetTransform(out transformB, 1.0f);
            for (int i = 0; i < _shapeB._vertexCount; ++i)
            {
                vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
            }
            _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new Color(0.9f, 0.5f, 0.5f));
        }
예제 #15
0
        public override void Update(GameSettings settings, GameTime gameTime)
        {
            base.Update(settings, gameTime);

            Sweep sweepA = new Sweep();

            sweepA.C0          = new Vector2(24.0f, -60.0f);
            sweepA.A0          = 2.95f;
            sweepA.C           = sweepA.C0;
            sweepA.A           = sweepA.A0;
            sweepA.LocalCenter = Vector2.Zero;

            Sweep sweepB = new Sweep();

            sweepB.C0          = new Vector2(53.474274f, -50.252514f);
            sweepB.A0          = 513.36676f; // - 162.0f * MathConstants.Pi;
            sweepB.C           = new Vector2(54.595478f, -51.083473f);
            sweepB.A           = 513.62781f; //  - 162.0f * MathConstants.Pi;
            sweepB.LocalCenter = Vector2.Zero;

            //sweepB.a0 -= 300.0f * MathConstants.Pi;
            //sweepB.a -= 300.0f * MathConstants.Pi;

            TOIInput input = new TOIInput();

            input.ProxyA = new DistanceProxy(_shapeA, 0);
            input.ProxyB = new DistanceProxy(_shapeB, 0);
            input.SweepA = sweepA;
            input.SweepB = sweepB;
            input.TMax   = 1.0f;

            TOIOutput output;

            TimeOfImpact.CalculateTimeOfImpact(ref input, out output);

            DrawString("toi = " + output.T);
            DrawString($"max toi iters = {TimeOfImpact.TOIMaxIters}, max root iters = {TimeOfImpact.TOIMaxRootIters}");

            Vector2[] vertices = new Vector2[Settings.MaxPolygonVertices];

            DebugView.BeginCustomDraw(ref GameInstance.Projection, ref GameInstance.View);

            Transform transformA;

            sweepA.GetTransform(out transformA, 0.0f);
            for (int i = 0; i < _shapeA.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformA, _shapeA.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeA.Vertices.Count, new Color(0.9f, 0.9f, 0.9f));

            Transform transformB;

            sweepB.GetTransform(out transformB, 0.0f);

            //b2Vec2 localPoint(2.0f, -0.1f);

            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.5f, 0.9f, 0.5f));

            sweepB.GetTransform(out transformB, output.T);
            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.5f, 0.7f, 0.9f));

            sweepB.GetTransform(out transformB, 1.0f);
            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.9f, 0.5f, 0.5f));

            DebugView.EndCustomDraw();

#if false
            for (float t = 0.0f; t < 1.0f; t += 0.1f)
            {
                sweepB.GetTransform(&transformB, t);
                for (int i = 0; i < _shapeB.m_count; ++i)
                {
                    vertices[i] = MathUtils.Mul(transformB, _shapeB.m_vertices[i]);
                }
                DebugView.DrawPolygon(vertices, _shapeB.m_count, b2Color(0.9f, 0.5f, 0.5f));
            }
#endif
        }
예제 #16
0
        protected override void OnRender()
        {
            var sweepA = new Sweep();

            sweepA.C0.Set(24.0f, -60.0f);
            sweepA.A0 = 2.95f;
            sweepA.C  = sweepA.C0;
            sweepA.A  = sweepA.A0;
            sweepA.LocalCenter.SetZero();

            var sweepB = new Sweep();

            sweepB.C0.Set(53.474274f, -50.252514f);
            sweepB.A0 = 513.36676f; // - 162.0f * _pi;
            sweepB.C.Set(54.595478f, -51.083473f);
            sweepB.A = 513.62781f;  //  - 162.0f * _pi;
            sweepB.LocalCenter.SetZero();

            //sweepB.A0 -= 300.0f * _pi;
            //sweepB.A -= 300.0f * _pi;

            var input = new ToiInput();

            input.ProxyA.Set(_shapeA, 0);
            input.ProxyB.Set(_shapeB, 0);
            input.SweepA = sweepA;
            input.SweepB = sweepB;
            input.Tmax   = 1.0f;

            TimeOfImpact.ComputeTimeOfImpact(out var output, input, World.ToiProfile, World.GJkProfile);

            DrawString($"toi = {output.Time}");

            DrawString($"max toi iters = {ToiMaxIters}, max root iters = {ToiMaxRootIters}");

            var vertices = new Vector2[Settings.MaxPolygonVertices];

            sweepA.GetTransform(out var transformA, 0.0f);

            for (var i = 0; i < _shapeA.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(transformA, _shapeA.Vertices[i]);
            }

            Drawer.DrawPolygon(vertices, _shapeA.Count, Color.FromArgb(230, 230, 230));

            sweepB.GetTransform(out var transformB, 0.0f);

            //Vec2 localPoint(2.0f, -0.1f);

            for (var i = 0; i < _shapeB.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(transformB, _shapeB.Vertices[i]);
            }

            Drawer.DrawPolygon(vertices, _shapeB.Count, Color.FromArgb(127, 230, 127));

            sweepB.GetTransform(out transformB, output.Time);

            for (var i = 0; i < _shapeB.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(transformB, _shapeB.Vertices[i]);
            }

            Drawer.DrawPolygon(vertices, _shapeB.Count, Color.FromArgb(127, 178, 230));

            sweepB.GetTransform(out transformB, 1.0f);

            for (var i = 0; i < _shapeB.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(transformB, _shapeB.Vertices[i]);
            }

            Drawer.DrawPolygon(vertices, _shapeB.Count, Color.FromArgb(230, 127, 127));
        }
예제 #17
0
        public static float FindMinSeparation(out int indexA, out int indexB, float t)
        {
            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t);
            _sweepB.GetTransform(out xfB, t);

            switch (_type)
            {
            case SeparationFunctionType.Points:
            {
                Vector2 axisA = Complex.Divide(ref _axis, ref xfA.q);
                Vector2 axisB = -Complex.Divide(ref _axis, ref xfB.q);

                indexA = _proxyA.GetSupport(axisA);
                indexB = _proxyB.GetSupport(axisB);

                Vector2 localPointA = _proxyA.Vertices[indexA];
                Vector2 localPointB = _proxyB.Vertices[indexB];

                Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
                Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);

                float separation = Vector2.Dot(pointB - pointA, _axis);
                return(separation);
            }

            case SeparationFunctionType.FaceA:
            {
                Vector2 normal = Complex.Multiply(ref _axis, ref xfA.q);
                Vector2 pointA = Transform.Multiply(ref _localPoint, ref xfA);

                Vector2 axisB = -Complex.Divide(ref normal, ref xfB.q);

                indexA = -1;
                indexB = _proxyB.GetSupport(axisB);

                Vector2 localPointB = _proxyB.Vertices[indexB];
                Vector2 pointB      = Transform.Multiply(ref localPointB, ref xfB);

                float separation = Vector2.Dot(pointB - pointA, normal);
                return(separation);
            }

            case SeparationFunctionType.FaceB:
            {
                Vector2 normal = Complex.Multiply(ref _axis, ref xfB.q);
                Vector2 pointB = Transform.Multiply(ref _localPoint, ref xfB);

                Vector2 axisA = -Complex.Divide(ref normal, ref xfA.q);

                indexB = -1;
                indexA = _proxyA.GetSupport(axisA);

                Vector2 localPointA = _proxyA.Vertices[indexA];
                Vector2 pointA      = Transform.Multiply(ref localPointA, ref xfA);

                float separation = Vector2.Dot(pointA - pointB, normal);
                return(separation);
            }

            default:
                Debug.Assert(false);
                indexA = -1;
                indexB = -1;
                return(0.0f);
            }
        }
예제 #18
0
        // float FindMinSeparation(int* indexA, int* indexB, float t) const
        public float FindMinSeparation(int[] indexes, float t)
        {
            SweepA.GetTransform(xfa, t);
            SweepB.GetTransform(xfb, t);

            switch (Type)
            {
            case Type.Points:
            {
                Rot.MulTransUnsafe(xfa.Q, Axis, axisA);
                Rot.MulTransUnsafe(xfb.Q, Axis.NegateLocal(), axisB);
                Axis.NegateLocal();

                indexes[0] = ProxyA.GetSupport(axisA);
                indexes[1] = ProxyB.GetSupport(axisB);

                localPointA.Set(ProxyA.GetVertex(indexes[0]));
                localPointB.Set(ProxyB.GetVertex(indexes[1]));

                Transform.MulToOutUnsafe(xfa, localPointA, pointA);
                Transform.MulToOutUnsafe(xfb, localPointB, pointB);

                float separation = Vec2.Dot(pointB.SubLocal(pointA), Axis);
                return(separation);
            }

            case Type.FaceA:
            {
                Rot.MulToOutUnsafe(xfa.Q, Axis, normal);
                Transform.MulToOutUnsafe(xfa, LocalPoint, pointA);

                Rot.MulTransUnsafe(xfb.Q, normal.NegateLocal(), axisB);
                normal.NegateLocal();

                indexes[0] = -1;
                indexes[1] = ProxyB.GetSupport(axisB);

                localPointB.Set(ProxyB.GetVertex(indexes[1]));
                Transform.MulToOutUnsafe(xfb, localPointB, pointB);

                float separation = Vec2.Dot(pointB.SubLocal(pointA), normal);
                return(separation);
            }

            case Type.FaceB:
            {
                Rot.MulToOutUnsafe(xfb.Q, Axis, normal);
                Transform.MulToOutUnsafe(xfb, LocalPoint, pointB);

                Rot.MulTransUnsafe(xfa.Q, normal.NegateLocal(), axisA);
                normal.NegateLocal();

                indexes[1] = -1;
                indexes[0] = ProxyA.GetSupport(axisA);

                localPointA.Set(ProxyA.GetVertex(indexes[0]));
                Transform.MulToOutUnsafe(xfa, localPointA, pointA);

                float separation = Vec2.Dot(pointA.SubLocal(pointB), normal);
                return(separation);
            }

            default:
                Debug.Assert(false);
                indexes[0] = -1;
                indexes[1] = -1;
                return(0f);
            }
        }
예제 #19
0
	    public override void Step(Framework.Settings settings)
	    {
		    base.Step(settings);

		    Sweep sweepA = new Sweep();
		    sweepA.c0 = new Vector2(24.0f, -60.0f);
		    sweepA.a0 = 2.95f;
		    sweepA.c = sweepA.c0;
		    sweepA.a = sweepA.a0;
		    sweepA.localCenter = Vector2.Zero;

		    Sweep sweepB = new Sweep();
            sweepB.c0 = new Vector2(53.474274f, -50.252514f);
            sweepB.a0 = 513.36676f;
            sweepB.c = new Vector2(54.595478f, -51.083473f);
            sweepB.a = 513.62781f;
		    sweepB.localCenter = Vector2.Zero;

		    TOIInput input = new TOIInput();
            input.proxyA.Set(_shapeA, 0);
            input.proxyB.Set(_shapeB, 0);
		    input.sweepA = sweepA;
		    input.sweepB = sweepB;
            input.tMax = 1.0f;

            TOIOutput output;
		    XNA.TimeOfImpact.CalculateTimeOfImpact(out output, ref input);

            _debugDraw.DrawString(50, _textLine, "toi = {0:n}", output.t);
		    _textLine += 15;

            _debugDraw.DrawString(50, _textLine, "max toi iters = {0:n}, max root iters = {1:n}", XNA.TimeOfImpact.b2_toiMaxIters, XNA.TimeOfImpact.b2_toiMaxRootIters);
		    _textLine += 15;

            FixedArray8<Vector2> vertices = new FixedArray8<Vector2>();

		    Transform transformA;
		    sweepA.GetTransform(out transformA, 0.0f);
		    for (int i = 0; i < _shapeA._vertexCount; ++i)
		    {
			    vertices[i] = MathUtils.Multiply(ref transformA, _shapeA._vertices[i]);
		    }
		    _debugDraw.DrawPolygon(ref vertices, _shapeA._vertexCount, new Color(0.9f, 0.9f, 0.9f));

		    Transform transformB;
		    sweepB.GetTransform(out transformB, 0.0f);

            Vector2 localPoint = new Vector2(2.0f, -0.1f);   
            Vector2 rB = MathUtils.Multiply(ref transformB, localPoint) - sweepB.c0;   
            float wB = sweepB.a - sweepB.a0;  
            Vector2 vB = sweepB.c - sweepB.c0;
            Vector2 v = vB + MathUtils.Cross(wB, rB); 

		    for (int i = 0; i < _shapeB._vertexCount; ++i)
		    {
			    vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
		    }
		    _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new Color(0.5f, 0.9f, 0.5f));

		    sweepB.GetTransform(out transformB, output.t);
		    for (int i = 0; i < _shapeB._vertexCount; ++i)
		    {
			    vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
		    }
		    _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new Color(0.5f, 0.7f, 0.9f));

		    sweepB.GetTransform(out transformB, 1.0f);
		    for (int i = 0; i < _shapeB._vertexCount; ++i)
		    {
			    vertices[i] = MathUtils.Multiply(ref transformB, _shapeB._vertices[i]);
		    }
		    _debugDraw.DrawPolygon(ref vertices, _shapeB._vertexCount, new Color(0.9f, 0.5f, 0.5f));
	    }
예제 #20
0
        // CCD via the local separating axis method. This seeks progression
        // by computing the largest time at which separation is maintained.
        public static bool TimeOfImpact(
            DistanceProxy proxyA,
            DistanceProxy proxyB,
            Sweep sweepA,
            Sweep sweepB,
            float tMax,
            out float t)
        {
            // Large rotations can make the root finder fail, so we normalize the
            // sweep angles.
            sweepA.Normalize();
            sweepB.Normalize();

            var totalRadius = proxyA.Radius + proxyB.Radius;
            var target      = System.Math.Max(Settings.LinearSlop, totalRadius - 3.0f * Settings.LinearSlop);

            const float tolerance = 0.25f * Settings.LinearSlop;

            System.Diagnostics.Debug.Assert(target > tolerance);

            // Prepare input for distance query.
            var cache = new SimplexCache {
                Count = 0
            };

            // The outer loop progressively attempts to compute new separating axes.
            // This loop terminates when an axis is repeated (no progress is made).
            var t1 = 0.0f;

            for (var iter = 0; iter < 20; ++iter)
            {
                WorldTransform xfA, xfB;
                sweepA.GetTransform(out xfA, t1);
                sweepB.GetTransform(out xfB, t1);

                // Get the distance between shapes. We can also use the results
                // to get a separating axis.
                var distance = Distance(ref cache, proxyA, xfA, proxyB, xfB);

                // If the shapes are overlapped, we give up on continuous collision.
                if (distance <= 0.0f)
                {
                    // Failure!
                    t = 0.0f;
                    return(false);
                }

                if (distance < target + tolerance)
                {
                    // Victory!
                    t = t1;
                    return(true);
                }

                // Initialize the separating axis.
                SeparationFunction fcn;
                SeparationFunction.Initialize(out fcn, cache, proxyA, proxyB, sweepA, sweepB, t1);

                // Compute the TOI on the separating axis. We do this by successively
                // resolving the deepest point. This loop is bounded by the number of vertices.
                var t2 = tMax;
                for (var pushBackIter = 0; pushBackIter < Settings.MaxPolygonVertices; ++pushBackIter)
                {
                    // Find the deepest point at t2. Store the witness point indices.
                    int indexA, indexB;
                    var s2 = fcn.FindMinSeparation(out indexA, out indexB, t2);

                    // Is the final configuration separated?
                    if (s2 > target + tolerance)
                    {
                        // Victory!
                        t = tMax;
                        return(false);
                    }

                    // Has the separation reached tolerance?
                    if (s2 > target - tolerance)
                    {
                        // Advance the sweeps
                        t1 = t2;
                        break;
                    }

                    // Compute the initial separation of the witness points.
                    var s1 = fcn.Evaluate(indexA, indexB, t1);

                    // Check for initial overlap. This might happen if the root finder
                    // runs out of iterations.
                    if (s1 < target - tolerance)
                    {
                        t = t1;
                        return(false);
                    }

                    // Check for touching
                    if (s1 <= target + tolerance)
                    {
                        // Victory! t1 should hold the TOI (could be 0.0).
                        t = t1;
                        return(true);
                    }

                    // Compute 1D root of: f(x) - target = 0
                    float a1 = t1, a2 = t2;
                    for (var rootIterCount = 0; rootIterCount < 50; ++rootIterCount)
                    {
                        // Use a mix of the secant rule and bisection.
                        float u;
                        if ((rootIterCount & 1) != 0)
                        {
                            // Secant rule to improve convergence.
                            u = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
                        }
                        else
                        {
                            // Bisection to guarantee progress.
                            u = 0.5f * (a1 + a2);
                        }

                        var s = fcn.Evaluate(indexA, indexB, u);

                        if (System.Math.Abs(s - target) < tolerance)
                        {
                            // t2 holds a tentative value for t1
                            t2 = u;
                            break;
                        }

                        // Ensure we continue to bracket the root.
                        if (s > target)
                        {
                            a1 = u;
                            s1 = s;
                        }
                        else
                        {
                            a2 = u;
                            s2 = s;
                        }
                    }
                }
            }

            // Root finder got stuck. Semi-victory.
            t = t1;
            return(false);
        }
예제 #21
0
        public float FindMinSeparation(out int indexA, out int indexB, float t)
        {
            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t);
            _sweepB.GetTransform(out xfB, t);

            switch (_type)
            {
            case SeparationFunctionType.Points:
            {
                Vector2 axisA = MathUtils.MultiplyT(ref xfA.R, _axis);
                Vector2 axisB = MathUtils.MultiplyT(ref xfB.R, -_axis);

                indexA = _proxyA.GetSupport(axisA);
                indexB = _proxyB.GetSupport(axisB);

                Vector2 localPointA = _proxyA.GetVertex(indexA);
                Vector2 localPointB = _proxyB.GetVertex(indexB);

                Vector2 pointA = MathUtils.Multiply(ref xfA, localPointA);
                Vector2 pointB = MathUtils.Multiply(ref xfB, localPointB);

                float separation = Vector2.Dot(pointB - pointA, _axis);
                return(separation);
            }

            case SeparationFunctionType.FaceA:
            {
                Vector2 normal = MathUtils.Multiply(ref xfA.R, _axis);
                Vector2 pointA = MathUtils.Multiply(ref xfA, _localPoint);

                Vector2 axisB = MathUtils.MultiplyT(ref xfB.R, -normal);

                indexA = -1;
                indexB = _proxyB.GetSupport(axisB);

                Vector2 localPointB = _proxyB.GetVertex(indexB);
                Vector2 pointB      = MathUtils.Multiply(ref xfB, localPointB);

                float separation = Vector2.Dot(pointB - pointA, normal);
                return(separation);
            }

            case SeparationFunctionType.FaceB:
            {
                Vector2 normal = MathUtils.Multiply(ref xfB.R, _axis);
                Vector2 pointB = MathUtils.Multiply(ref xfB, _localPoint);

                Vector2 axisA = MathUtils.MultiplyT(ref xfA.R, -normal);

                indexB = -1;
                indexA = _proxyA.GetSupport(axisA);

                Vector2 localPointA = _proxyA.GetVertex(indexA);
                Vector2 pointA      = MathUtils.Multiply(ref xfA, localPointA);

                float separation = Vector2.Dot(pointA - pointB, normal);
                return(separation);
            }

            default:
                Debug.Assert(false);
                indexA = -1;
                indexB = -1;
                return(0.0f);
            }
        }
예제 #22
0
            public float FindMinSeparation(out int indexA, out int indexB, float t)
            {
                WorldTransform xfA, xfB;

                _sweepA.GetTransform(out xfA, t);
                _sweepB.GetTransform(out xfB, t);

                switch (_type)
                {
                case Type.Points:
                {
                    var axisA = -xfA.Rotation * _axis;
                    var axisB = -xfB.Rotation * -_axis;

                    indexA = _proxyA.GetSupport(axisA);
                    indexB = _proxyB.GetSupport(axisB);

                    var localPointA = _proxyA.Vertices[indexA];
                    var localPointB = _proxyB.Vertices[indexB];

                    var pointA = xfA.ToGlobal(localPointA);
                    var pointB = xfB.ToGlobal(localPointB);

// ReSharper disable RedundantCast Necessary for FarPhysics.
                    return(Vector2Util.Dot((Vector2)(pointB - pointA), _axis));
// ReSharper restore RedundantCast
                }

                case Type.FaceA:
                {
                    var normal = xfA.Rotation * _axis;
                    var pointA = xfA.ToGlobal(_localPoint);

                    var axisB = -xfB.Rotation * -normal;

                    indexA = -1;
                    indexB = _proxyB.GetSupport(axisB);

                    var localPointB = _proxyB.Vertices[indexB];
                    var pointB      = xfB.ToGlobal(localPointB);

// ReSharper disable RedundantCast Necessary for FarPhysics.
                    return(Vector2Util.Dot((Vector2)(pointB - pointA), normal));
// ReSharper restore RedundantCast
                }

                case Type.FaceB:
                {
                    var normal = xfB.Rotation * _axis;
                    var pointB = xfB.ToGlobal(_localPoint);

                    var axisA = -xfA.Rotation * -normal;

                    indexB = -1;
                    indexA = _proxyA.GetSupport(axisA);

                    var localPointA = _proxyA.Vertices[indexA];
                    var pointA      = xfA.ToGlobal(localPointA);

// ReSharper disable RedundantCast Necessary for FarPhysics.
                    return(Vector2Util.Dot((Vector2)(pointA - pointB), normal));
// ReSharper restore RedundantCast
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
예제 #23
0
        public SeparationFunction(ref SimplexCache cache,
                                  ref DistanceProxy proxyA, ref Sweep sweepA,
                                  ref DistanceProxy proxyB, ref Sweep sweepB,
                                  float t1)
        {
            _localPoint = Vector2.Zero;
            _proxyA     = proxyA;
            _proxyB     = proxyB;
            int count = cache.Count;

            Debug.Assert(0 < count && count < 3);

            _sweepA = sweepA;
            _sweepB = sweepB;

            Transform xfA, xfB;

            _sweepA.GetTransform(out xfA, t1);
            _sweepB.GetTransform(out xfB, t1);

            if (count == 1)
            {
                _type = SeparationFunctionType.Points;
                Vector2 localPointA = _proxyA.GetVertex(cache.IndexA[0]);
                Vector2 localPointB = _proxyB.GetVertex(cache.IndexB[0]);
                Vector2 pointA      = MathUtils.Multiply(ref xfA, localPointA);
                Vector2 pointB      = MathUtils.Multiply(ref xfB, localPointB);
                _axis = pointB - pointA;
                _axis.Normalize();
                return;
            }
            else if (cache.IndexA[0] == cache.IndexA[1])
            {
                // Two points on B and one on A.
                _type = SeparationFunctionType.FaceB;
                Vector2 localPointB1 = proxyB.GetVertex(cache.IndexB[0]);
                Vector2 localPointB2 = proxyB.GetVertex(cache.IndexB[1]);

                _axis = MathUtils.Cross(localPointB2 - localPointB1, 1.0f);
                _axis.Normalize();
                Vector2 normal = MathUtils.Multiply(ref xfB.R, _axis);

                _localPoint = 0.5f * (localPointB1 + localPointB2);
                Vector2 pointB = MathUtils.Multiply(ref xfB, _localPoint);

                Vector2 localPointA = proxyA.GetVertex(cache.IndexA[0]);
                Vector2 pointA      = MathUtils.Multiply(ref xfA, localPointA);

                float s = Vector2.Dot(pointA - pointB, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                    s     = -s;
                }
                return;
            }
            else
            {
                // Two points on A and one or two points on B.
                _type = SeparationFunctionType.FaceA;
                Vector2 localPointA1 = _proxyA.GetVertex(cache.IndexA[0]);
                Vector2 localPointA2 = _proxyA.GetVertex(cache.IndexA[1]);

                _axis = MathUtils.Cross(localPointA2 - localPointA1, 1.0f);
                _axis.Normalize();
                Vector2 normal = MathUtils.Multiply(ref xfA.R, _axis);

                _localPoint = 0.5f * (localPointA1 + localPointA2);
                Vector2 pointA = MathUtils.Multiply(ref xfA, _localPoint);

                Vector2 localPointB = _proxyB.GetVertex(cache.IndexB[0]);
                Vector2 pointB      = MathUtils.Multiply(ref xfB, localPointB);

                float s = Vector2.Dot(pointB - pointA, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                    s     = -s;
                }
                return;
            }
        }
예제 #24
0
        public override void Update(GameSettings settings, GameTime gameTime)
        {
            base.Update(settings, gameTime);

            Sweep sweepA = new Sweep();

            sweepA.C0          = new Vector2(24.0f, -60.0f);
            sweepA.A0          = 2.95f;
            sweepA.C           = sweepA.C0;
            sweepA.A           = sweepA.A0;
            sweepA.LocalCenter = Vector2.Zero;

            Sweep sweepB = new Sweep();

            sweepB.C0          = new Vector2(53.474274f, -50.252514f);
            sweepB.A0          = 513.36676f; // - 162.0f * b2_pi;
            sweepB.C           = new Vector2(54.595478f, -51.083473f);
            sweepB.A           = 513.62781f; //  - 162.0f * b2_pi;
            sweepB.LocalCenter = Vector2.Zero;

            //sweepB.a0 -= 300.0f * b2_pi;
            //sweepB.a -= 300.0f * b2_pi;

            TOIInput input = new TOIInput();

            input.ProxyA.Set(_shapeA, 0);
            input.ProxyB.Set(_shapeB, 0);
            input.SweepA = sweepA;
            input.SweepB = sweepB;
            input.TMax   = 1.0f;

            TOIOutput output;

            TimeOfImpact.CalculateTimeOfImpact(out output, input);

            DrawString("TOI = " + output.T);
            DrawString(string.Format("Max TOI iters = {0:n}, Max root iters = {1:n}", TimeOfImpact.TOIMaxIters, TimeOfImpact.TOIMaxRootIters));

            Vector2[] vertices = new Vector2[Settings.MaxPolygonVertices];

            DebugView.BeginCustomDraw(ref GameInstance.Projection, ref GameInstance.View);
            Transform transformA;

            sweepA.GetTransform(out transformA, 0.0f);
            for (int i = 0; i < _shapeA.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformA, _shapeA.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeA.Vertices.Count, new Color(0.9f, 0.9f, 0.9f));

            Transform transformB;

            sweepB.GetTransform(out transformB, 0.0f);

            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.5f, 0.9f, 0.5f));

            sweepB.GetTransform(out transformB, output.T);
            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.5f, 0.7f, 0.9f));

            sweepB.GetTransform(out transformB, 1.0f);
            for (int i = 0; i < _shapeB.Vertices.Count; ++i)
            {
                vertices[i] = MathUtils.Mul(ref transformB, _shapeB.Vertices[i]);
            }
            DebugView.DrawPolygon(vertices, _shapeB.Vertices.Count, new Color(0.9f, 0.5f, 0.5f));
            DebugView.EndCustomDraw();
        }
예제 #25
0
        public static void Set(ref SimplexCache cache,
                               DistanceProxy proxyA, ref Sweep sweepA,
                               DistanceProxy proxyB, ref Sweep sweepB,
                               float t1)
        {
            _localPoint = Vector2.Zero;
            _proxyA = proxyA;
            _proxyB = proxyB;
            int count = cache.Count;
            Debug.Assert(0 < count && count < 3);

            _sweepA = sweepA;
            _sweepB = sweepB;

            Transform xfA, xfB;
            _sweepA.GetTransform(out xfA, t1);
            _sweepB.GetTransform(out xfB, t1);

            if (count == 1)
            {
                _type = SeparationFunctionType.Points;
                Vector2 localPointA = _proxyA.Vertices[cache.IndexA[0]];
                Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
                Vector2 pointA = MathUtils.Multiply(ref xfA, localPointA);
                Vector2 pointB = MathUtils.Multiply(ref xfB, localPointB);
                _axis = pointB - pointA;
                _axis.Normalize();
                return;
            }
            else if (cache.IndexA[0] == cache.IndexA[1])
            {
                // Two points on B and one on A.
                _type = SeparationFunctionType.FaceB;
                Vector2 localPointB1 = proxyB.Vertices[cache.IndexB[0]];
                Vector2 localPointB2 = proxyB.Vertices[cache.IndexB[1]];

                Vector2 a = localPointB2 - localPointB1;
                _axis = new Vector2(a.Y, -a.X);
                _axis.Normalize();
                Vector2 normal = MathUtils.Multiply(ref xfB.R, _axis);

                _localPoint = 0.5f * (localPointB1 + localPointB2);
                Vector2 pointB = MathUtils.Multiply(ref xfB, _localPoint);

                Vector2 localPointA = proxyA.Vertices[cache.IndexA[0]];
                Vector2 pointA = MathUtils.Multiply(ref xfA, localPointA);

                float s = Vector2.Dot(pointA - pointB, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                    s = -s;
                }
                return;
            }
            else
            {
                // Two points on A and one or two points on B.
                _type = SeparationFunctionType.FaceA;
                Vector2 localPointA1 = _proxyA.Vertices[cache.IndexA[0]];
                Vector2 localPointA2 = _proxyA.Vertices[cache.IndexA[1]];

                Vector2 a = localPointA2 - localPointA1;
                _axis = new Vector2(a.Y, -a.X);
                _axis.Normalize();
                Vector2 normal = MathUtils.Multiply(ref xfA.R, _axis);

                _localPoint = 0.5f * (localPointA1 + localPointA2);
                Vector2 pointA = MathUtils.Multiply(ref xfA, _localPoint);

                Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
                Vector2 pointB = MathUtils.Multiply(ref xfB, localPointB);

                float s = Vector2.Dot(pointB - pointA, normal);
                if (s < 0.0f)
                {
                    _axis = -_axis;
                    s = -s;
                }
                return;
            }
        }
예제 #26
0
        /// <summary>
        /// CCD via the secant method.
        /// Compute the time when two shapes begin to touch or touch at a closer distance.
        /// TOI considers the shape radii. It attempts to have the radii overlap by the tolerance.
        /// Iterations terminate with the overlap is within 0.5 * tolerance. The tolerance should be
        /// smaller than sum of the shape radii.
        /// @warning the sweeps must have the same time interval.
        /// fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="shapeA">The shape A.</param>
        /// <param name="shapeB">The shape B.</param>
        /// <returns>
        /// fraction between [0,1] in which the shapes first touch.
        /// </returns>
        public static float TimeOfImpact(TOIInput input)
        {
            ++ToiCalls;

            DistanceProxy proxyA = input.ProxyA;
            DistanceProxy proxyB = input.ProxyB;

            Sweep sweepA = input.SweepA;
            Sweep sweepB = input.SweepB;

            Box2DXDebug.Assert(sweepA.T0 == sweepB.T0);
            Box2DXDebug.Assert(1.0f - sweepA.T0 > Settings.FLT_EPSILON);

            float radius    = proxyA._radius + proxyB._radius;
            float tolerance = input.Tolerance;

            float alpha = 0.0f;

            const int k_maxIterations = 1000; // TODO_ERIN b2Settings
            int       iter            = 0;
            float     target          = 0.0f;

            // Prepare input for distance query.
            SimplexCache cache = new SimplexCache();

            cache.Count = 0;
            DistanceInput distanceInput = new DistanceInput();

            distanceInput.proxyA   = input.ProxyA;
            distanceInput.proxyB   = input.ProxyB;
            distanceInput.UseRadii = false;

            for (;;)
            {
                Transform xfA, xfB;
                sweepA.GetTransform(out xfA, alpha);
                sweepB.GetTransform(out xfB, alpha);

                // Get the distance between shapes.
                distanceInput.TransformA = xfA;
                distanceInput.TransformB = xfB;
                DistanceOutput distanceOutput;
                Distance(out distanceOutput, cache, distanceInput);

                if (distanceOutput.Distance <= 0.0f)
                {
                    alpha = 1.0f;
                    break;
                }

                SeparationFunction fcn = new SeparationFunction();
                fcn.Initialize(cache, proxyA, xfA, proxyB, xfB);

                float separation = fcn.Evaluate(xfA, xfB);
                if (separation <= 0.0f)
                {
                    alpha = 1.0f;
                    break;
                }

                if (iter == 0)
                {
                    // Compute a reasonable target distance to give some breathing room
                    // for conservative advancement. We take advantage of the shape radii
                    // to create additional clearance.
                    if (separation > radius)
                    {
                        target = Math.Max(radius - tolerance, 0.75f * radius);
                    }
                    else
                    {
                        target = Math.Max(separation - tolerance, 0.02f * radius);
                    }
                }

                if (separation - target < 0.5f * tolerance)
                {
                    if (iter == 0)
                    {
                        alpha = 1.0f;
                        break;
                    }

                    break;
                }

#if false
                // Dump the curve seen by the root finder
                {
                    const int N  = 100;
                    float     dx = 1.0f / N;
                    float     xs[N + 1];