示例#1
0
        private static Point3D? CastRay_Cylinder(Point3D point, Vector3D direction, double radius, RayHitTestParameters mouseDownClickRay, RayHitTestParameters mouseDownCenterRay, RayHitTestParameters currentClickRay)
        {
            // Get points on the cylinder
            Point3D? mouseDownClickPoint = null;
            Point3D? mouseDownCenterPoint = null;
            Point3D? currentClickPoint = null;

            Point3D[] nearestCylinderPoints, nearestLinePoints;
            if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, currentClickRay.Origin, currentClickRay.Direction, Math3D.RayCastReturn.ClosestToRay))
            {
                currentClickPoint = nearestCylinderPoints[0];

                if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, mouseDownClickRay.Origin, mouseDownClickRay.Direction, Math3D.RayCastReturn.ClosestToRay))
                {
                    mouseDownClickPoint = nearestCylinderPoints[0];

                    if (Math3D.GetClosestPoints_Cylinder_Line(out nearestCylinderPoints, out nearestLinePoints, point, direction, radius, mouseDownCenterRay.Origin, mouseDownCenterRay.Direction, Math3D.RayCastReturn.ClosestToRay))
                    {
                        mouseDownCenterPoint = nearestCylinderPoints[0];
                    }
                }
            }

            if (mouseDownCenterPoint == null || mouseDownClickPoint == null || currentClickPoint == null)
            {
                return currentClickPoint;		// it doesn't matter if this one is null or not, the offset can't be determined, so just return the raw click value
            }

            // Circle only cared about an offset angle, but cylinder needs two things:
            //		Offset line (the part of the offset that is parallel to the cylinder's axis)
            //		Offset angle (the part of the offset that is perpendicular to the cylinder's axis)
            Vector3D offsetLinear = (mouseDownCenterPoint.Value - mouseDownClickPoint.Value).GetProjectedVector(direction);
            Quaternion offsetRadial = GetRotation_Circle(point, direction, mouseDownClickPoint.Value, mouseDownCenterPoint.Value);





            //TODO: Get the radial offset working as well (sphere is also messed up, the same fix should work for both)







            //TODO: See if this is the most effiecient way or not
            Transform3DGroup transform = new Transform3DGroup();
            //transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(offsetRadial)));
            transform.Children.Add(new TranslateTransform3D(offsetLinear));

            //TODO: Bring currentClickPoint into local coords, do the transform, then put it back into global coords

            // Find the point along the cylinder's axis that is nearest to the current click.  This will become the center of the model coords
            Point3D modelCenter = Math3D.GetClosestPoint_Line_Point(point, direction, currentClickPoint.Value);

            // Shift the click point into model coords
            Vector3D modelClick = currentClickPoint.Value - modelCenter;

            // Adjust by the offset transform (needed to put into model coords, because there is a rotation)
            modelClick = transform.Transform(modelClick);

            // Now put back into world coords
            return modelCenter + modelClick;
        }
示例#2
0
        /// <summary>
        /// Takes the average velocity of the requested cells
        /// </summary>
        /// <remarks>
        /// This was written to assist with IFluidField.GetForce.  I decided to not use the interface to give the caller
        /// the option of model or world coords.  Also, there is more flexibility if multiple fields need to be stitched
        /// together.
        /// 
        /// TODO: When this class implements viscosity, also implement IFluidField directly (and assume world coords)
        /// </remarks>
        public Vector3D[] GetFlowAtLocations(Point3D[] points, double radius)
        {
            //TODO: look at radius

            double fullSize = this.SizeWorld;
            double halfSize = fullSize / 2d;
            double cellSize = fullSize / _size;

            // This is to transform the point from world to model coords
            Transform3DGroup transformPoint = new Transform3DGroup();
            transformPoint.Children.Add(new RotateTransform3D(new QuaternionRotation3D(this.RotationWorld.ToReverse())));
            transformPoint.Children.Add(new TranslateTransform3D(this.PositionWorld.ToVector() * -1d));
            transformPoint.Children.Add(new TranslateTransform3D(new Vector3D(halfSize, halfSize, halfSize)));       // The point passed in is from -half to +half, but the ints are 0 to size

            // This is to transform the return velocity back to world coords
            RotateTransform3D transformVect = new RotateTransform3D(new QuaternionRotation3D(this.RotationWorld));

            Vector3D[] retVal = new Vector3D[points.Length];

            for (int cntr = 0; cntr < points.Length; cntr++)
            {
                // Convert into int positions
                Point3D transformed = transformPoint.Transform(points[cntr]);

                int x = Convert.ToInt32(Math.Round(transformed.X / cellSize));
                int y = Convert.ToInt32(Math.Round(transformed.Y / cellSize));
                int z = Convert.ToInt32(Math.Round(transformed.Z / cellSize));

                int index = Get1DIndex(x, y, z);
                if (index < 0 || index >= _size1D)
                {
                    // The point is outside this field
                    retVal[cntr] = new Vector3D(0, 0, 0);
                }

                double negate = 1d;
                if (_blocked[index])
                {
                    // Blocked cells have the opposite velocity, so that they push back.  But when reporting, it needs to be flipped back
                    // so that it's more like the force felt at that point
                    negate = -1d;
                }

                retVal[cntr] = transformVect.Transform(new Vector3D(_velocityX[index] * negate, _velocityY[index] * negate, _velocityZ[index] * negate));
            }

            // Exit Function
            return retVal;
        }
        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();
        }
