Exemple #1
0
        private Point3D GetWorldCenterMass(Body body)
        {
            ConvexBody3D bodyCast = body as ConvexBody3D;

            if (bodyCast == null)
            {
                throw new ApplicationException("Couldn't cast body as a ConvexBody3D: " + body.ToString());
            }


            //TODO:  Put this in a property off of convexbody


            //// Get the center of mass in model coords
            //Point3D centerMass = bodyCast.CenterOfMass;
            //Vector3D retVal = new Vector3D(centerMass.X, centerMass.Y, centerMass.Z);

            //// Transform that into world coords
            //body.VisualMatrix.Transform(retVal);


            return(body.VisualMatrix.Transform(bodyCast.CenterOfMass));



            // Exit Function
            //return retVal;
        }
Exemple #2
0
        /// <summary>
        /// Set the properties, then call create
        /// NOTE:  This adds itself to the viewport and world.  In the future, that should be handled by the caller
        /// </summary>
        public void CreateAsteroid(MaterialManager materialManager, Map map, SharedVisuals sharedVisuals, Vector3D position)
        {
            _map = map;

            #region WPF Model

            // Material
            MaterialGroup materials = new MaterialGroup();
            materials.Children.Add(new DiffuseMaterial(Brushes.Gray));
            materials.Children.Add(new SpecularMaterial(Brushes.Silver, 100d));

            // Geometry Model
            GeometryModel3D geometry = new GeometryModel3D();
            geometry.Material     = materials;
            geometry.BackMaterial = materials;
            geometry.Geometry     = sharedVisuals.AsteroidMesh;
            geometry.Transform    = new ScaleTransform3D(_radius, _radius, _radius);

            // Model Visual
            ModelVisual3D model = new ModelVisual3D();
            model.Content   = geometry;
            model.Transform = new TranslateTransform3D(position);

            // Add to the viewport
            _visuals.Add(model);
            _map.Viewport.Children.Add(model);

            #endregion

            #region Physics Body

            // Make a physics body that represents this shape
            _physicsBody = new ConvexBody3D(_map.World, model);
            //_physicsBody = new ConvexBody3D(_map.World, model, ConvexBody3D.CollisionShape.Sphere, _radius, _radius, _radius);   // for some reason, this is throwing an exception.  debug it

            _physicsBody.MaterialGroupID = materialManager.AsteroidMaterialID;

            _physicsBody.NewtonBody.UserData = this;

            _physicsBody.Mass = Convert.ToSingle(_mass);

            _physicsBody.LinearDamping  = .01f;
            _physicsBody.AngularDamping = new Vector3D(.01f, .01f, .01f);
            _physicsBody.Override2DEnforcement_Rotation = true;

            _physicsBody.ApplyForce += new BodyForceEventHandler(Body_ApplyForce);

            #endregion

            // Add to the map
            _map.AddItem(this);
        }
Exemple #3
0
        private void CreateCube(Color color, Point3D location)
        {
            #region WPF Model

            // Material
            MaterialGroup materials = new MaterialGroup();
            materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(color)));
            materials.Children.Add(new SpecularMaterial(Brushes.White, 100d));

            // Geometry Model
            GeometryModel3D geometry = new GeometryModel3D();
            geometry.Material = materials;
            geometry.Geometry = UtilityWPF.GetCube(1d);
            //geometry.Geometry = UtilityWPF.GetRectangle3D()

            // Transform
            Transform3DGroup transform = new Transform3DGroup();                // rotate needs to be added before translate
            //transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(Math3D.GetRandomVectorSpherical(_rand, 10), Math3D.GetNearZeroValue(_rand, 360d))));
            transform.Children.Add(new TranslateTransform3D(location.ToVector()));

            // Model Visual
            ModelVisual3D model = new ModelVisual3D();
            model.Content   = geometry;
            model.Transform = transform;

            #endregion

            // Add to the viewport
            _viewport.Children.Add(model);

            // Make a physics body that represents this cube
            ConvexBody3D body = new ConvexBody3D(_world, model);
            body.Mass = 1f;

            _cubes.Add(body);
        }
Exemple #4
0
        public void CreateMineral(MaterialManager materialManager, Map map, SharedVisuals sharedVisuals, Vector3D position, bool randomOrientation, double volumeInCubicMeters)
        {
            _map           = map;
            _sharedVisuals = sharedVisuals;

            if (_mineralType == MineralType.Custom)
            {
                #region Validate

                if (_numSides < 3)
                {
                    throw new ApplicationException("The number of sides must at least be 3");
                }

                if (_rings.Count == 0)
                {
                    throw new ApplicationException("Need at least one ring");
                }

                #endregion
            }
            else
            {
                // Overwrite my public properties based on the mineral type
                StoreSettingsForMineralType(volumeInCubicMeters);
            }

            RotateTransform3D randomRotation = null;
            if (randomOrientation)
            {
                randomRotation = new RotateTransform3D(new AxisAngleRotation3D(Math3D.GetRandomVector_Spherical(1d), Math1D.GetNearZeroValue(360d)));
            }

            if (_mineralType == MineralType.Rixium)
            {
                #region Rixium Visuals

                Model3DGroup ringModels = new Model3DGroup();

                ringModels.Children.Add(GetRixiumTorusVisual(new Vector3D(0, 0, -.6), .38, .5, randomRotation));
                ringModels.Children.Add(GetRixiumTorusVisual(new Vector3D(0, 0, -.3), .44, .75, randomRotation));
                ringModels.Children.Add(GetRixiumTorusVisual(new Vector3D(0, 0, 0), .5, 1, randomRotation));
                ringModels.Children.Add(GetRixiumTorusVisual(new Vector3D(0, 0, .3), .44, .75, randomRotation));
                ringModels.Children.Add(GetRixiumTorusVisual(new Vector3D(0, 0, .6), .38, .5, randomRotation));

                //TODO:  Look at the global lighting options
                PointLight pointLight = new PointLight();
                pointLight.Color             = Color.FromArgb(255, 54, 147, 168);
                pointLight.Range             = 20;
                pointLight.LinearAttenuation = .33;
                ringModels.Children.Add(pointLight);

                ModelVisual3D ringModel = new ModelVisual3D();        // this is the expensive one, so as few of these should be made as possible
                ringModel.Content = ringModels;

                _visuals.Add(ringModel);
                _map.Viewport.Children.Add(ringModel);

                #endregion
            }

            #region WPF Model

            // Material
            MaterialGroup materials = new MaterialGroup();
            if (_diffuseColor.A > 0)
            {
                materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(_diffuseColor)));
            }

            if (_specularColor.A > 0)
            {
                materials.Children.Add(new SpecularMaterial(new SolidColorBrush(_specularColor), _specularPower));
            }

            if (_emissiveColor.A > 0)
            {
                materials.Children.Add(new EmissiveMaterial(new SolidColorBrush(_emissiveColor)));
            }

            // Geometry Model
            GeometryModel3D geometry = new GeometryModel3D();
            geometry.Material     = materials;
            geometry.BackMaterial = materials;

            if (_mineralType == MineralType.Custom)
            {
                geometry.Geometry = UtilityWPF.GetMultiRingedTube_ORIG(_numSides, _rings, false, true);
            }
            else
            {
                geometry.Geometry = _sharedVisuals.GetMineralMesh(_mineralType);
            }
            if (randomOrientation)
            {
                geometry.Transform = randomRotation;
            }

            // Model Visual
            ModelVisual3D model = new ModelVisual3D();
            model.Content   = geometry;
            model.Transform = new TranslateTransform3D(position);

            // Add to the viewport
            _visuals.Add(model);
            _map.Viewport.Children.Add(model);

            #endregion

            #region Physics Body

            // Make a physics body that represents this shape
            _physicsBody = new ConvexBody3D(_map.World, model);

            _physicsBody.MaterialGroupID = materialManager.MineralMaterialID;

            _physicsBody.NewtonBody.UserData = this;

            _physicsBody.Mass = Convert.ToSingle(_mass);

            _physicsBody.LinearDamping  = .01f;
            _physicsBody.AngularDamping = new Vector3D(.01f, .01f, .01f);
            _physicsBody.Override2DEnforcement_Rotation = true;

            _physicsBody.ApplyForce += new BodyForceEventHandler(Body_ApplyForce);

            #endregion

            // Add to the map
            _map.AddItem(this);
        }
Exemple #5
0
 public PointVisualizer(Viewport3D viewport, SharedVisuals sharedVisuals, ConvexBody3D physicsBody)
     : this(viewport, sharedVisuals)
 {
     _physicsBody = physicsBody;
 }
Exemple #6
0
        private void Body_ApplyForce(Body sender, BodyForceEventArgs e)
        {
            ConvexBody3D senderCast = sender as ConvexBody3D;

            if (senderCast == null)
            {
                return;
            }

            #region Boundry Force

            Vector3D positionWorld = senderCast.PositionToWorld(senderCast.CenterOfMass).ToVector();

            // Just using one property from boundry assumes the boundry is square, and max is positive
            double boundryMax  = _boundryMax.X;
            double maxDistance = _boundryMax.X * .85d;
            if (positionWorld.LengthSquared > maxDistance * maxDistance)
            {
                // Get the distance from the max distance
                double distFromMax = positionWorld.Length - maxDistance;     // wait till now to do the expensive operation.

                // I want an acceleration of zero when distFromMax is 1, but an accel of 10 when it's boundryMax
                //NOTE: _boundryMax.X is to the edge of the box.  If they are in the corner the distance will be greater, so the accel will be greater
                double accel = UtilityCore.GetScaledValue(0, 30, 0, boundryMax - maxDistance, distFromMax);

                // Apply a force
                Vector3D force = positionWorld;
                force.Normalize();
                force *= accel * senderCast.Mass * -1d;
                e.AddForce(force);
            }

            #endregion

            #region Gravity

            if (_hasGravity)
            {
                //TODO:  Attract all other objects to the asteroids
                if (senderCast.MaterialGroupID == _materialManager.AsteroidMaterialID && _asteroidGravityForces.ContainsKey(senderCast))
                {
                    e.AddForce(_asteroidGravityForces[senderCast]);
                }
                else if (senderCast.MaterialGroupID == _materialManager.ShipMaterialID && _asteroidGravityForces.Keys.Count > 0)                // the asteroids only attract every few frames.  If I attract every frame, the forces are unbalanced, and the ship ends up propelling the asteroid around
                {
                    #region Ship to asteroids

                    Point3D shipPos  = senderCast.PositionToWorld(senderCast.CenterOfMass);
                    double  shipMass = senderCast.Mass;

                    Vector3D gravityForce = new Vector3D(0, 0, 0);

                    foreach (Asteroid asteroid in _asteroids)
                    {
                        #region Apply Gravity

                        Vector3D gravityLink = shipPos - asteroid.PositionWorld;

                        double force = GRAVITATIONALCONSTANT * (asteroid.Mass * shipMass) / gravityLink.LengthSquared;

                        gravityLink.Normalize();
                        gravityLink *= force;

                        //_asteroidGravityForces[_asteroids[innerCntr].PhysicsBody] += gravityLink;
                        gravityForce -= gravityLink;

                        #endregion
                    }

                    e.AddForce(gravityForce);

                    #endregion
                }
            }

            #endregion

            #region Set Velocities

            if (_setVelocityArgs != null)
            {
                _hasSetVelocities = true;

                // See if the velocity should be set for this type of object
                bool shouldSetVelocity = false;
                if (_setVelocityArgs.Asteroids && senderCast.MaterialGroupID == _materialManager.AsteroidMaterialID)
                {
                    shouldSetVelocity = true;
                }
                else if (_setVelocityArgs.Minerals && senderCast.MaterialGroupID == _materialManager.MineralMaterialID)
                {
                    shouldSetVelocity = true;
                }

                if (shouldSetVelocity)
                {
                    // Figure out the velocity
                    Vector3D velocity        = new Vector3D(0, 0, 0);
                    Vector3D angularVelocity = new Vector3D(0, 0, 0);
                    if (_setVelocityArgs.Speed > 0d)
                    {
                        velocity        = Math3D.GetRandomVector_Spherical(_setVelocityArgs.Speed);
                        angularVelocity = Math3D.GetRandomVector_Spherical(_setVelocityArgs.Speed / 10d);

                        if (_setVelocityArgs.IsRandom)
                        {
                            double halfSpeed = _setVelocityArgs.Speed / 2d;
                            if (velocity.Length < halfSpeed)
                            {
                                // It's going too slow, choose a new speed between half and full
                                velocity.Normalize();
                                double newSpeed = halfSpeed + (StaticRandom.NextDouble() * halfSpeed);
                                velocity *= newSpeed;
                            }
                        }
                        else
                        {
                            // GetRandomVectorSpherical returns random, but this should be fixed
                            velocity.Normalize();
                            velocity *= _setVelocityArgs.Speed;
                        }
                    }

                    // Set it (and clear rotation)
                    senderCast.Omega    = angularVelocity;
                    senderCast.Velocity = velocity;
                }
            }

            #endregion
        }
