private static void EllasticColl()
        {
            var m1 = 4d;
            var m2 = 6d;

            var vx1 = 5d;
            var vx2 = -5d;

            var x1 = new Polynomial(0, 5);
            var x2 = new Polynomial(10, -5);

            var vy1 = 5d;
            var vy2 = 0d;
            var y1  = new Polynomial(0, 5);
            var y2  = new Polynomial(5, 0);

            var r1 = 0.5d;
            var r2 = 0.5d;

            var dx = (x2 - x1);
            var dy = (y2 - y1);

            var meetingPointsPol = (dx ^ 2) + (dy ^ 2) - System.Math.Pow(r1 + r2, 2);
            var roots            = FindRoots.Polynomial(meetingPointsPol.Coefficients);
            var t = roots.Where(r => r.IsReal()).Select(r => r.Real).Min();

            Vector2D v1      = new Vector2D(vx1, vy1);
            Vector2D v2      = new Vector2D(vx2, vy2);
            var      tangent = new Vector2D(dx.Evaluate(t), dy.Evaluate(t)).Orthogonal.Normalize();

            var v1t = v1.ProjectOn(tangent);
            var u1t = v1t;
            var v1p = v1 - v1t;

            var v2t = v2.ProjectOn(tangent);
            var u2t = v2t;
            var v2p = v2 - v2t;

            var p_p = m1 * v1p.Length + m2 * v2p.Length;
            var e   = 0.5 * m1 * System.Math.Pow(v1.Length, 2) + 0.5 * m2 * System.Math.Pow(v2.Length, 2);

            var u1p        = new Polynomial(p_p / m1, -m2 / m1);
            var u2pLengths = (0.5 * m1 * ((u1p ^ 2) + System.Math.Pow(u1t.Length, 2)) +
                              0.5 * m2 * ((new Polynomial(0, 1) ^ 2) + System.Math.Pow(u2t.Length, 2))).Roots(e);

            var u1pLength = u1p.Evaluate(u2pLengths.First());
        }
        public override ISimulation <AngularMomentumSimulationMoment> GenerateSimulation(double t1, double t2)
        {
            var vt     = new IntervalIndexer <Polynomial>();
            var xt     = new IntervalIndexer <Polynomial>();
            var omegat = new IntervalIndexer <Polynomial>();
            var anglet = new IntervalIndexer <Polynomial>();

            var v     = new Polynomial(_v0);
            var omega = new Polynomial(_omega0);

            var vOnSurface = v + omega * _disk.Radius;

            var t = t1;

            var vOnSurface0 = vOnSurface.Evaluate(t);

            // There's friction that acts on the disk
            if (vOnSurface0.CompareTo(0, 6e-5) != 0)
            {
                var circumferenceByR = new Polynomial(0, 2 * System.Math.PI);
                var tMass            = (circumferenceByR * _disk.SpecificMassByR).DefiniteIntegral(_disk.Radius);
                var rSquared         = new Polynomial(0, 0, 1);
                var iZ       = ((circumferenceByR * _disk.SpecificMassByR) * rSquared).DefiniteIntegral(_disk.Radius);
                var friction = (-System.Math.Sign(vOnSurface0)) * (_coOfKineticFriction * tMass * g0);

                var torque = _disk.Radius * friction;
                var angularAcceleration = torque / iZ;
                omega = (new Polynomial(angularAcceleration)).AntiDerivative(_omega0);

                var a = friction / tMass;
                v = (new Polynomial(a)).AntiDerivative(_v0);

                vOnSurface = v + omega * _disk.Radius;

                var tf = t2;
                try
                {
                    tf = vOnSurface.Roots(0, t1, t2).First();
                }
                catch (InvalidOperationException)
                {
                }

                var slipInterval = (Endpoints.Closed(t), Endpoints.Open(tf));

                vt.AddInterval(slipInterval, v);
                xt.AddInterval(slipInterval, v.AntiDerivative());
                omegat.AddInterval(slipInterval, omega);
                anglet.AddInterval(slipInterval, omega.AntiDerivative());

                t = tf;
            }

            if (t < t2)
            {
                var noSlipInterval = (Endpoints.Closed(t), Endpoints.Unbounded);

                vt.AddInterval(
                    noSlipInterval,
                    new Polynomial(v.Evaluate(t))
                    );
                xt.AddInterval(
                    noSlipInterval,
                    new Polynomial(v.AntiDerivative().Evaluate(t), v.Evaluate(t))
                    .Offset(-t)
                    );

                omegat.AddInterval(
                    noSlipInterval,
                    new Polynomial(omega.Evaluate(t))
                    );
                anglet.AddInterval(
                    noSlipInterval,
                    new Polynomial(omega.AntiDerivative().Evaluate(t), omega.Evaluate(t))
                    .Offset(-t)
                    );
            }

            return(new AngularMomentumSimulation(_disk, omegat, anglet, vt, xt));
        }