示例#4
0
        private static void GetDome(ref int pointOffset, MeshGeometry3D geometry, Point[] pointsTheta, Transform3D transform, int numSegmentsPhi, double radiusX, double radiusY, double radiusZ)
        {
            #region Initial calculations

            // NOTE: There is one more than what the passed in
            Point[] pointsPhi = new Point[numSegmentsPhi + 1];

            pointsPhi[0] = new Point(1d, 0d);		// along the equator
            pointsPhi[numSegmentsPhi] = new Point(0d, 1d);		// north pole

            if (pointsPhi.Length > 2)
            {
                // Need to go from 0 to half pi
                double halfPi = Math.PI * .5d;
                double deltaPhi = halfPi / pointsPhi.Length;		// there is one more point than numSegmentsPhi

                for (int cntr = 1; cntr < numSegmentsPhi; cntr++)
                {
                    double phi = deltaPhi * cntr;		// phi goes from 0 to pi for a full sphere, so start halfway up
                    pointsPhi[cntr] = new Point(Math.Cos(phi), Math.Sin(phi));
                }
            }

            #endregion

            #region Positions/Normals

            // Can't use all of the transform passed in for the normal, because translate portions will skew the normal funny
            Transform3DGroup normalTransform = new Transform3DGroup();
            if (transform is Transform3DGroup)
            {
                foreach (var subTransform in ((Transform3DGroup)transform).Children)
                {
                    if (!(subTransform is TranslateTransform3D))
                    {
                        normalTransform.Children.Add(subTransform);
                    }
                }
            }
            else if (transform is TranslateTransform3D)
            {
                normalTransform.Children.Add(Transform3D.Identity);
            }
            else
            {
                normalTransform.Children.Add(transform);
            }

            //for (int phiCntr = 0; phiCntr < numSegmentsPhi; phiCntr++)		// The top point will be added after this loop
            for (int phiCntr = pointsPhi.Length - 1; phiCntr > 0; phiCntr--)
            {
                for (int thetaCntr = 0; thetaCntr < pointsTheta.Length; thetaCntr++)
                {
                    // Phi points are going from bottom to equator.  

                    Point3D point = new Point3D(
                        radiusX * pointsTheta[thetaCntr].X * pointsPhi[phiCntr].Y,
                        radiusY * pointsTheta[thetaCntr].Y * pointsPhi[phiCntr].Y,
                        radiusZ * pointsPhi[phiCntr].X);

                    geometry.Positions.Add(transform.Transform(point));

                    //TODO: For a standalone dome, the bottom rings will point straight out.  But for something like a snow cone, the normal will have to be averaged with the cone
                    geometry.Normals.Add(normalTransform.Transform(point).ToVector().ToUnit());		// the normal is the same as the point for a sphere (but no tranlate transform)
                }
            }

            // This is north pole point
            geometry.Positions.Add(transform.Transform(new Point3D(0, 0, radiusZ)));
            geometry.Normals.Add(transform.Transform(new Vector3D(0, 0, 1)));

            #endregion

            #region Triangles - Rings

            int zOffsetBottom = pointOffset;
            int zOffsetTop;

            for (int phiCntr = 0; phiCntr < numSegmentsPhi - 1; phiCntr++)		// The top cone will be added after this loop
            {
                zOffsetTop = zOffsetBottom + pointsTheta.Length;

                for (int thetaCntr = 0; thetaCntr < pointsTheta.Length - 1; thetaCntr++)
                {
                    // Top/Left triangle
                    geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0);
                    geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1);
                    geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 0);

                    // Bottom/Right triangle
                    geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 0);
                    geometry.TriangleIndices.Add(zOffsetBottom + thetaCntr + 1);
                    geometry.TriangleIndices.Add(zOffsetTop + thetaCntr + 1);
                }

                // Connecting the last 2 points to the first 2
                // Top/Left triangle
                geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0);
                geometry.TriangleIndices.Add(zOffsetTop);		// wrapping back around
                geometry.TriangleIndices.Add(zOffsetTop + (pointsTheta.Length - 1) + 0);

                // Bottom/Right triangle
                geometry.TriangleIndices.Add(zOffsetBottom + (pointsTheta.Length - 1) + 0);
                geometry.TriangleIndices.Add(zOffsetBottom);
                geometry.TriangleIndices.Add(zOffsetTop);

                // Prep for the next ring
                zOffsetBottom = zOffsetTop;
            }

            #endregion
            #region Triangles - Cap

            int topIndex = geometry.Positions.Count - 1;

            for (int cntr = 0; cntr < pointsTheta.Length - 1; cntr++)
            {
                geometry.TriangleIndices.Add(zOffsetBottom + cntr + 0);
                geometry.TriangleIndices.Add(zOffsetBottom + cntr + 1);
                geometry.TriangleIndices.Add(topIndex);
            }

            // The last triangle links back to zero
            geometry.TriangleIndices.Add(zOffsetBottom + pointsTheta.Length - 1 + 0);
            geometry.TriangleIndices.Add(zOffsetBottom + 0);
            geometry.TriangleIndices.Add(topIndex);

            #endregion

            pointOffset = geometry.Positions.Count;
        }
示例#5
0
        /// <summary>
        /// Call this to apply the thruster force to the physics body
        /// </summary>
        public void ApplyForce(double percentMax, Transform3D worldTransform, BodyForceEventArgs e)
        {
            if (!_isFiring)        // the property set will make sure the visual is no longer known to the viewport
            {
                return;
            }

            double actualForce = _forceStrength * percentMax;
            if (_fuelTank != null)
            {
                #region Use Fuel

                if (_fuelTank.QuantityCurrent > 0d)
                {
                    double fuelToUse = actualForce * e.ElapsedTime * _fuelToThrustRatio;

                    double fuelUnused = _fuelTank.RemoveQuantity(fuelToUse, false);
                    if (fuelUnused > 0d)
                    {
                        // Not enough fuel, reduce the amount of force
                        actualForce -= fuelUnused / (e.ElapsedTime * _fuelToThrustRatio);
                    }
                }
                else
                {
                    actualForce = 0d;
                }

                #endregion
            }

            if (actualForce == 0d)
            {
                // No force to apply
                //TODO:  Play a clicking sound, or some kind of error tone
                //TODO:  Don't show the flames
                return;
            }

            // Figure out how to place it in world coords
            Transform3DGroup transform = new Transform3DGroup();       // I don't use _initialRotate, because that's for the visual (it's always created along the X axis, but _force is already stored correctly)
            transform.Children.Add(this.BodyOffset);
            transform.Children.Add(worldTransform);

            Vector3D positionOnBodyWorld = transform.Transform(new Point3D(0, 0, 0)).ToVector();    // note that I have to use a point (transform acts different on points than vectors)
            Vector3D deltaForceWorld = transform.Transform(_forceDirection);
            deltaForceWorld.Normalize();
            deltaForceWorld *= actualForce;

            // Apply the force
            e.AddForceAtPoint(deltaForceWorld, positionOnBodyWorld);
        }
示例#6
0
        /// <summary>
        /// This is exposed so it can be called externally on a separate thread, then call this asteroid's constructor
        /// in the main thread once this returns
        /// </summary>
        public static ITriangleIndexed[] GetHullTriangles(double radius)
        {
            const int NUMPOINTS = 60;		// too many, and it looks too perfect

            Exception lastException = null;
            Random rand = StaticRandom.GetRandomForThread();

            for (int infiniteLoopCntr = 0; infiniteLoopCntr < 50; infiniteLoopCntr++)		// there is a slight chance that the convex hull generator will choke on the inputs.  If so just retry
            {
                try
                {
                    double minRadius = radius * .9d;

                    Point3D[] points = new Point3D[NUMPOINTS];

                    // Make a point cloud
                    for (int cntr = 0; cntr < NUMPOINTS; cntr++)
                    {
                        points[cntr] = Math3D.GetRandomVector_Spherical(minRadius, radius).ToPoint();
                    }

                    // Squash it
                    Transform3DGroup transform = new Transform3DGroup();
                    transform.Children.Add(new ScaleTransform3D(.33d + (rand.NextDouble() * .66d), .33d + (rand.NextDouble() * .66d), 1d));		// squash it
                    transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRandomRotation())));		// giving it a random rotation, since it's always squashed along the same axiis
                    transform.Transform(points);

                    // Get a hull that wraps those points
                    ITriangleIndexed[] retVal = Math3D.GetConvexHull(points.ToArray());

                    // Get rid of unused points
                    retVal = TriangleIndexed.Clone_CondensePoints(retVal);

                    // Exit Function
                    return retVal;
                }
                catch (Exception ex)
                {
                    lastException = ex;
                }
            }

            throw new ApplicationException(lastException.ToString());
        }
示例#7
0
        public static MeshGeometry3D GetCylinder_AlongX(int numSegments, double radius, double height, RotateTransform3D rotateTransform = null)
        {
            //NOTE: All the other geometries in this class are along the x axis, so I want to follow suit, but I think best along the z axis.  So I'll transform the points before commiting them to the geometry
            //TODO: This is so close to GetMultiRingedTube, the only difference is the multi ring tube has "hard" faces, and this has "soft" faces (this one shares points and normals, so the lighting is smoother)

            if (numSegments < 3)
            {
                throw new ArgumentException("numSegments must be at least 3: " + numSegments.ToString(), "numSegments");
            }

            MeshGeometry3D retVal = new MeshGeometry3D();

            #region Initial calculations

            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 90d)));

            if (rotateTransform != null)
            {
                // This is in case they wanted oriented other than along the x axis
                transform.Children.Add(rotateTransform);
            }

            double halfHeight = height / 2d;

            Point[] points = Math2D.GetCircle_Cached(numSegments);

            #endregion

            #region Side

            for (int cntr = 0; cntr < numSegments; cntr++)
            {
                retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * radius, points[cntr].Y * radius, -halfHeight)));
                retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X * radius, points[cntr].Y * radius, halfHeight)));

                retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X, points[cntr].Y, 0d)));		// the normals point straight out of the side
                retVal.Normals.Add(transform.Transform(new Vector3D(points[cntr].X, points[cntr].Y, 0d)));
            }

            for (int cntr = 0; cntr < numSegments - 1; cntr++)
            {
                // 0,2,3
                retVal.TriangleIndices.Add((cntr * 2) + 0);
                retVal.TriangleIndices.Add((cntr * 2) + 2);
                retVal.TriangleIndices.Add((cntr * 2) + 3);

                // 0,3,1
                retVal.TriangleIndices.Add((cntr * 2) + 0);
                retVal.TriangleIndices.Add((cntr * 2) + 3);
                retVal.TriangleIndices.Add((cntr * 2) + 1);
            }

            // Connecting the last 2 points to the first 2
            // last,0,1
            int offset = (numSegments - 1) * 2;
            retVal.TriangleIndices.Add(offset + 0);
            retVal.TriangleIndices.Add(0);
            retVal.TriangleIndices.Add(1);

            // last,1,last+1
            retVal.TriangleIndices.Add(offset + 0);
            retVal.TriangleIndices.Add(1);
            retVal.TriangleIndices.Add(offset + 1);

            #endregion

            // Caps
            int pointOffset = retVal.Positions.Count;

            //NOTE: The normals are backward from what you'd think

            GetCylinder_AlongXSprtEndCap(ref pointOffset, retVal, points, new Vector3D(0, 0, 1), radius, radius, -halfHeight, transform);
            GetCylinder_AlongXSprtEndCap(ref pointOffset, retVal, points, new Vector3D(0, 0, -1), radius, radius, halfHeight, transform);

            // Exit Function
            //retVal.Freeze();
            return retVal;
        }
        private Point3D[] GetVoronoiCtrlPoints_AroundLine(Point3D lineStart, Point3D lineStop)
        {
            const int MIN = 5;

            double lineLength = (lineStop - lineStart).Length;
            double drift = lineLength / 20;
            bool evenDist = chkOneShotPlateEvenDistribute.IsChecked.Value;

            List<Point3D> points = new List<Point3D>();

            // Plates
            if (radOneShot_SinglePlate.IsChecked.Value)
            {
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist1.Value, 0, evenDist, drift));
            }
            else if (radOneShot_TwoPlates.IsChecked.Value)
            {
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist1.Value, -lineLength / 6, evenDist, drift));
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist2.Value, lineLength / 6, evenDist, drift));
            }
            else if (radOneShot_ThreePlates.IsChecked.Value)
            {
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist1.Value, -lineLength / 4, evenDist, drift));
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist2.Value, 0, evenDist, drift));
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_Plate(lineLength * trkOneShotPercentDist3.Value, lineLength / 4, evenDist, drift));
            }
            else
            {
                throw new ApplicationException("Unknown plate configuration");
            }

            // Center line
            if (radOneShot_LineNone.IsChecked.Value)
            {
            }
            else if (radOneShot_LineAbove.IsChecked.Value)
            {
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(new[] { -lineLength / 4 }, drift * 2));
            }
            else if (radOneShot_LineMiddle.IsChecked.Value)
            {
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(new[] { 0d }, drift * 2));
            }
            else if (radOneShot_LineBelow.IsChecked.Value)
            {
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(new[] { lineLength / 4 }, drift * 2));
            }
            else if (radOneShot_LineSeveral.IsChecked.Value)
            {
                var zs = Enumerable.Range(0, StaticRandom.Next(1, 5)).
                    Select(o => StaticRandom.NextDouble(-lineLength / 2, lineLength / 2));
                points.AddRange(GetVoronoiCtrlPoints_AroundLine_CenterLine(zs, drift * 2));
            }
            else
            {
                throw new ApplicationException("Unknown centerline configuration");
            }

            // The voronoi algrorithm fails if there aren't at least 5 points (really should fix that).  So add points that are
            // way away from the hull.  This will make the voronoi algorithm happy, and won't affect the local results
            if (points.Count < MIN)
            {
                points.AddRange(Enumerable.Range(0, MIN - points.Count).
                    Select(o => Math3D.GetRandomVector_Spherical_Shell(lineLength * 20).ToPoint()));
            }

            // Rotate/Translate
            Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), lineStop - lineStart);

            Point3D centerPoint = Math3D.GetCenter(new[] { lineStart, lineStop });

            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation)));
            transform.Children.Add(new TranslateTransform3D(centerPoint.X, centerPoint.Y, centerPoint.Z));

            return points.Select(o => transform.Transform(o)).
                ToArray();
        }
        /// <summary>
        /// Make a few (2 to 6) control points radially around the line.  All in a plane
        /// </summary>
        /// <remarks>
        /// The voronoi algorithm requires at least 4 (probably not coplanar).  So if you want fewer than that, extra points
        /// are created away from the hull
        /// </remarks>
        private static Point3D[] GetVoronoiCtrlPoints_AroundLine_Simple(Point3D lineStart, Point3D lineStop, int count)
        {
            const int MIN = 5;

            //double radius = (lineStop - lineStart).Length * .5;
            double radius = (lineStop - lineStart).Length * .1;

            var points = Enumerable.Range(0, count).
                Select(o => Math3D.GetRandomVector_Circular_Shell(radius).ToPoint());
            //Select(o => Math3D.GetRandomVector_Spherical(radius).ToPoint());

            // The voronoi algrorithm fails if there aren't at least 5 points (really should fix that).  So add points that are
            // way away from the hull.  This will make the voronoi algorithm happy, and won't affect the local results
            if (count < MIN)
            {
                points = points.Concat(
                    Enumerable.Range(0, MIN - count).
                    //Select(o => Math3D.GetRandomVector_Circular_Shell(radius * 100).ToPoint())
                    Select(o => Math3D.GetRandomVector_Spherical_Shell(radius * 20).ToPoint())
                    );
            }

            //points = points.Select(o => new Point3D(o.X, o.Y, Math1D.GetNearZeroValue(radius / 20)));     // the voronoi can't handle coplanar input
            points = points.Select(o => o + Math3D.GetRandomVector_Spherical(radius / 20));     // the voronoi can't handle coplanar input

            // This will cause a cylinder core to be cut out, but only if the other points are ringed around (if they clump around one angle, then this won't look right)
            //points = UtilityCore.Iterate<Point3D>(points, Math3D.GetRandomVector_Spherical(radius / 10).ToPoint());

            // Rotate/Translate
            Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), lineStop - lineStart);

            Point3D centerPoint = Math3D.GetCenter(new[] { lineStart, lineStop });

            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation)));
            transform.Children.Add(new TranslateTransform3D(centerPoint.X, centerPoint.Y, centerPoint.Z));

            points = points.Select(o => transform.Transform(o));

            return points.ToArray();
        }
        public ConverterRadiationToEnergy(EditorOptions options, ItemOptions itemOptions, ConverterRadiationToEnergyDNA dna, IContainer energyTanks, RadiationField radiationField)
            : base(options, dna, itemOptions.SolarPanel_Damage.HitpointMin, itemOptions.SolarPanel_Damage.HitpointSlope, itemOptions.SolarPanel_Damage.Damage)
        {
            _itemOptions = itemOptions;
            _energyTanks = energyTanks;
            _radiationField = radiationField;

            this.Design = new ConverterRadiationToEnergyDesign(options, true, dna.Shape);
            this.Design.SetDNA(dna);

            this.ClarityPercent_Front = 1d;
            this.ClarityPercent_Back = 1d;

            Point3D center;
            Vector3D normal;
            GetStats(out _mass, out center, out normal, out _scaleActual);

            // Store the center and normals
            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(dna.Orientation)));
            transform.Children.Add(new TranslateTransform3D(dna.Position.ToVector()));

            _centerPoint = transform.Transform(center);
            _normalFront = transform.Transform(normal);
            _normalBack = transform.Transform(normal * -1d);
        }
示例#11
0
		private void ResetBtnLocation(Point3D point)
		{
			Model3D m = (Model3D)(((Model3DGroup)grpMain.Children[0]).Children[0]);

			Transform3DGroup tgp = new Transform3DGroup();
			tgp.Children.Add(grpMain.Transform);
			tgp.Children.Add(m.Transform);

			GeneralTransform3DTo2D gt = lvMain.TransformToAncestor(vpMain);//vpmain.TransformToDescendant(...);
			Point p = gt.Transform(tgp.Transform(point));
			Canvas.SetLeft(btnTest, p.X);
			Canvas.SetTop(btnTest, p.Y);
			btnTest.Content = p.X + "," + p.Y;
		}
        public void rotatePoints(double nextAngleXY, double nextAngleXZ, double nextAngleYZ)
        {
            if (nextAngleXY - angleXY != 0 || nextAngleXZ - angleXZ != 0 || nextAngleYZ - angleYZ != 0)
            {

                var group = new Transform3DGroup();
                var myRotateTransformZ = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), nextAngleXY-angleXY), currentPosition);
                group.Children.Add((myRotateTransformZ));
                /*var myRotateTransformY = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), nextAngleXZ - angleXZ), currentPosition);
                group.Children.Add((myRotateTransformY));
                var myRotateTransformX = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), nextAngleYZ - angleYZ), currentPosition);
                group.Children.Add((myRotateTransformX));*/
                for (var i = 0; i < trolley.Count(); i++)
                {
                    trolley[i] = group.Transform(trolley[i]);

                }
                angleXY = nextAngleXY;
                angleXZ = nextAngleXZ;
                angleYZ = nextAngleYZ;
            }
        }
示例#13
0
        private void moveToAngles(double alpha, double beta, double gamma) {
            RotateTransform3D bodyCoxaTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), alpha));
            bodyCoxaTransform.CenterX = 0;
            bodyCoxaTransform.CenterY = 0;
            bodyCoxaTransform.CenterZ = 0;
            Model.Transform = bodyCoxaTransform;

            RotateTransform3D coxaFemurTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), beta));
            coxaFemurTransform.CenterX = bodyCoxaLen;
            coxaFemurTransform.CenterY = 0;
            coxaFemurTransform.CenterZ = 0;
            femurTibiaLink.Model.Transform = coxaFemurTransform;
            femurTibiaJoint.Model.Transform = coxaFemurTransform;
            foot.Model.Transform = coxaFemurTransform;


            var group3Dtransformation = new Transform3DGroup();
            group3Dtransformation.Children.Add(femurTibiaLink.Model.Transform);
            Point3D origin = group3Dtransformation.Transform(new Point3D(bodyCoxaLen, 0, femurLen));
            RotateTransform3D femurTibiaTransform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), gamma));
            femurTibiaTransform.CenterX = origin.X;
            femurTibiaTransform.CenterY = origin.Y;
            femurTibiaTransform.CenterZ = origin.Z;
            group3Dtransformation.Children.Add(femurTibiaTransform);
            tibiaFootLink.Model.Transform = group3Dtransformation;
            foot.Model.Transform = group3Dtransformation;

            var p = new Point3D(bodyCoxaJoint.Point2.X, bodyCoxaJoint.Point2.Y, bodyCoxaJoint.Point2.Z);
            p.Offset(0, 0, 1.5 * jointDiameter);
            coxaAngleLabel.Position = p;
            coxaAngleLabel.Text = String.Format("{0:N1}°", alpha);

            var q = new Point3D(coxaFemurTransform.CenterX, coxaFemurTransform.CenterY, coxaFemurTransform.CenterZ);
            q.Offset(0,0, -2 * jointDiameter);
            femurAngleLabel.Transform = bodyCoxaTransform;
            femurAngleLabel.Position = q;
            femurAngleLabel.Text = String.Format("{0:N1}°", beta);

            var r = new Point3D(femurTibiaTransform.CenterX, femurTibiaTransform.CenterY, femurTibiaTransform.CenterZ);
            r.Offset(0, 0, 1.5 * jointDiameter);
            tibiaAngleLabel.Position = r;
            tibiaAngleLabel.Transform = bodyCoxaTransform;
            tibiaAngleLabel.Text = String.Format("{0:N1}°", gamma);

          //  coxaFemurConstraint.Transform = bodyCoxaTransform;


        }
        /// <summary>
        /// This defines the back side of a cylinder
        /// </summary>
        private static Geometry3D GetGeometry(int numSegments, double thetaOffset, double height, double radius, double translate)
        {
            double thetaStart = 270 - thetaOffset;
            double thetaStop = 270 + thetaOffset;

            MeshGeometry3D retVal = new MeshGeometry3D();

            #region Initial calculations

            // The rest of this method has height along Z, but the final needs to go along Y
            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90d)));
            //transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), 180d)));
            transform.Children.Add(new TranslateTransform3D(0, 0, translate));

            double halfHeight = height / 2d;

            Point[] points = new Point[numSegments];

            double deltaTheta = Math1D.DegreesToRadians((thetaStop - thetaStart) / (numSegments - 1));        //NOTE: This will fail if theta start/stop goes past 0/360
            double theta = Math1D.DegreesToRadians(thetaStart);

            for (int cntr = 0; cntr < numSegments; cntr++)
            {
                points[cntr] = new Point(Math.Cos(theta) * radius, Math.Sin(theta) * radius);
                theta += deltaTheta;
            }

            #endregion

            for (int cntr = 0; cntr < numSegments; cntr++)
            {
                retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X, points[cntr].Y, -halfHeight)));
                retVal.Positions.Add(transform.Transform(new Point3D(points[cntr].X, points[cntr].Y, halfHeight)));

                retVal.Normals.Add(transform.Transform(new Vector3D(-points[cntr].X, -points[cntr].Y, 0d)));		// the normals point straight in from the side
                retVal.Normals.Add(transform.Transform(new Vector3D(-points[cntr].X, -points[cntr].Y, 0d)));

                double coord = Convert.ToDouble(cntr) / Convert.ToDouble(numSegments - 1);
                retVal.TextureCoordinates.Add(new Point(coord, 0));
                retVal.TextureCoordinates.Add(new Point(coord, 1));
            }

            for (int cntr = 0; cntr < numSegments - 1; cntr++)
            {
                // 0,2,3
                retVal.TriangleIndices.Add((cntr * 2) + 0);
                retVal.TriangleIndices.Add((cntr * 2) + 3);
                retVal.TriangleIndices.Add((cntr * 2) + 2);

                // 0,3,1
                retVal.TriangleIndices.Add((cntr * 2) + 0);
                retVal.TriangleIndices.Add((cntr * 2) + 1);
                retVal.TriangleIndices.Add((cntr * 2) + 3);
            }

            return retVal;
        }
示例#15
0
        public void LoadModel(string path, bool transformYup, double scale)
        {
            var mod = ModelImporter.Load(path);

            if (mod == null || mod.Children.Count == 0)
                return;

            var model = (mod.Children[0] as GeometryModel3D);
            if (model == null)
                return;

            var mesh = model.Geometry as MeshGeometry3D;
            if (mesh == null)
                return;

            var transform = new Transform3DGroup();
            if (transformYup)
                transform.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), 90)));
            transform.Children.Add(new ScaleTransform3D(scale, scale, scale));

            for (int i = 0; i < mesh.Positions.Count; i++)
                mesh.Positions[i] = transform.Transform(mesh.Positions[i]);

            ScaleHeightOnly = false;
            Geometry = mesh;
        }
        /// <summary>
        /// Each hit line should create a cone of probability to place control points onto
        /// Once a point on the surface of a cone is chosen, choose a couple more on that circle
        /// </summary>
        private static Point3D[] GetVoronoiCtrlPoints_AroundLine_Cone(Point3D lineStart, Point3D lineStop, int count, double entryRadius, double exitRadius, double maxAxisLength)
        {
            // Figure out where on the axis the control point ring should go (the bell has a spike around 30% in)
            double axisPercent = StaticRandomWPF.NextBell(_coneAxisBell.Value);

            Vector3D axis = lineStop - lineStart;
            double axisLength = axis.Length;

            Point3D ringCenter = lineStart + (axis * axisPercent);

            // Figure out the radius of the cone at this point
            double exitRadiusAdjusted = (axisLength / maxAxisLength) * exitRadius;

            double ringRadius = UtilityCore.GetScaledValue(entryRadius, exitRadiusAdjusted, 0, 1, axisPercent);

            // Get some points
            var points = Enumerable.Range(0, count).
                Select(o => Math3D.GetRandomVector_Circular_Shell(ringRadius).ToPoint());





            //TODO: Figure out the minimum to shift by
            //double shiftRadius = Math.Max(.01, ringRadius / 20);
            double shiftRadius = ringRadius / 20;
            points = points.Select(o => o + Math3D.GetRandomVector_Spherical(shiftRadius));     // the voronoi can't handle coplanar input







            // Rotate/Translate
            Quaternion roation = Math3D.GetRotation(new Vector3D(0, 0, 1), axis);

            Transform3DGroup transform = new Transform3DGroup();
            transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(roation)));
            transform.Children.Add(new TranslateTransform3D(ringCenter.X, ringCenter.Y, ringCenter.Z));

            points = points.Select(o => transform.Transform(o));

            return points.ToArray();
        }
示例#17
0
        private void MoveCameraAroundCenter(double leftRight, double topDown)
        {
            // Use WPF maths for camera rotation.
            // It is slower than using Matrix4F and Vector4F,
            // but camera calculations are only done once per camera move
            Transform3DGroup tg = new Transform3DGroup();
            //left/right drags rotate around the camera's up vector
            Vector3D leftRightRotationAxis = new Vector3D(Up.X, Up.Y, Up.Z);
            //top/down drags rotate around the vector that is perpendicular
            //to both Up and Eye (camera location) - their cross product
            Vector3D topDownRotationAxis = Vector3D.CrossProduct(
                leftRightRotationAxis,
                new Vector3D(Eye.X, Eye.Y, Eye.Z));
            tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(leftRightRotationAxis, leftRight)));
            tg.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(topDownRotationAxis, topDown)));
            Vector3D newEye = tg.Transform(new Vector3D(Eye.X, Eye.Y, Eye.Z));
            Vector3D newUp = tg.Transform(new Vector3D(Up.X, Up.Y, Up.Z));
            Eye.X = (float)newEye.X;
            Eye.Y = (float)newEye.Y;
            Eye.Z = (float)newEye.Z;
            Up.X = (float)newUp.X;
            Up.Y = (float)newUp.Y;
            Up.Z = (float)newUp.Z;

            effects.ViewMatrix = DXUtil.Camera.MatrixLookAtLH(Eye, At, Up);
        } 
        private void FireRaySprtShootBall()
        {
            Vector3D velocity = _rayDirection.ToUnit() * trkBulletSpeed.Value;
            DoubleVector directionFacing = new DoubleVector(velocity, Math3D.GetArbitraryOrhonganal(velocity));

            switch (cboLeftBallType.Text)
            {
                case "Nerf":
                    #region Nerf

                    AddCannonBall(
                        CollisionShapeType.Cylinder,
                        Colors.Coral,
                        new Vector3D(.75d, 5d, 0d),		// x is radius, y is height
                        .1d,
                        _rayPoint,
                        velocity,
                        new Vector3D(),
                        directionFacing);

                    #endregion
                    break;

                case "Pellet":
                    #region Pellet

                    AddCannonBall(
                        CollisionShapeType.Sphere,
                        Colors.SteelBlue,
                        new Vector3D(.5d, .5d, .5d),
                        2d,
                        _rayPoint,
                        velocity,
                        new Vector3D(),
                        directionFacing);

                    #endregion
                    break;

                case "Slug":
                    #region Slug

                    AddCannonBall(
                        CollisionShapeType.Cylinder,
                        Colors.DimGray,
                        new Vector3D(.5d, .8d, 0d),		// x is radius, y is height
                        6d,
                        _rayPoint,
                        velocity,
                        new Vector3D(),
                        directionFacing);

                    #endregion
                    break;

                case "Baseball":
                    #region Baseball

                    AddCannonBall(
                        CollisionShapeType.Sphere,
                        Colors.GhostWhite,
                        new Vector3D(2d, 2d, 2d),
                        5d,
                        _rayPoint,
                        velocity,
                        new Vector3D(),
                        directionFacing);

                    #endregion
                    break;

                case "Cannon":
                    #region Cannon

                    AddCannonBall(
                        CollisionShapeType.Sphere,
                        Color.FromArgb(255, 45, 45, 32),
                        new Vector3D(2d, 2d, 2d),
                        15d,
                        _rayPoint,
                        velocity,
                        new Vector3D(),
                        directionFacing);

                    #endregion
                    break;

                case "Wrecker":
                    #region Wrecker

                    AddCannonBall(
                        CollisionShapeType.Sphere,
                        Color.FromArgb(255, 50, 15, 15),
                        new Vector3D(4d, 4d, 4d),
                        60d,
                        _rayPoint,
                        velocity,
                        new Vector3D(),
                        directionFacing);

                    #endregion
                    break;

                case "Shotgun":
                    #region Shotgun

                    // Build a transform to go from origin to camera
                    DoubleVector originDirFacing = new DoubleVector(0, 0, 1, 0, 1, 0);
                    Quaternion rotationToCameraRay = originDirFacing.GetRotation(new DoubleVector(_rayDirection, Math3D.GetArbitraryOrhonganal(_rayDirection)));
                    Transform3DGroup transformToCamera = new Transform3DGroup();
                    transformToCamera.Children.Add(new RotateTransform3D(new QuaternionRotation3D(rotationToCameraRay)));
                    transformToCamera.Children.Add(new TranslateTransform3D(_rayPoint.ToVector()));

                    for (int cntr = 0; cntr < 10; cntr++)
                    {
                        Vector3D pos2D = Math3D.GetRandomVector_Circular(1d);
                        //Vector3D vel2D = new Vector3D(pos2D.X, pos2D.Y, trkBulletSpeed.Value * 2d);


                        //Point3D position = _rayPoint;
                        velocity = _rayDirection.ToUnit() * trkBulletSpeed.Value * 2d;		//TODO:  Diverge the shot

                        Point3D position = transformToCamera.Transform(pos2D.ToPoint());
                        //velocity = transformToCamera.Transform(vel2D);


                        directionFacing = new DoubleVector(velocity, Math3D.GetArbitraryOrhonganal(velocity));

                        AddCannonBall(
                            CollisionShapeType.Sphere,
                            Color.FromRgb(25, 25, 25),
                            new Vector3D(.1d, .1d, .1d),
                            .2d,
                            position,
                            velocity,
                            new Vector3D(),
                            directionFacing);

                    }

                    #endregion
                    break;

                default:
                    MessageBox.Show("Unknown ball type: " + cboLeftBallType.Text, this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
            }


        }