Exemple #7
0
        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            const double MINRATIO = .25d;
            const double MAXRATIO = 2d;
            const double MINMASS  = .9d;
            const double MAXMASS  = 5d;

            try
            {
                double ratioX, ratioY, ratioZ;
                if (chkRandomRatios.IsChecked.Value)
                {
                    ratioX = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, 0d, 1d, StaticRandom.NextDouble());
                    ratioY = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, 0d, 1d, StaticRandom.NextDouble());
                    ratioZ = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, 0d, 1d, StaticRandom.NextDouble());
                }
                else
                {
                    ratioX = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, trkX.Minimum, trkX.Maximum, trkX.Value);
                    ratioY = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, trkY.Minimum, trkY.Maximum, trkY.Value);
                    ratioZ = UtilityCore.GetScaledValue(MINRATIO, MAXRATIO, trkZ.Minimum, trkZ.Maximum, trkZ.Value);
                }

                #region WPF Model

                // Material
                MaterialGroup materials = new MaterialGroup();
                materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.GetRandomColor(64, 192))));
                materials.Children.Add(new SpecularMaterial(Brushes.White, 100d));

                // Geometry Model
                GeometryModel3D geometry = new GeometryModel3D();
                geometry.Material     = materials;
                geometry.BackMaterial = materials;
                geometry.Geometry     = UtilityWPF.GetCube(new Point3D(-ratioX, -ratioY, -ratioZ), new Point3D(ratioX, ratioY, ratioZ));
                //geometry.Geometry = UtilityWPF.GetRectangle3D()

                // Transform
                Transform3DGroup transform = new Transform3DGroup();            // rotate needs to be added before translate
                transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(Math3D.GetRandomVector_Spherical(10), Math1D.GetNearZeroValue(360d))));
                transform.Children.Add(new TranslateTransform3D(Math3D.GetRandomVector(_boundryMin, _boundryMax)));

                // Model Visual
                ModelVisual3D model = new ModelVisual3D();
                model.Content   = geometry;
                model.Transform = transform;

                #endregion

                // Add to the viewport
                _viewport.Children.Add(model);

                // Make a physics body that represents this cube
                ConvexBody3D body = new ConvexBody3D(_world, model);

                if (chkConstantMass.IsChecked.Value)
                {
                    body.Mass = 1f;
                }
                else
                {
                    // If I try to be realistic, then it's boring, so I'll scale the result.  (density shrinks a bit as things get larger)
                    double mass = ratioX * ratioY * ratioZ;
                    mass      = UtilityCore.GetScaledValue(MINMASS, MAXMASS, Math.Pow(MINRATIO, 3), Math.Pow(MAXRATIO, 3), mass);
                    body.Mass = Convert.ToSingle(mass);
                }

                body.LinearDamping  = .01f;
                body.AngularDamping = new Vector3D(.01f, .01f, .01f);

                //TODO:  Make this work
                //body.Velocity =

                //needed?
                //_world.AddBody(body);


                body.ApplyForce += new BodyForceEventHandler(Body_ApplyForce);



                _cubes.Add(body);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
Exemple #8
0
        /// <summary>
        /// Set the properties, then call create
        /// NOTE:  This adds itself to the viewport and world.  In the future, that should be handled by the caller
        /// </summary>
        public void CreateShip(MaterialManager materialManager, SharedVisuals sharedVisuals, Map map, ProgressBarGame progressBarCargo, ProgressBarGame progressBarFuel)
        {
            const double THRUSTLINELENGTH       = .5d;
            const double THRUSTLINELENGTH_EXTRA = .75d;
            const double THRUSTLINELENGTH_TURN  = .3;

            _sharedVisuals    = sharedVisuals;
            _map              = map;
            _progressBarCargo = progressBarCargo;
            _progressBarFuel  = progressBarFuel;

            #region Thrusters

            // These need to be definded before the visuals are created
            double radians = Math1D.DegreesToRadians(225);
            _thrusterOffset_BottomLeft = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0);
            radians = Math1D.DegreesToRadians(135);
            _thrusterOffset_TopLeft = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0);

            radians = Math1D.DegreesToRadians(315);
            _thrusterOffset_BottomRight = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0);
            radians = Math1D.DegreesToRadians(45);
            _thrusterOffset_TopRight = new Vector3D(this.RadiusX * Math.Cos(radians), this.RadiusY * Math.Sin(radians), 0);

            _thrustForce = 100d;
            _torqueballLeftRightThrusterForce = -10d;

            #region Define ThrustLines

            //NOTE: The ThrustLine class will add/remove visuals directly from the viewport.  There's no need for the map to get involved

            // The reference to the fuel tank will be made when I create the tank

            ThrustLine thrustLine;

            // Up
            _thrustLines.Add(Key.Up, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _thrustForce, _thrusterOffset_BottomRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.Up].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _thrustForce, _thrusterOffset_BottomLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.Up].Add(thrustLine);

            // W
            _thrustLines.Add(Key.W, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * (_thrustForce * 2d), _thrusterOffset_BottomRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA;
            _thrustLines[Key.W].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * (_thrustForce * 2d), _thrusterOffset_BottomLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA;
            _thrustLines[Key.W].Add(thrustLine);

            // Down
            _thrustLines.Add(Key.Down, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _thrustForce, _thrusterOffset_TopRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.Down].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _thrustForce, _thrusterOffset_TopLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.Down].Add(thrustLine);

            // S
            _thrustLines.Add(Key.S, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * (_thrustForce * 2d), _thrusterOffset_TopRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA;
            _thrustLines[Key.S].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * (_thrustForce * 2d), _thrusterOffset_TopLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_EXTRA;
            _thrustLines[Key.S].Add(thrustLine);

            // Left
            _thrustLines.Add(Key.Left, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_BottomRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN;
            _thrustLines[Key.Left].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_TopLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN;
            _thrustLines[Key.Left].Add(thrustLine);

            // Right
            _thrustLines.Add(Key.Right, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, 1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_TopRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN;
            _thrustLines[Key.Right].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(0, -1, 0) * _torqueballLeftRightThrusterForce, _thrusterOffset_BottomLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH_TURN;
            _thrustLines[Key.Right].Add(thrustLine);

            // A
            _thrustLines.Add(Key.A, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(-1, 0, 0) * _thrustForce, _thrusterOffset_TopRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.A].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(-1, 0, 0) * _thrustForce, _thrusterOffset_BottomRight);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.A].Add(thrustLine);

            // D
            _thrustLines.Add(Key.D, new List <ThrustLine>());

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(1, 0, 0) * _thrustForce, _thrusterOffset_TopLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.D].Add(thrustLine);

            thrustLine = new ThrustLine(_map.Viewport, _sharedVisuals, new Vector3D(1, 0, 0) * _thrustForce, _thrusterOffset_BottomLeft);
            thrustLine.LineMaxLength = THRUSTLINELENGTH;
            _thrustLines[Key.D].Add(thrustLine);

            #endregion

            #endregion

            MaterialGroup   material = null;
            GeometryModel3D geometry = null;
            Model3DGroup    models   = new Model3DGroup();
            ModelVisual3D   model    = null;

            #region Interior Extra Visuals

            // These are visuals that will stay oriented to the ship, but don't count in collision calculations

            #region Thrusters

            // These are the little balls, not the thrust lines

            double thrusterLocScale = 1d;

            models.Children.Add(GetThrusterVisual(_thrusterOffset_BottomLeft * thrusterLocScale));
            models.Children.Add(GetThrusterVisual(_thrusterOffset_BottomRight * thrusterLocScale));
            models.Children.Add(GetThrusterVisual(_thrusterOffset_TopLeft * thrusterLocScale));
            models.Children.Add(GetThrusterVisual(_thrusterOffset_TopRight * thrusterLocScale));

            #endregion
            #region Cargo Bay

            //TODO:  Make a visual for this (probably pretty cube like)

            _cargoBay = new CargoBay(_cargoBayMass, _cargoBayVolume);

            _progressBarCargo.Minimum = 0d;
            _progressBarCargo.Maximum = _cargoBay.MaxVolume;
            _progressBarCargo.Value   = 0d;

            #endregion
            #region Fuel Tank

            //TODO:  This visual should be a pill

            _fuelTank                 = new FuelTank();
            _fuelTank.DryMass         = _fuelTankMass;
            _fuelTank.QuantityMax     = _fuelTankCapacity;
            _fuelTank.QuantityCurrent = _fuelTank.QuantityMax;          // a full tank with the purchace of a new ship!!!
            _fuelTank.FuelDensity     = _fuelDensity;

            _progressBarFuel.Minimum = 0d;
            _progressBarFuel.Maximum = _fuelTank.QuantityMax;
            _progressBarFuel.Value   = _fuelTank.QuantityCurrent;

            // Link to the thrusters
            foreach (List <ThrustLine> thrustLines in _thrustLines.Values)
            {
                foreach (ThrustLine thrustLine1 in thrustLines)
                {
                    thrustLine1.FuelToThrustRatio = _fuelThrustRatio;
                    thrustLine1.FuelTank          = _fuelTank;
                }
            }

            #endregion

            #region Core

            // This just looks stupid.  The idea is that you would see the various components (which would also be point masses).  But until
            // the user can modify their ship, it's just an arbitrary ellipse that is ugly

            //// Material
            //material = new MaterialGroup();
            //material.Children.Add(new DiffuseMaterial(Brushes.DimGray));
            //material.Children.Add(new SpecularMaterial(Brushes.DimGray, 100d));

            //// Geometry Model
            //geometry = new GeometryModel3D();
            //geometry.Material = material;
            //geometry.BackMaterial = material;
            //geometry.Geometry = UtilityWPF.GetSphere(5, .45, .25, .05);
            //geometry.Transform = new TranslateTransform3D(0, this.RadiusY * -.25, 0);

            //// Model Visual
            //model = new ModelVisual3D();
            //model.Content = geometry;

            ////NOTE: model.Transform is set to the physics body's transform every frame

            //// Add to the viewport
            //_viewport.Children.Add(model);

            //_visuals.Add(model);

            #endregion

            // Make a model visual for what I have so far
            model         = new ModelVisual3D(); // this is the expensive one, so as few of these should be made as possible
            model.Content = models;

            _visuals.Add(model);
            _map.Viewport.Children.Add(model);

            #endregion

            #region WPF Collision Model

            // Material
            //NOTE:  There seems to be an issue with drawing objects inside a semitransparent object - I think they have to be added in a certain order or something
            //Brush skinBrush = new SolidColorBrush(Color.FromArgb(50, _hullColor.R, _hullColor.G, _hullColor.B));  // making the skin semitransparent, so you can see the components inside
            Brush skinBrush = new SolidColorBrush(_hullColor);  // decided to make it opaque, since I'm not showing anything inside

            material = new MaterialGroup();
            material.Children.Add(new DiffuseMaterial(skinBrush));
            material.Children.Add(new SpecularMaterial(Brushes.White, 75d));     // more reflective (and white light)

            MaterialGroup backMaterial = new MaterialGroup();
            backMaterial.Children.Add(new DiffuseMaterial(skinBrush));
            backMaterial.Children.Add(new SpecularMaterial(new SolidColorBrush(Color.FromArgb(255, 20, 20, 20)), 10d));       // dark light, and not very reflective

            // Geometry Model
            geometry              = new GeometryModel3D();
            geometry.Material     = material;
            geometry.BackMaterial = backMaterial;
            geometry.Geometry     = UtilityWPF.GetSphere_LatLon(5, this.RadiusX, this.RadiusY, this.RadiusZ);

            // Transform
            Transform3DGroup transform = new Transform3DGroup();                // rotate needs to be added before translate
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 0)));
            transform.Children.Add(new TranslateTransform3D(new Vector3D(0, 0, 0)));

            // Model Visual
            model           = new ModelVisual3D();
            model.Content   = geometry;
            model.Transform = transform;

            _physicsModel = model;    // remember this, so I don't set its transform
            _visuals.Add(model);

            // Add to the viewport (the physics body constructor requires it to be added)
            _map.Viewport.Children.Add(model);

            #endregion
            #region Physics Body

            // Make a physics body that represents this shape
            _physicsBody = new ConvexBody3D(_map.World, model);

            _physicsBody.MaterialGroupID = materialManager.ShipMaterialID;

            _physicsBody.NewtonBody.UserData = this;

            _physicsBody.Mass = Convert.ToSingle(this.TotalMass);

            _physicsBody.LinearDamping = .01f;
            //_physicsBody.AngularDamping = new Vector3D(.01f, .01f, .01f);
            //_physicsBody.AngularDamping = new Vector3D(10f, 10f, 10f);
            _physicsBody.AngularDamping = new Vector3D(1f, 1f, 1f);

            _physicsBody.ApplyForce += new BodyForceEventHandler(Body_ApplyForce);

            #endregion

            #region Exterior Extra Visuals

            // There is a bug in WPF where visuals added after a semitransparent one won't show inside.  The cockpit looks stupid when you can see
            // it inside the skin

            #region Cockpit

            // Material
            material = new MaterialGroup();
            material.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.AlphaBlend(Colors.Teal, Colors.DimGray, .2d))));
            material.Children.Add(new SpecularMaterial(Brushes.White, 100d));

            // Geometry Model
            geometry              = new GeometryModel3D();
            geometry.Material     = material;
            geometry.BackMaterial = material;
            //geometry.Geometry = UtilityWPF.GetSphere(3, .4, .2, .3);
            geometry.Geometry  = UtilityWPF.GetSphere_LatLon(3, .45, .25, .25);
            geometry.Transform = new TranslateTransform3D(0, this.RadiusY * .5, 0);

            // Model Visual
            model         = new ModelVisual3D();
            model.Content = geometry;

            // Add to the viewport
            _visuals.Add(model);
            _map.Viewport.Children.Add(model);

            #endregion
            #region Headlight

            SpotLight spotLight = new SpotLight();
            //spotLight.Color = Color.FromArgb(255, 50, 170, 50);
            spotLight.Color          = UtilityWPF.AlphaBlend(Colors.White, _hullColor, .25d);
            spotLight.Direction      = new Vector3D(0, 1, 0);
            spotLight.OuterConeAngle = 25;
            spotLight.InnerConeAngle = 5;
            //spotLight.LinearAttenuation = .1;
            spotLight.QuadraticAttenuation = .0001;
            spotLight.Range = 1000;

            model         = new ModelVisual3D();
            model.Content = spotLight;

            _visuals.Add(model);
            _map.Viewport.Children.Add(model);

            #endregion

            #endregion

            // Add to the map
            _map.AddItem(this);
        }
        private void btnAdd_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Figure out the ratios and mass of this body
                ConvexBody3D.CollisionShape shape;
                double ratioX, ratioY, ratioZ, mass;
                GetRatiosMass(out shape, out ratioX, out ratioY, out ratioZ, out mass);

                #region WPF Model

                // Material
                MaterialGroup materials = new MaterialGroup();
                materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.GetRandomColor(64, 192))));
                materials.Children.Add(new SpecularMaterial(Brushes.White, 100d));

                // Geometry Model
                GeometryModel3D geometry = new GeometryModel3D();
                geometry.Material     = materials;
                geometry.BackMaterial = materials;

                switch (shape)
                {
                case ConvexBody3D.CollisionShape.Cube:
                    geometry.Geometry = UtilityWPF.GetCube(new Point3D(-ratioX, -ratioY, -ratioZ), new Point3D(ratioX, ratioY, ratioZ));
                    break;

                case ConvexBody3D.CollisionShape.Sphere:
                    geometry.Geometry = UtilityWPF.GetSphere_LatLon(5, ratioX, ratioY, ratioZ);
                    //geometry.Geometry = UtilityWPF.GetTorus(30, 10, ratioX * .2, ratioX);    //
                    break;

                case ConvexBody3D.CollisionShape.Capsule:
                case ConvexBody3D.CollisionShape.ChamferCylinder:
                case ConvexBody3D.CollisionShape.Cone:
                case ConvexBody3D.CollisionShape.Cylinder:
                default:
                    throw new ApplicationException("Unknown ConvexBody3D.CollisionShape: " + shape.ToString());
                }

                // Transform
                Transform3DGroup transform = new Transform3DGroup();            // rotate needs to be added before translate
                transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(Math3D.GetRandomVector_Spherical(10), Math1D.GetNearZeroValue(360d))));
                transform.Children.Add(new TranslateTransform3D(Math3D.GetRandomVector(CREATEOBJECTBOUNDRY)));

                // Model Visual
                ModelVisual3D model = new ModelVisual3D();
                model.Content   = geometry;
                model.Transform = transform;

                #endregion

                // Add to the viewport
                _viewport.Children.Add(model);

                // Make a physics body that represents this shape
                ConvexBody3D body = new ConvexBody3D(_world, model);

                body.Mass = Convert.ToSingle(mass);

                body.LinearDamping  = .01f;
                body.AngularDamping = new Vector3D(.01f, .01f, .01f);

                body.ApplyForce += new BodyForceEventHandler(Body_ApplyForce);

                _bodies.Add(body);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }