private void btnBodyPropeller3_Click(object sender, RoutedEventArgs e)
        {
            //TODO:  This is just a tweaked copy of 2 (I was feeling lazy).  They should really be merged

            RemoveCurrentBody();

            _world.Pause();

            // Materials
            MaterialGroup materialsFluidBlade = new MaterialGroup();		// These blades are what the fluid model knows about, but newton will know about a more complex object
            materialsFluidBlade.Children.Add(new DiffuseMaterial(new SolidColorBrush(_colors.HullFace)));
            materialsFluidBlade.Children.Add(_colors.HullFaceSpecular);

            MaterialGroup materialsPhysics = new MaterialGroup();		// this is the material for the composite physics object
            materialsPhysics.Children.Add(new DiffuseMaterial(new SolidColorBrush(_colors.GhostBodyFace)));
            materialsPhysics.Children.Add(_colors.GhostBodySpecular);

            // Geometries
            MeshGeometry3D meshFluidBlade = new MeshGeometry3D();

            MeshGeometry3D meshPhysicsBlade1 = null;
            MeshGeometry3D meshPhysicsBlade2 = null;
            MeshGeometry3D meshPhysicsBlade3 = null;
            MeshGeometry3D meshPhysicsCone = null;

            // Centered blade positions (these are defined once, then copies will be transformed and commited)
            Point3D[] bladePositionsFluid = new Point3D[4];
            bladePositionsFluid[0] = new Point3D(-1d, .25d, 0d);
            bladePositionsFluid[1] = new Point3D(-1d, -.25d, 0d);
            bladePositionsFluid[2] = new Point3D(1d, -.25d, 0d);
            bladePositionsFluid[3] = new Point3D(1d, .25d, 0d);

            Point3D[] bladePositionsPhysics = new Point3D[2];
            bladePositionsPhysics[0] = new Point3D(-1d, -.25d, -.05d);
            bladePositionsPhysics[1] = new Point3D(1d, .25d, .05d);

            // This tranform is throw away.  It's just used to transform points
            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90d + 5d)));		// rotar tilt (the flow defaults to -x, so face them into the wind)
            transform.Children.Add(new TranslateTransform3D(new Vector3D(1d + .33d, 0, 0)));		// pull away from the center a bit
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 90)));		// I don't want it along X, I want it along Y

            // Fluid blade 1
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[0]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[1]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[2]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[3]));

            meshFluidBlade.TriangleIndices.Add(0);
            meshFluidBlade.TriangleIndices.Add(1);
            meshFluidBlade.TriangleIndices.Add(2);
            meshFluidBlade.TriangleIndices.Add(2);
            meshFluidBlade.TriangleIndices.Add(3);
            meshFluidBlade.TriangleIndices.Add(0);

            // Physics blade 1
            meshPhysicsBlade1 = UtilityWPF.GetCube_IndependentFaces(bladePositionsPhysics[0], bladePositionsPhysics[1]);
            CollisionHull collisionPhysicsBlade1 = CollisionHull.CreateBox(_world, 0, bladePositionsPhysics[1] - bladePositionsPhysics[0], transform.Value);
            Transform3D transformPhysicsBlade1 = transform.Clone();

            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 120d)));		// rotate the whole thing 120 degrees

            // Fluid blade 2
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[0]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[1]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[2]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[3]));

            meshFluidBlade.TriangleIndices.Add(0 + 4);
            meshFluidBlade.TriangleIndices.Add(1 + 4);
            meshFluidBlade.TriangleIndices.Add(2 + 4);
            meshFluidBlade.TriangleIndices.Add(2 + 4);
            meshFluidBlade.TriangleIndices.Add(3 + 4);
            meshFluidBlade.TriangleIndices.Add(0 + 4);

            // Physics blade 2
            meshPhysicsBlade2 = UtilityWPF.GetCube_IndependentFaces(bladePositionsPhysics[0], bladePositionsPhysics[1]);
            CollisionHull collisionPhysicsBlade2 = CollisionHull.CreateBox(_world, 0, bladePositionsPhysics[1] - bladePositionsPhysics[0], transform.Value);
            Transform3D transformPhysicsBlade2 = transform.Clone();

            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 120d)));		// rotate the whole thing 120 degrees

            // Fluid blade 3
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[0]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[1]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[2]));
            meshFluidBlade.Positions.Add(transform.Transform(bladePositionsFluid[3]));

            meshFluidBlade.TriangleIndices.Add(0 + 8);
            meshFluidBlade.TriangleIndices.Add(1 + 8);
            meshFluidBlade.TriangleIndices.Add(2 + 8);
            meshFluidBlade.TriangleIndices.Add(2 + 8);
            meshFluidBlade.TriangleIndices.Add(3 + 8);
            meshFluidBlade.TriangleIndices.Add(0 + 8);

            // Physics blade 3
            meshPhysicsBlade3 = UtilityWPF.GetCube_IndependentFaces(bladePositionsPhysics[0], bladePositionsPhysics[1]);
            CollisionHull collisionPhysicsBlade3 = CollisionHull.CreateBox(_world, 0, bladePositionsPhysics[1] - bladePositionsPhysics[0], transform.Value);
            Transform3D transformPhysicsBlade3 = transform.Clone();

            //TODO:  Make an overload on some of the geometry builders that take a tranform
            //meshPhysicsCone = UtilityWPF.GetCone_AlongX();

            // Geometry Models
            GeometryModel3D geometryFluidBlade = new GeometryModel3D();
            geometryFluidBlade.Material = materialsFluidBlade;
            geometryFluidBlade.BackMaterial = materialsFluidBlade;
            geometryFluidBlade.Geometry = meshFluidBlade;

            GeometryModel3D geometryPhysicsBlade1 = new GeometryModel3D();
            geometryPhysicsBlade1.Material = materialsPhysics;
            geometryPhysicsBlade1.BackMaterial = materialsPhysics;
            geometryPhysicsBlade1.Geometry = meshPhysicsBlade1;
            geometryPhysicsBlade1.Transform = transformPhysicsBlade1;

            GeometryModel3D geometryPhysicsBlade2 = new GeometryModel3D();
            geometryPhysicsBlade2.Material = materialsPhysics;
            geometryPhysicsBlade2.BackMaterial = materialsPhysics;
            geometryPhysicsBlade2.Geometry = meshPhysicsBlade2;
            geometryPhysicsBlade2.Transform = transformPhysicsBlade2;

            GeometryModel3D geometryPhysicsBlade3 = new GeometryModel3D();
            geometryPhysicsBlade3.Material = materialsPhysics;
            geometryPhysicsBlade3.BackMaterial = materialsPhysics;
            geometryPhysicsBlade3.Geometry = meshPhysicsBlade3;
            geometryPhysicsBlade3.Transform = transformPhysicsBlade3;

            // Model Visual
            ModelVisual3D modelFluidBlade = new ModelVisual3D();
            modelFluidBlade.Content = geometryFluidBlade;
            modelFluidBlade.Transform = _modelOrientationTrackball.Transform;

            ModelVisual3D modelPysicsBlade1 = new ModelVisual3D();
            modelPysicsBlade1.Content = geometryPhysicsBlade1;
            modelPysicsBlade1.Transform = _modelOrientationTrackball.Transform;

            ModelVisual3D modelPysicsBlade2 = new ModelVisual3D();
            modelPysicsBlade2.Content = geometryPhysicsBlade2;
            modelPysicsBlade2.Transform = _modelOrientationTrackball.Transform;

            ModelVisual3D modelPysicsBlade3 = new ModelVisual3D();
            modelPysicsBlade3.Content = geometryPhysicsBlade3;
            modelPysicsBlade3.Transform = _modelOrientationTrackball.Transform;

            CollisionHull collisionHull = CollisionHull.CreateCompoundCollision(_world, 0, new CollisionHull[] { collisionPhysicsBlade1, collisionPhysicsBlade2, collisionPhysicsBlade3 });

            // Body
            _body = new Body(collisionHull, _modelOrientationTrackball.Transform.Value, 1, null);
            collisionHull.Dispose();
            collisionPhysicsBlade1.Dispose();
            collisionPhysicsBlade2.Dispose();
            collisionPhysicsBlade3.Dispose();

            // Hull
            _fluidHull = new FluidHull();
            _fluidHull.Triangles = FluidHull.FluidTriangle.GetTrianglesFromMesh(meshFluidBlade);
            _fluidHull.IsClosedConvexInUniformField = false;
            _fluidHull.Transform = _modelOrientationTrackball.Transform;
            _fluidHull.Field = _field;
            _fluidHull.Body = _body;

            // Wireframe
            ScreenSpaceLines3D modelWireframe = GetModelWireframe(_fluidHull);
            modelWireframe.Transform = _modelOrientationTrackball.Transform;
            _viewport.Children.Add(modelWireframe);

            // Rope
            Point3D bodyAttachPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(.25, 0, 0));
            Point3D anchorPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(3, 0, 0));
            //Point3D bodyAttachPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(0, 0, 0));
            //Point3D anchorPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(.33, 0, 0));
            AddRope(bodyAttachPoint, anchorPoint, Math1D.DegreesToRadians(1d));

            // Add to the viewport
            _viewport.Children.Add(modelFluidBlade);
            _viewport.Children.Add(modelPysicsBlade1);
            _viewport.Children.Add(modelPysicsBlade2);
            _viewport.Children.Add(modelPysicsBlade3);

            // Finish setting up the body
            _body.Visuals = new Visual3D[] { modelPysicsBlade1, modelPysicsBlade2, modelPysicsBlade3, modelWireframe, modelFluidBlade };
            _body.ApplyForceAndTorque += new EventHandler<BodyApplyForceAndTorqueArgs>(Body_ApplyForceAndTorque);
            _body.BodyMoved += new EventHandler(Body_BodyMoved);

            _world.UnPause();
        }
        private void btnBodyPropellerPlates_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                RemoveCurrentBody();

                _world.Pause();

                // Material
                MaterialGroup materials = new MaterialGroup();
                materials.Children.Add(new DiffuseMaterial(new SolidColorBrush(_colors.HullFace)));
                materials.Children.Add(_colors.HullFaceSpecular);

                #region Templates

                // These positions are transformed for each blade
                Point3D[] bladePositions = new Point3D[2];
                bladePositions[0] = new Point3D(-1d, -.25d, -.05d);
                bladePositions[1] = new Point3D(1d, .25d, .05d);

                // This tranform is throw away.  It's just used to transform points
                Transform3DGroup transform = new Transform3DGroup();
                transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90d + 15d)));		// rotar tilt (the flow defaults to -x, so face them into the wind)
                transform.Children.Add(new TranslateTransform3D(new Vector3D(1d + .5d, 0, 0)));		// pull away from the center a bit
                transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 90)));		// I don't want it along X, I want it along Y

                #endregion

                // Blades
                MeshGeometry3D[] meshBlades = new MeshGeometry3D[StaticRandom.Next(1, 8)];
                CollisionHull[] collisionBlades = new CollisionHull[meshBlades.Length];
                Transform3D[] transformBlades = new Transform3D[meshBlades.Length];
                GeometryModel3D[] geometryBlades = new GeometryModel3D[meshBlades.Length];
                ModelVisual3D[] modelBlades = new ModelVisual3D[meshBlades.Length];

                for (int cntr = 0; cntr < meshBlades.Length; cntr++)
                {
                    meshBlades[cntr] = UtilityWPF.GetCube_IndependentFaces(bladePositions[0], bladePositions[1]);
                    collisionBlades[cntr] = CollisionHull.CreateBox(_world, 0, bladePositions[1] - bladePositions[0], transform.Value);
                    transformBlades[cntr] = transform.Clone();

                    geometryBlades[cntr] = new GeometryModel3D();
                    geometryBlades[cntr].Material = materials;
                    geometryBlades[cntr].BackMaterial = materials;
                    geometryBlades[cntr].Geometry = meshBlades[cntr];
                    geometryBlades[cntr].Transform = transformBlades[cntr];

                    modelBlades[cntr] = new ModelVisual3D();
                    modelBlades[cntr].Content = geometryBlades[cntr];
                    modelBlades[cntr].Transform = _modelOrientationTrackball.Transform;

                    // Prep for the next blade
                    transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 360d / meshBlades.Length)));
                }

                // Body
                CollisionHull collisionHull = CollisionHull.CreateCompoundCollision(_world, 0, collisionBlades);

                _body = new Body(collisionHull, _modelOrientationTrackball.Transform.Value, 1, null);
                collisionHull.Dispose();
                foreach (CollisionHull hull in collisionBlades)
                {
                    hull.Dispose();
                }

                _fluidHull = new FluidHull();
                _fluidHull.Triangles = FluidHull.FluidTriangle.GetTrianglesFromMesh(meshBlades, transformBlades);
                _fluidHull.IsClosedConvexInUniformField = false;
                _fluidHull.Transform = _modelOrientationTrackball.Transform;
                _fluidHull.Field = _field;
                _fluidHull.Body = _body;

                // Wireframe
                ScreenSpaceLines3D modelWireframe = GetModelWireframe(_fluidHull);
                modelWireframe.Transform = _modelOrientationTrackball.Transform;
                _viewport.Children.Add(modelWireframe);

                // Rope
                Point3D bodyAttachPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(.25, 0, 0));
                Point3D anchorPoint = _modelOrientationTrackball.Transform.Transform(new Point3D(3, 0, 0));
                AddRope(bodyAttachPoint, anchorPoint, Math1D.DegreesToRadians(1d));

                // Add to the viewport
                foreach (ModelVisual3D model in modelBlades)
                {
                    _viewport.Children.Add(model);
                }

                // Finish setting up the body
                Visual3D[] visuals = new Visual3D[meshBlades.Length + 1];
                for (int cntr = 0; cntr < meshBlades.Length; cntr++)
                {
                    visuals[cntr] = modelBlades[cntr];
                }
                visuals[visuals.Length - 1] = modelWireframe;

                _body.Visuals = visuals;
                _body.ApplyForceAndTorque += new EventHandler<BodyApplyForceAndTorqueArgs>(Body_ApplyForceAndTorque);
                _body.BodyMoved += new EventHandler(Body_BodyMoved);

                _world.UnPause();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }