public GravMouse(LargeMapViewer2D picturebox, SimpleMap map, MyVector boundryLower, MyVector boundryUpper)
        {
            const double RADIUS = 400;

            _picturebox = picturebox;
            _map = map;
            _boundryLower = boundryLower;
            _boundryUpper = boundryUpper;

            _cursorBlip = new BallBlip(new Ball(new MyVector(), new DoubleVector(1, 0, 0, 0, 1, 0), RADIUS, UtilityCore.GetMassForRadius(RADIUS, 1d), 1, 0, 0, _boundryLower, _boundryUpper), CollisionStyle.Stationary, RadarBlipQual.BallUserDefined05, TokenGenerator.NextToken());

            _picturebox.MouseDown += new MouseEventHandler(picturebox_MouseDown);
            _picturebox.MouseUp += new MouseEventHandler(picturebox_MouseUp);
            _picturebox.MouseMove += new MouseEventHandler(picturebox_MouseMove);
            _picturebox.MouseLeave += new EventHandler(picturebox_MouseLeave);
        }
        protected void GetCollisionNormalAndPointsOfContact_SphereSphere(out MyVector normal, out double normalMagnitude, out MyVector pointOfContact1, out MyVector pointOfContact2, BallBlip ball1, BallBlip ball2)
        {
            // Vector that is perpendicular to the tangent of the collision, and it points in the direction of object 1.  Real
            // easy when dealing with spheres     :)
            normal = ball2.Ball.Position - ball1.Ball.Position;

            // Remember this length
            normalMagnitude = normal.GetMagnitude();

            // This needs to be returned as a unit vector
            normal.Divide(normalMagnitude);

            // Start them off as unit vectors
            pointOfContact1 = normal.Clone();
            pointOfContact2 = normal.Clone();

            // Finish (use the ratio of their radii)
            pointOfContact1.Multiply((ball1.Ball.Radius / (ball1.Ball.Radius + ball2.Ball.Radius)) * normalMagnitude);
            pointOfContact2.Multiply((ball2.Ball.Radius / (ball1.Ball.Radius + ball2.Ball.Radius)) * normalMagnitude * -1);		// I want this one pointing the other direction

            // Now that I have the points of contact relative to the centers of position, I need to make them
            // relative to the centers of mass
            if (ball1.TorqueBall != null)
            {
                pointOfContact1.Subtract(ball1.TorqueBall.CenterOfMass);
            }

            if (ball2.TorqueBall != null)
            {
                pointOfContact2.Subtract(ball2.TorqueBall.CenterOfMass);
            }
        }
        protected void Collide_TorqueBallTorqueBall_2IsStationary(BallBlip ball1, BallBlip ball2)
        {
            // See if they're sitting directly on top of each other
            if (Utility3D.IsNearValue(ball1.Sphere.Position.X, ball2.Sphere.Position.X) && Utility3D.IsNearValue(ball1.Sphere.Position.Y, ball2.Sphere.Position.Y) && Utility3D.IsNearValue(ball1.Sphere.Position.Z, ball2.Sphere.Position.Z))
            {
                // They're sitting directly on top of each other.  Move them slightly away from each other
                ball2.Sphere.Position.X += .001;
                ball2.Sphere.Position.Y += .001;
            }

            // Get the collision normal and points of contact relative to the center of mass (assume they are spheres)
            MyVector normal, pointOfContact1, pointOfContact2;
            double normalMagnitude;
            GetCollisionNormalAndPointsOfContact_SphereSphere(out normal, out normalMagnitude, out pointOfContact1, out pointOfContact2, ball1, ball2);

            // ------------------------------ Calculate the impulse
            // ------------------------------ impulse = ( -(1+elasticity)(Va - Vb) dot Normal ) / ( Normal dot ((1/Ma) + (1/Mb))Normal + [a lot of rotation calculation])
            #region Numerator

            // Figure out the velocities at the point of contact, which is linear + (angular x pointofcontact)
            MyVector velocity1 = MyVector.Cross(ball1.TorqueBall.AngularVelocity, pointOfContact1);
            velocity1.Add(ball1.Ball.Velocity);

            MyVector velocity2 = MyVector.Cross(ball2.TorqueBall.AngularVelocity, pointOfContact2);
            velocity2.Add(ball2.Ball.Velocity);

            MyVector contactVelocity = velocity1 - velocity2;

            double numerator = MyVector.Dot(contactVelocity, normal);		// get the relative velocity dot normal
            numerator *= -1d * (1d + ((ball1.Ball.Elasticity + ball2.Ball.Elasticity) / 2d));

            #endregion

            if (numerator > 0d)
            {
                // Technically, there's no collision
                return;
            }

            #region Denominator

            double sumOf1OverMass = (1d / ball1.Ball.Mass);		// pretend ball2 has infinite mass, so 1 over infinity is zero

            // (inverse inertia tensor * (pointofcontact x normal)) x pointofcontact
            MyVector i1 = MyVector.Cross(pointOfContact1, normal);
            i1 = MyMatrix3.Multiply(ball1.TorqueBall.InertialTensorBodyInverse, i1);
            i1 = MyVector.Cross(i1, pointOfContact1);


            //TODO:  may need to skip i2 if stationary (not rotatable)

            // (inverse inertia tensor * (pointofcontact x normal)) x pointofcontact
            MyVector i2 = MyVector.Cross(pointOfContact2, normal);
            i2 = MyMatrix3.Multiply(ball2.TorqueBall.InertialTensorBodyInverse, i2);
            i2 = MyVector.Cross(i2, pointOfContact2);

            double denominator = sumOf1OverMass + MyVector.Dot(i1, normal) + MyVector.Dot(i2, normal);

            #endregion

            double impulse = numerator / denominator;

            // ------------------------------ Calculate Linear Velocity
            // ------------------------------ velocity = Va + ( impulse / Ma )Normal
            // ------------------------------ velocity = Vb - ( impulse / Mb )Normal
            ball1.Ball.Velocity.Add(normal * (impulse / ball1.Ball.Mass));
            //ball2.Ball.Velocity.Subtract(normal * (impulse / ball2.Ball.Mass));

            // ------------------------------ Calculate Angular Velocity (collision)
            // For spheres with mass in the center, there will be no spin as a result of the collision (because the collision
            // normal points directly to the center).  But if the center of mass is elsewhere, there will be a spin.
            MyVector deltaAngularMomentum = normal * impulse;
            deltaAngularMomentum = MyVector.Cross(pointOfContact1, deltaAngularMomentum);
            ball1.TorqueBall.AngularMomentum.Add(deltaAngularMomentum);

            if (ball2.CollisionStyle == CollisionStyle.StationaryRotatable)
            {
                deltaAngularMomentum = normal * (impulse * -1d);
                deltaAngularMomentum = MyVector.Cross(pointOfContact2, deltaAngularMomentum);
                ball2.TorqueBall.AngularMomentum.Add(deltaAngularMomentum);
            }

            #region Friction

            // The direction of friction must always be tangent to the collision normal, and in reverse of the sliding velocity.
            // It might be easier to think of a block sitting on a ramp.  The normal of the collision with the ramp points toward
            // the block.  The tangent of that is the surface of the ramp.  If friction pointed anywhere but along the surface of
            // the ramp, the block would go airborne.

            // Figure out the direction of friction
            MyVector tangentDirection = contactVelocity - (normal * MyVector.Dot(normal, contactVelocity));
            tangentDirection.BecomeUnitVector();
            MyVector frictionDirection = tangentDirection * -1.0d;

            // See how much of the contact velocity is along the tangent
            double tangentSpeed = MyVector.Dot(tangentDirection, contactVelocity);

            // Figure out how much of an impulse it would take to exactly stop the objects
            double impulseToStop = GetImpulseForceMagnitudeFromDeltaVelocity(tangentSpeed, pointOfContact1, pointOfContact2, frictionDirection, sumOf1OverMass, ball1.TorqueBall.InertialTensorBodyInverse, ball2.TorqueBall.InertialTensorBodyInverse);

            // Take the average of the two object's static friction, and multiply by size of the normal
            double maxStaticFrictionForce = normalMagnitude * ((ball1.Ball.StaticFriction + ball2.Ball.StaticFriction) * .5d);

            MyVector frictionImpulse;

            // Figure out which friction coeficient to use
            if (maxStaticFrictionForce < impulseToStop)
            {
                // Use kinetic friction (slipping).  Kinetic friction is always less than static.
                double kineticFrictionForce = normalMagnitude * ((ball1.Ball.KineticFriction + ball2.Ball.KineticFriction) * .5d);
                frictionImpulse = frictionDirection * kineticFrictionForce;
            }
            else
            {
                // Use static friction (not slipping).  I don't want to multiply by maxStaticFrictionForce, because
                // that is too large.  I want to use the value that will perfectly stop the objects
                frictionImpulse = frictionDirection * impulseToStop;
            }

            // ------------------------------ Apply Linear Velocity
            ball1.Ball.Velocity.Add(frictionImpulse * (1d / ball1.Ball.Mass));
            //ball2.Ball.Velocity.Subtract(frictionImpulse * (1d / ball2.Ball.Mass));

            // ------------------------------ Apply Angular Momentum
            ball1.TorqueBall.AngularMomentum.Add(MyVector.Cross(pointOfContact1, frictionImpulse));
            if (ball2.CollisionStyle == CollisionStyle.StationaryRotatable)
            {
                ball2.TorqueBall.AngularMomentum.Subtract(MyVector.Cross(pointOfContact2, frictionImpulse));
            }

            #endregion
        }
        protected void Collide_BallBall_2IsStationary(BallBlip ball1, BallBlip ball2)
        {
            // See if they're sitting directly on top of each other
            if (Utility3D.IsNearValue(ball1.Sphere.Position.X, ball2.Sphere.Position.X) && Utility3D.IsNearValue(ball1.Sphere.Position.Y, ball2.Sphere.Position.Y) && Utility3D.IsNearValue(ball1.Sphere.Position.Z, ball2.Sphere.Position.Z))
            {
                // They're sitting directly on top of each other.  Move them slightly away from each other
                ball2.Sphere.Position.X += .001;
                ball2.Sphere.Position.Y += .001;
            }

            // Vector that is perpendicular to the tangent of the collision, and it points in the direction of object 1.  Real
            // easy when dealing with spheres     :)
            MyVector normal = ball2.Ball.Position - ball1.Ball.Position;

            // ------------------------------ Calculate the impulse
            // ------------------------------ impulse = ( -(1+elasticity)(Va - Vb) dot Normal ) / ( Normal dot ((1/Ma) + (1/Mb))Normal)
            // Numerator
            MyVector temp = ball1.Ball.Velocity - ball2.Ball.Velocity;
            temp.Multiply(-1d * (1d + ((ball1.Ball.Elasticity + ball2.Ball.Elasticity) / 2d)));
            double numerator = MyVector.Dot(temp, normal);

            if (numerator > 0d)
            {
                // Technically, there's no collision
                return;
            }

            // Divisor
            temp = normal.Clone();
            //temp.Multiply((1d / ball1.Ball.Mass) + (1d / ball2.Ball.Mass));
            temp.Multiply(1d / ball1.Ball.Mass);		// pretend ball2 has infinite mass, so 1 over infinity is zero
            double divisor = MyVector.Dot(normal, temp);

            // Impulse
            double impulse = numerator / divisor;

            // ------------------------------ Calculate the first object's new velocity
            // ------------------------------ velocity = Va + ( impulse / Ma )Normal
            ball1.Ball.Velocity.Add(normal * (impulse / ball1.Ball.Mass));

            // ------------------------------ Calculate the second object's new velocity
            // ------------------------------ velocity = Vb - ( impulse / Mb )Normal
            //ball2.Ball.Velocity.Subtract(normal * (impulse / ball2.Ball.Mass));		// ball2 is stationary
        }
 protected void PullItemsApartSpring_BallSphere(BallBlip ball, RadarBlip blip)
 {
 }
        protected void PullItemsApartSpring_BallBall(BallBlip ball1, BallBlip ball2)
        {
            double sumRadii = ball1.Sphere.Radius + ball2.Sphere.Radius;

            // Get the vector from 2 to 1
            MyVector move1From2 = ball1.Sphere.Position - ball2.Sphere.Position;
            double totalDistance = move1From2.GetMagnitude();		// distance from centers

            if (totalDistance > sumRadii)
            {
                return;
            }

            // Make this a unit vector
            move1From2.Divide(totalDistance);

            // Normally, it's f=kx, but I want x to always be from zero to one.  So I'm really just finding the percent of
            // total velocity.
            double percent = 1d - (totalDistance / sumRadii);

            //TODO:  Don't pull them both away at the same velocity, use the ratio of the masses

            move1From2.Multiply(_pullApartSpringVelocity * percent);

            //TODO:  Instead of just adding directly to velocity, set it (but leave some of it there?  dot product?)
            if (ball1.CollisionStyle == CollisionStyle.Standard)
            {
                ball1.Ball.Velocity.Add(move1From2);
            }
            if (ball2.CollisionStyle == CollisionStyle.Standard)
            {
                move1From2.Multiply(-1d);
                ball2.Ball.Velocity.Add(move1From2);
            }
        }
 /// <summary>
 /// This ties this gun to a ship (null is an allowed value)
 /// </summary>
 public void SetShip(BallBlip ship)
 {
     _ship = ship;
 }
        private void btnAddRigidBody_Click(object sender, EventArgs e)
        {
            const int MINPOINTMASSES = 3;
            const int MAXPOINTMASSES = 8;
            const double MINPOINTMASSRADIUS = MINRADIUSMASS / MINPOINTMASSES;
            const double MAXPOINTMASSRADIUS = MAXRADIUSMASS / MAXPOINTMASSES;

            // Make the chassis
            RigidBody ball = new RigidBody(Utility3D.GetRandomVector(_boundryLower, _boundryUpper), new DoubleVector(0, -1, 0, -1, 0, 0), .1d, GetElasticity(), 1, 1, _boundryLower, _boundryUpper);

            int numPointMasses = _rand.Next(MINPOINTMASSES, MAXPOINTMASSES + 1);
            //double maxOffset = MAXRADIUSMASS - ((MINPOINTMASSRADIUS + MAXPOINTMASSRADIUS) / 2d);		// this could result in bodies slightly larger than the other two types, but it should be close
            double maxOffset = MAXRADIUSMASS - MAXPOINTMASSRADIUS;
            double ballRadius = ball.Radius;
            double curRadius;

            // Add point masses
            for (int massCntr = 1; massCntr <= numPointMasses; massCntr++)
            {
                MyVector pointMassPos = Utility3D.GetRandomVectorSpherical(maxOffset);
                pointMassPos.Z = 0;		// I do this here for the radius calculation below
                double pointMassMass = MINPOINTMASSRADIUS + (_rand.NextDouble() * (MAXPOINTMASSRADIUS - MINPOINTMASSRADIUS));

                // Add a point mass
                ball.AddPointMass(pointMassPos.X, pointMassPos.Y, 0, pointMassMass);

                // See if this pushes out the ball's overall radius
                curRadius = pointMassPos.GetMagnitude() + pointMassMass;		// I assume that the pointmass's mass is the same as its radius
                if (curRadius > ballRadius)
                {
                    ballRadius = curRadius;
                }
            }

            // Store the new radius
            ball.Radius = ballRadius * 1.1d;		// make it slightly bigger

            // Set the velocity
            ball.Velocity.Add(Utility3D.GetRandomVector(MAXVELOCITY));
            ball.Velocity.Z = 0;

            BallBlip blip = new BallBlip(ball, CollisionStyle.Standard, RadarBlipQual.BallUserDefined02, TokenGenerator.NextToken());

            _map.Add(blip);
        }
Exemple #9
0
        public static RadarBlip CloneBlip(RadarBlip blip, SimpleMap map)
        {
            BallBlip retVal = new BallBlip((Ball)blip.Sphere.Clone(), blip.CollisionStyle, blip.Qual, TokenGenerator.NextToken());
            retVal.Ball.Velocity.StoreNewValues(((Ball)blip.Sphere).Velocity);

            if (blip.Sphere is TorqueBall)
            {
                ((TorqueBall)retVal.Sphere).AngularMomentum.StoreNewValues(((TorqueBall)blip.Sphere).AngularMomentum);
            }

            return retVal;
        }
        private void TimerBalls()
        {
            #region Collide

            BallBlip collided1 = new BallBlip(_ball1.CloneBall(), CollisionStyle.Standard, RadarBlipQual.BallUserDefined00, 1);
            collided1.Ball.Velocity.StoreNewValues(_ball1.Velocity);
            BallBlip collided2 = new BallBlip(_ball2.CloneBall(), CollisionStyle.Standard, RadarBlipQual.BallUserDefined00, 2);
            collided2.Ball.Velocity.StoreNewValues(_ball2.Velocity);

            collided1.PrepareForNewCycle();
            collided2.PrepareForNewCycle();

            _collider.Collide(collided1, collided2);

            collided1.TimerTestPosition(1);
            collided2.TimerTestPosition(1);
            collided1.TimerFinish();
            collided2.TimerFinish();

            #endregion

            pictureBox1.PrepareForNewDraw();

            #region Draw Balls

            // Ball1
            pictureBox1.FillCircle(UtilityGDI.AlphaBlend(Color.Orange, Color.Silver, .25), _ball1.Position, _ball1.Radius);
            pictureBox1.DrawCircle(Color.DimGray, 1, _ball1.Position, _ball1.Radius);

            pictureBox1.DrawLine(Color.Yellow, 8, _ball1.Position, GetVelocityEnd(_ball1));
            pictureBox1.DrawLine(Color.Black, 4, _ball1.Position, GetVelocityEnd(_ball1.Position, collided1.Ball));

            if (_ball1 is TorqueBall)
            {
                pictureBox1.DrawLine(Color.White, 8, GetVelocityEnd(_ball1), GetAngularVelocityEnd((TorqueBall)_ball1));
                pictureBox1.DrawLine(Color.Brown, 4, GetVelocityEnd(_ball1.Position, collided1.Ball), GetAngularVelocityEnd(_ball1.Position, collided1.TorqueBall));
            }

            // Ball2
            pictureBox1.FillCircle(UtilityGDI.AlphaBlend(Color.DodgerBlue, Color.Silver, .5), _ball2.Position, _ball2.Radius);
            pictureBox1.DrawCircle(Color.DimGray, 1, _ball2.Position, _ball2.Radius);

            pictureBox1.DrawLine(UtilityGDI.AlphaBlend(Color.White, Color.Navy, .8), 8, _ball2.Position, GetVelocityEnd(_ball2));
            pictureBox1.DrawLine(Color.Black, 4, _ball2.Position, GetVelocityEnd(_ball2.Position, collided2.Ball));

            if (_ball2 is TorqueBall)
            {
                pictureBox1.DrawLine(Color.White, 8, GetVelocityEnd(_ball2), GetAngularVelocityEnd((TorqueBall)_ball2));
                pictureBox1.DrawLine(Color.Brown, 4, GetVelocityEnd(_ball2.Position, collided2.Ball), GetAngularVelocityEnd(_ball2.Position, collided2.TorqueBall));
            }

            #endregion

            pictureBox1.FinishedDrawing();
        }
Exemple #11
0
        private void CommitObject()
        {
            Ball newObject;
            #region Get the base object to add

            if (_drawingBall != null)
            {
                newObject = _drawingBall;
                _drawingBall = null;
            }
            else
            {
                newObject = BuildObject();
            }

            #endregion

            RadarBlipQual blipQual;
            #region Figure out the blipqual

            //TODO:  Define these as constants somewhere
            switch (_mode)
            {
                case AddingMode.AddBall:
                    blipQual = RadarBlipQual.BallUserDefined00;
                    break;

                case AddingMode.AddSolidBall:
                    blipQual = RadarBlipQual.BallUserDefined01;
                    break;

                case AddingMode.AddRigidBody:
                    blipQual = RadarBlipQual.BallUserDefined02;
                    break;

                default:
                    throw new ApplicationException("Unknown AddingMode: " + _mode.ToString());
            }

            #endregion

            // Create a blip to contain this object
            BallBlip blip = new BallBlip(newObject, _newBallProps.CollisionStyle, blipQual, TokenGenerator.NextToken());

            // If this is a torqueball, then it will get the angular velocity.  I have to wait until now, because
            // the size could change during a draw (you don't see it spin during the drag anyway, because I
            // don't call it's timer, so there is no reason to set angular velocity before now.)
            StoreAngularVelocity(blip.Ball);

            // Add it to the map
            _map.Add(blip);

            if (_newBallProps.Temporary)
            {
                _tempObjects.Add(blip.Token);
            }
        }
        private void PropsChangedSprtNew()
        {
            MyVector position = null;

            // Kill Existing
            if (_ship != null)
            {
                position = _ship.Ball.Position.Clone();
                _map.Remove(_ship.Token);
                _ship = null;
            }
            else
            {
                position = Utility3D.GetRandomVector(_boundryLower, _boundryUpper);
            }

            _tractorBeams.Clear();
            _cannon = null;
            _machineGuns.Clear();

            #region New Ship

            //TODO:  Listen to global props
            double elasticity = .75d;
            double kineticFriction = .75d;
            double staticFriction = 1d;

            // Build New
            Ball newBall;
            RadarBlipQual blipQual;        // logic came from BallAdder.CommitObject

            switch (_type)
            {
                case ShipTypeQual.None:
                    return;

                case ShipTypeQual.Ball:
                    #region Ball

                    newBall = new Ball(position, new DoubleVector(0, 1, 0, 1, 0, 0), _shipSize, UtilityCore.GetMassForRadius(_shipSize, 1d), elasticity, kineticFriction, staticFriction, _boundryLower, _boundryUpper);

                    blipQual = RadarBlipQual.BallUserDefined00;

                    _thrustForce = GetThrustForce(newBall.Mass);
                    _torqueballLeftRightThrusterForce = _thrustForce;

                    #endregion
                    break;

                case ShipTypeQual.SolidBall:
                    #region Solid Ball

                    newBall = new SolidBall(position, new DoubleVector(0, 1, 0, 1, 0, 0), _shipSize, UtilityCore.GetMassForRadius(_shipSize, 1d), elasticity, kineticFriction, staticFriction, _boundryLower, _boundryUpper);

                    blipQual = RadarBlipQual.BallUserDefined01;

                    _thrustForce = GetThrustForce(newBall.Mass);
                    _torqueballLeftRightThrusterForce = GetLeftRightThrusterMagnitude(((SolidBall)newBall).InertialTensorBody);

                    #endregion
                    break;

                default:
                    throw new ApplicationException("Unknown ShipTypeQual: " + _type.ToString());
            }

            newBall.RotateAroundAxis(new MyVector(0, 0, 1), Math.PI);

            // Finish Building
            _ship = new BallBlip(newBall, CollisionStyle.Standard, blipQual, _blipToken);
            _map.Add(_ship);

            #endregion

            if (this.CreateNewTractorBeams != null)
            {
                this.CreateNewTractorBeams(this, new EventArgs());
            }

            #region Guns

            _cannon = new ProjectileWeapon(300, 150, UtilityCore.GetMassForRadius(150, 1d), 25, true, _ignoreOtherProjectiles, RadarBlipQual.Projectile, false, _map, _boundryLower, _boundryUpper);
            _cannon.AddBarrel(_ship.Ball.OriginalDirectionFacing.Standard.Clone());
            _cannon.AddFiringMode(20);
            _cannon.SetProjectileExplosion(450, 2, 10000);
            _cannon.SeProjectileFuse(500);
            _cannon.SetShip(_ship);

            for (int cntr = 0; cntr < 2; cntr++)
            {
                ProjectileWeapon weapon = new ProjectileWeapon(30, 20, UtilityCore.GetMassForRadius(20, 1d), 100, true, _ignoreOtherProjectiles, RadarBlipQual.Projectile, false, _map, _boundryLower, _boundryUpper);
                weapon.AddBarrel(new MyVector(), new MyQuaternion());
                weapon.AddFiringMode(2);
                weapon.SetProjectileExplosion(40, 2, 300);
                weapon.SeProjectileFuse(500);
                weapon.SetShip(_ship);

                _machineGuns.Add(weapon);
            }

            #endregion
        }
 public Interaction(BallBlip blip, MyVector forceDirection, double force)
 {
     this.Blip = blip;
     this.ForceDirection = forceDirection;
     this.Force = force;
 }
        public TractorBeamCone(SimpleMap map, BallBlip ship, MyVector offset, DoubleVector dirFacing, BeamMode mode, bool isSoft, double sweepAngle, double maxDistance, double forceAtZero, double forceAtMax, double maxForcePerTick)
        {
            _map = map;

            _ship = ship;

            _offset = offset;
            _dirFacing = dirFacing;

            _mode = mode;

            _isSoft = isSoft;

            _sweepAngle = sweepAngle;
            _maxDistance = maxDistance;
            _forceAtZero = forceAtZero;
            _forceAtMax = forceAtMax;
            _maxForcePerTick = maxForcePerTick;
        }
        private void AddMultiBall(double radius, double mass)
        {
            // Physical Ball
            MyVector pos = Utility3D.GetRandomVector(BOUNDRY);
            DoubleVector dirFacing = new DoubleVector(1, 0, 0, 0, 1, 0);

            Ball ball = new Ball(pos, dirFacing, radius, mass, ELASTICITY, KINETICFRICTION, STATICFRICTION, _boundryLower, _boundryUpper);

            BallBlip blip = new BallBlip(ball, CollisionStyle.Standard, RadarBlipQual.BallUserDefined00, TokenGenerator.NextToken());
            _map.Add(blip);

            // WPF Rendering
            Geometry3D geometry = UtilityWPF.GetSphere(5, radius);
            Material material = new DiffuseMaterial(new SolidColorBrush(Color.FromArgb(255, Convert.ToByte(_rand.Next(256)), Convert.ToByte(_rand.Next(256)), Convert.ToByte(_rand.Next(256)))));
            GeometryModel3D geometryModel = new GeometryModel3D(geometry, material);
            geometryModel.Transform = new Transform3DGroup();

            //TODO:  Tie this transform directly to the ball's velocity (the shpere class should take the transform group)
            Transform3DGroup group = geometryModel.Transform as Transform3DGroup;
            group.Children.Clear();
            group.Children.Add(new TranslateTransform3D(pos.X, pos.Y, pos.Z));

            _geometries.Add(geometryModel);
            _modelGroup.Children.Add(geometryModel);
        }
        private void btnAddSolidBall_Click(object sender, EventArgs e)
        {
            double radius = _rand.Next(Convert.ToInt32(MINRADIUSMASS), Convert.ToInt32(MAXRADIUSMASS));
            double mass = GetMass(radius);
            double elasticity = GetElasticity();

            SolidBall ball = new SolidBall(Utility3D.GetRandomVector(_boundryLower, _boundryUpper), new DoubleVector(0, 1, 0, 1, 0, 0), radius, mass, elasticity, 1, 1, _boundryLower, _boundryUpper);
            ball.Velocity.Add(Utility3D.GetRandomVector(MAXVELOCITY));
            ball.Velocity.Z = 0;

            BallBlip blip = new BallBlip(ball, CollisionStyle.Standard, RadarBlipQual.BallUserDefined01, TokenGenerator.NextToken());

            _map.Add(blip);
        }
        private void CollideSprtBallTorqueBall(BallBlip ballBlip1, BallBlip ballBlip2)
        {
            // Make a temp torqueball to use in place of ball1
            BallBlip tempTorqueball = new BallBlip(new SolidBall(ballBlip1.Ball.Position, ballBlip1.Ball.OriginalDirectionFacing, ballBlip1.Ball.Radius, ballBlip1.Ball.Mass, ballBlip1.Ball.Elasticity, ballBlip1.Ball.KineticFriction, ballBlip1.Ball.StaticFriction, ballBlip1.Ball.BoundryLower, ballBlip1.Ball.BoundryUpper), ballBlip1.CollisionStyle, ballBlip1.Qual, ballBlip1.Token);
            tempTorqueball.Ball.Velocity.StoreNewValues(ballBlip1.Ball.Velocity);

            #region Treat them like solid balls

            if (ballBlip1.CollisionStyle == CollisionStyle.Standard)
            {
                if (ballBlip2.CollisionStyle == CollisionStyle.Standard)
                {
                    // Two standard balls
                    Collide_TorqueBallTorqueBall(tempTorqueball, ballBlip2);
                }
                else
                {
                    // One is standard, two is stationary
                    Collide_TorqueBallTorqueBall_2IsStationary(tempTorqueball, ballBlip2);
                }
            }
            else if (ballBlip2.CollisionStyle == CollisionStyle.Standard)
            {
                // One is stationary, two is standard
                Collide_TorqueBallTorqueBall_2IsStationary(ballBlip2, tempTorqueball);
            }

            // No need for an else.  There is nothing to do (both are stationary)

            #endregion

            // Apply the changes that were made to the temp torqueball onto the ball1
            ballBlip1.Ball.Velocity.StoreNewValues(tempTorqueball.Ball.Velocity);
        }
        private void chkIncludeShip_CheckedChanged(object sender, EventArgs e)
        {
            const double THRUSTERANGLE = 75;

            if (chkIncludeShip.Checked)
            {
                if (_ship == null)
                {
                    #region Create Ship

                    // Set up the ship
                    double radius = MINRADIUSMASS + (_rand.NextDouble() * (MAXRADIUSMASS - MINRADIUSMASS));
                    SolidBall ship = new SolidBall(Utility3D.GetRandomVector(_boundryLower, _boundryUpper), new DoubleVector(0, 1, 0, 1, 0, 0), radius, GetMass(radius), GetElasticity(), 1, 1, _boundryLower, _boundryUpper);

                    // Set up the thrusters
                    MyVector thrusterSeed = new MyVector(0, ship.Radius, 0);
                    MyVector zAxis = new MyVector(0, 0, 1);

                    // Bottom Thrusters
                    _shipThrusterOffset_BottomRight = thrusterSeed.Clone();
                    _shipThrusterOffset_BottomRight.RotateAroundAxis(zAxis, Utility3D.GetDegreesToRadians(THRUSTERANGLE * -1));

                    _shipThrusterOffset_BottomLeft = thrusterSeed.Clone();
                    _shipThrusterOffset_BottomLeft.RotateAroundAxis(zAxis, Utility3D.GetDegreesToRadians(THRUSTERANGLE));

                    // Top Thrusters
                    thrusterSeed = new MyVector(0, ship.Radius * -1, 0);
                    _shipThrusterOffset_TopRight = thrusterSeed.Clone();
                    _shipThrusterOffset_TopRight.RotateAroundAxis(zAxis, Utility3D.GetDegreesToRadians(THRUSTERANGLE));

                    _shipThrusterOffset_TopLeft = thrusterSeed.Clone();
                    _shipThrusterOffset_TopLeft.RotateAroundAxis(zAxis, Utility3D.GetDegreesToRadians(THRUSTERANGLE * -1));

                    // Add to the map
                    _ship = new BallBlip(ship, CollisionStyle.Standard, RadarBlipQual.BallUserDefined03, TokenGenerator.NextToken());
                    _map.Add(_ship);

                    #endregion
                }
            }
            else
            {
                if (_ship != null)
                {
                    _map.Remove(_ship.Token);
                    _ship = null;
                }
            }
        }
        /// <summary>
        /// This function pulls the items directly apart based on the ratio of their radii * mass
        /// </summary>
        protected void PullItemsApartInstant_BallBall(BallBlip ball1, BallBlip ball2)
        {
            // Get the vector from 2 to 1
            MyVector move1From2 = ball1.Ball.Position - ball2.Ball.Position;
            double totalDistance = move1From2.GetMagnitude() * _pullApartInstantPercent;		// distance from centers (exagerated by the percent passed in)
            double actualDistance = (ball1.Ball.Radius + ball2.Ball.Radius) - totalDistance;		// distance from edges

            // Make this a unit vector
            move1From2.Divide(totalDistance);

            double ratio1 = (ball1.Ball.Radius * ball1.Ball.Mass) / ((ball1.Ball.Radius * ball1.Ball.Mass) + (ball2.Ball.Radius * ball2.Ball.Mass));

            // Set their positions
            if (ball1.CollisionStyle == CollisionStyle.Standard)
            {
                ball1.Ball.Position.Add(move1From2 * (actualDistance * ratio1));
            }
            if (ball2.CollisionStyle == CollisionStyle.Standard)
            {
                ball2.Ball.Position.Add(move1From2 * (actualDistance * (1d - ratio1) * -1d));
            }
        }