//NOTE: Radius isn't the radius of the ball, it's how far that ball is from the center
        public DraggableModifierSphere(Vector3D offset, EditorColors editorColors)
            : base(editorColors)
        {
            _radius = offset.Length;
            _initialOffset = offset.ToUnit();

            this.Model = new ModelVisual3D();
            this.Model.Content = GetBall();
        }
        private static Vector3D[] DistributeForces_UNECESSARRILYCOMLEX(Point3D[] bodyCenters, Point3D hitStart, Vector3D hitDirection, double mainBodyRadius, bool useDistDot = true, double distDotPow = .4)
        {
            Vector3D hitDirectionUnit = hitDirection.ToUnit();
            double hitForceBase = hitDirection.Length / mainBodyRadius;

            var vectors = bodyCenters.
                Select(o =>
                {
                    Vector3D toPoint = o - hitStart;
                    Vector3D toPointUnit = toPoint.ToUnit();

                    double dot = Vector3D.DotProduct(hitDirectionUnit, toPointUnit);
                    double linearDot = Math3D.GetLinearDotProduct(hitDirectionUnit, toPointUnit);

                    Vector3D along = toPoint.GetProjectedVector(hitDirection).ToUnit(false);
                    Vector3D orth = (o - Math3D.GetClosestPoint_Line_Point(hitStart, hitDirection, o)).ToUnit(false);

                    along *= linearDot;
                    orth *= (1 - linearDot);

                    double distance = toPoint.Length;

                    // Exaggerate the distance based on dot product.  That way, points in line with the hit will get more of the impact
                    double scale = (1 - Math.Abs(linearDot));
                    scale = Math.Pow(scale, distDotPow);
                    double scaledDistance = scale * distance;

                    return new
                    {
                        ForcePoint = o,
                        Distance = distance,
                        ScaledDistance = scaledDistance,
                        Along = along,
                        Orth = orth,
                    };
                }).
                ToArray();

            double[] distances = useDistDot ?
                vectors.Select(o => o.ScaledDistance).ToArray() :
                vectors.Select(o => o.Distance).ToArray();

            double[] percents = ExplosionForceWorker.GetPercentOfProjForce(distances);

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

            for (int cntr = 0; cntr < vectors.Length; cntr++)
            {
                Vector3D along = vectors[cntr].Along * (hitForceBase * percents[cntr]);
                Vector3D orth = vectors[cntr].Orth * (hitForceBase * percents[cntr]);

                retVal[cntr] = along + orth;
            }

            return retVal;
        }
        private void RedrawProjForce()
        {
            double linearDotPow = .4;
            if (chkProjForceUseDistDot.IsChecked.Value && !double.TryParse(txtProjForceDistDotPow.Text, out linearDotPow))
            {
                txtProjForceDistDotPow.Effect = _errorEffect;
                return;
            }
            else
            {
                txtProjForceDistDotPow.Effect = null;
            }

            Point3D hitStart = new Point3D(0, MAXRADIUS * -.6, 0);
            Vector3D hitDirection = new Vector3D(0, MAXRADIUS / 2, 0);

            double asteroidSize = MAXRADIUS * .8;

            Vector3D hitDirectionUnit = hitDirection.ToUnit();
            double hitForceBase = hitDirection.Length / asteroidSize;

            ClearAll();

            AddDot(hitStart, DOTRADIUS * 4, _colors.Shot);
            AddLine_Billboard(hitStart, hitStart + hitDirection, LINETHICKNESS_BILLBOARD, _colors.Shot);

            if (_projForcePoints != null)
            {
                AddDots(_projForcePoints, DOTRADIUS, _colors.ControlPoint);

                var vectors = _projForcePoints.
                    Select(o =>
                    {
                        Vector3D toPoint = o - hitStart;
                        Vector3D toPointUnit = toPoint.ToUnit();

                        double dot = Vector3D.DotProduct(hitDirectionUnit, toPointUnit);
                        double linearDot = Math3D.GetLinearDotProduct(hitDirectionUnit, toPointUnit);

                        Vector3D along = toPoint.GetProjectedVector(hitDirection).ToUnit(false);
                        Vector3D orth = (o - Math3D.GetClosestPoint_Line_Point(hitStart, hitDirection, o)).ToUnit(false);

                        along *= linearDot * trkProjForceAlong.Value;
                        orth *= (1 - linearDot) * trkProjForceOrth.Value;

                        double distance = toPoint.Length;

                        // Exaggerate the distance based on dot product.  That way, points in line with the hit will get more of the impact
                        double scale = (1 - Math.Abs(linearDot));
                        scale = Math.Pow(scale, linearDotPow);
                        double scaledDistance = scale * distance;

                        return new
                        {
                            ForcePoint = o,

                            Distance = distance,
                            ScaledDistance = scaledDistance,

                            LinearDot = linearDot,
                            Dot = dot,

                            Along = along,
                            Orth = orth,
                        };
                    }).
                    ToArray();

                double[] distances = chkProjForceUseDistDot.IsChecked.Value ?
                    vectors.Select(o => o.ScaledDistance).ToArray() :
                    vectors.Select(o => o.Distance).ToArray();

                double[] percents = ExplosionForceWorker.GetPercentOfProjForce(distances);

                for (int cntr = 0; cntr < vectors.Length; cntr++)
                {
                    Vector3D along = vectors[cntr].Along * (hitForceBase * percents[cntr] * trkProjForceOverall.Value);
                    Vector3D orth = vectors[cntr].Orth * (hitForceBase * percents[cntr] * trkProjForceOverall.Value);

                    AddLine_Billboard(vectors[cntr].ForcePoint, vectors[cntr].ForcePoint + along, LINETHICKNESS_BILLBOARD / 3, UtilityWPF.ColorFromHex("808080"));
                    AddLine_Billboard(vectors[cntr].ForcePoint, vectors[cntr].ForcePoint + orth, LINETHICKNESS_BILLBOARD / 3, UtilityWPF.ColorFromHex("808080"));
                }
            }
        }
        private static Vector3D? GetScaledDirection(Tuple<Point3D, Vector3D>[] nearby)
        {
            Vector3D retVal = new Vector3D(0, 0, 0);

            for (int cntr = 0; cntr < nearby.Length; cntr++)
            {
                retVal += nearby[cntr].Item2;
            }

            if (Math3D.IsNearZero(retVal))
            {
                return null;
            }

            return retVal.ToUnit();
        }
        private void ShadowMultiStepSprtFinish(Point3D cameraPos, Vector3D cameraLook, TriangleIndexed[] triangles)
        {
            // Order by distance to plane
            ITriangleIndexed[] sorted = Math3D.SortByPlaneDistance(triangles, cameraPos, cameraLook);

            SortedList<int, List<Point3D[]>> clipPolygons = new SortedList<int, List<Point3D[]>>();

            Vector3D hullDepth = cameraLook.ToUnit() * 50d;

            //for (int outer = 0; outer < sorted.Length - 1; outer++)
            for (int outer = 0; outer < sorted.Length; outer++)
            {
                // Create a volume out of the this triangle
                ITriangleIndexed[] hull = GetHullFromTriangle(sorted[outer], hullDepth);

                if (hull != null && hull.Length > 6)        // if the triangle is super thin, then a 2D hull will be created
                {
                    //for (int inner = outer + 1; inner < sorted.Length; inner++)
                    for (int inner = 0; inner < sorted.Length; inner++)
                    {
                        if (outer == inner)
                        {
                            continue;
                        }

                        Point3D[] poly = HullTriangleIntersect2.GetIntersection_Hull_Triangle(hull, sorted[inner]);
                        if (poly != null)
                        {
                            if (!clipPolygons.ContainsKey(inner))
                            {
                                clipPolygons.Add(inner, new List<Point3D[]>());
                            }

                            clipPolygons[inner].Add(poly);
                        }
                    }
                }
            }

            double[] percents = new double[sorted.Length];
            for (int cntr = 0; cntr < sorted.Length; cntr++)
            {
                if (clipPolygons.ContainsKey(cntr))
                {
                    percents[cntr] = GetPercentVisible(new Point3D[] { sorted[cntr].Point0, sorted[cntr].Point1, sorted[cntr].Point2 }, clipPolygons[cntr].ToArray());
                }
                else
                {
                    percents[cntr] = 1d;
                }
            }

            #region Draw

            Visual3D visual;
            Color color;

            // % in shadow
            for (int cntr = 0; cntr < sorted.Length; cntr++)
            {
                color = UtilityWPF.AlphaBlend(Colors.White, Colors.Black, percents[cntr]);

                visual = GetVisual_PolygonLines(new Point3D[] { sorted[cntr].Point0, sorted[cntr].Point1, sorted[cntr].Point2 }, color, 2d);
                _debugVisuals.Add(visual);
                _viewport.Children.Add(visual);
            }

            // Clip polygons
            foreach (Point3D[] polygon in clipPolygons.Values.SelectMany(o => o))
            {
                visual = GetVisual_PolygonHull(polygon, Colors.DodgerBlue, .005);
                _debugVisuals.Add(visual);
                _viewport.Children.Add(visual);
            }

            // Triangles
            color = UtilityWPF.ColorFromHex("50E0E0E0");

            for (int cntr = 0; cntr < sorted.Length; cntr++)
            {
                visual = GetVisual_Triangle(new ITriangle[] { sorted[cntr] }, color);
                _debugVisuals.Add(visual);
                _viewport.Children.Add(visual);
            }


            //// Draw the plane
            //visual = GetTriangleVisual(GetPlane(_camera.Position, _camera.LookDirection, 60), UtilityWPF.ColorFromHex("20B0B0B0"));
            //_debugVisuals.Add(visual);
            //_viewport.Children.Add(visual);

            #endregion



        }
        //TODO: These two are aspects of the same thing.  Make a single method for this
        private static double GetScore_UnderPowered(Vector3D? objective, Vector3D actual, double maxPossible)
        {
            if (objective == null || objective.Value.LengthSquared.IsNearZero())
            {
                // The underpowered check doesn't care about this condition
                return 0;
            }

            double lenSqr = actual.LengthSquared;
            double maxSqr = maxPossible * maxPossible;

            double dot = Vector3D.DotProduct(objective.Value.ToUnit(false), actual.ToUnit(false));

            // This makes sure it's actually pushing the bot, and not just balancing forces
            double underPower = 0;
            if (lenSqr * dot < maxSqr)
            {
                if (dot > 0)
                {
                    underPower = maxSqr - (lenSqr * dot);
                }
                else
                {
                    underPower = maxSqr;
                }
            }

            return underPower;
        }
        //TODO: Have a way to determine which props will be needed up front, and only populate those
        /// <param name="item">NOTE: This is the item chasing, NOT the item being chased</param>
        public ChasePoint_GetForceArgs(IMapObject item, Vector3D direction)
        {
            this.Item = item;
            this.ItemMass = item.PhysicsBody.Mass;

            this.DirectionLength = direction.Length;
            this.DirectionUnit = direction.ToUnit(false);

            // Velocity
            Vector3D velocity = this.Item.PhysicsBody.Velocity;
            this.VelocityLength = velocity.Length;
            this.VelocityUnit = velocity.ToUnit(false);

            // Along
            Vector3D velocityAlong = velocity.GetProjectedVector(direction);
            this.VelocityAlongLength = velocityAlong.Length;
            this.VelocityAlongUnit = velocityAlong.ToUnit(false);
            this.IsVelocityAlongTowards = Vector3D.DotProduct(direction, velocity) > 0d;

            // Orth
            Vector3D orth = Vector3D.CrossProduct(direction, velocity);       // the first cross is orth to both (outside the plane)
            orth = Vector3D.CrossProduct(orth, direction);       // the second cross is in the plane, but orth to distance
            Vector3D velocityOrth = velocity.GetProjectedVector(orth);

            this.VelocityOrthLength = velocityOrth.Length;
            this.VelocityOrthUnit = velocityOrth.ToUnit(false);
        }
示例#8
0
        private static Vector3D CapVector(Vector3D vector, double maxLength)
        {
            if (vector.LengthSquared <= maxLength * maxLength)
            {
                return vector;
            }

            return vector.ToUnit(false) * maxLength;
        }
            private static bool CanCounterVectors2(Vector3D[] tests, Vector3D[] others)
            {
                Vector3D cumulative = new Vector3D();
                foreach (Vector3D test in tests)
                {
                    cumulative += test;
                }

                // Make the cumulative point the opposite way (that's what all the tests need)
                cumulative = cumulative * -1d;

                // Check for 0D, 1D, 2D, 3D opposition
                if (others.Length == 0)
                {
                    #region 0D

                    // Nothing to oppose.  The only thing that works is if the test self cancel
                    return Math3D.IsNearZero(cumulative);

                    #endregion
                }
                else if (others.Length == 1)
                {
                    #region 1D

                    // Opposition is a single line
                    // If cumulative's length is longer, then the other is overwhelmed
                    // If the dot product isn't one, then they aren't lined up (cumulative has already been negated)
                    return cumulative.LengthSquared <= others[0].LengthSquared && Math1D.IsNearValue(Vector3D.DotProduct(cumulative.ToUnit(), others[0].ToUnit()), 1d);

                    #endregion
                }
                else if (others.Length == 2)
                {
                    #region 2D

                    // Opposition forms a parallelagram
                    Triangle triangle = new Triangle(new Point3D(0, 0, 0), others[0].ToPoint(), others[1].ToPoint());
                    if (!Math1D.IsNearZero(Vector3D.DotProduct(triangle.Normal, cumulative)))
                    {
                        return false;
                    }

                    Vector bary = Math3D.ToBarycentric(triangle, cumulative.ToPoint());
                    return bary.X >= 0d && bary.Y >= 0d && bary.X + bary.Y <= 2d;

                    #endregion
                }
                else
                {
                    #region 3D

                    //NOTE: The reason there is no need to check for 4D, 5D, etc is because cumulative is a 3D vector

                    // Build the hull out of others
                    Point3D[] extremes = GetRemainingExtremes(others, new int[0]);

                    TriangleIndexed[] hull = Math3D.GetConvexHull(extremes);
                    if (hull != null)
                    {
                        return Math3D.IsInside_Planes(hull, cumulative.ToPoint());
                    }

                    // If hull is null, the points could be coplanar, so try 2D
                    var perimiter = Math2D.GetConvexHull(extremes);
                    if (perimiter != null)
                    {
                        // These are coplanar, see if the cumulative is inside
                        Point? cumulative2D = perimiter.GetTransformedPoint(cumulative.ToPoint());

                        if (cumulative2D == null)
                        {
                            return false;
                        }
                        else
                        {
                            return perimiter.IsInside(cumulative2D.Value);
                        }
                    }

                    return false;

                    #endregion
                }
            }
            private static Vector3D GetThrustLine(Vector3D force, double strengthRatio)
            {
                const double MULT = -1d;		// the desired length when force.length / strengthRatio is one

                double ratio = MULT * force.Length / strengthRatio;

                return force.ToUnit() * MULT;
            }
示例#11
0
        private static IEnumerable<ThrusterSetting> EnsureThrustKeysBuilt_Rotate(Vector3D axis, ThrustContribution[] contributions, double maxAcceleration, MassMatrix inertia)
        {
            axis = axis.ToUnit();     // doing this so the dot product can be used as a percent

            List<Tuple<ThrustContribution, double>> retVal = new List<Tuple<ThrustContribution, double>>();

            // Get a list of thrusters that will contribute to the direction
            foreach (ThrustContribution contribution in contributions)
            {
                double dot = Vector3D.DotProduct(contribution.TorqueUnit, axis);

                if (dot > .5d)
                {
                    //retVal.Add(new ThrusterSetting(contribution.Thruster, contribution.Index, 1));     // for now, just do 100%
                    retVal.Add(Tuple.Create(contribution, contribution.TorqueLength * dot));
                }
            }

            retVal = FilterThrusts(retVal);

            #region Reduce Percent

            double percent = 1;

            if (retVal.Count > 0)
            {
                double torque = retVal.Sum(o => o.Item2);

                // A=F/M
                //double accel = torque / (Vector3D.DotProduct(inertia.Inertia, axis) * inertia.Mass);
                double accel = torque / Math.Abs(Vector3D.DotProduct(inertia.Inertia, axis));

                if (accel > maxAcceleration)
                {
                    percent = maxAcceleration / accel;
                }
            }

            #endregion

            return retVal.Select(o => new ThrusterSetting(o.Item1.Thruster, o.Item1.Index, percent)).ToArray();     // commiting to array so that this linq isn't rerun each time it's iterated over
        }
示例#12
0
        /// <summary>
        /// This overload will cut back the returned percents if the thrusters exceed the acceleration passed in
        /// </summary>
        private static IEnumerable<ThrusterSetting> EnsureThrustKeysBuilt_Linear(Vector3D direction, ThrustContribution[] contributions, double maxAcceleration, double mass)
        {
            direction = direction.ToUnit();     // doing this so the dot product can be used as a percent

            List<Tuple<ThrustContribution, double>> retVal = new List<Tuple<ThrustContribution, double>>();

            // Get a list of thrusters that will contribute to the direction
            foreach (ThrustContribution contribution in contributions)
            {
                double dot = Vector3D.DotProduct(contribution.TranslationForceUnit, direction);

                if (dot > .05d)
                {
                    retVal.Add(Tuple.Create(contribution, contribution.TranslationForceLength * dot));
                }
            }

            retVal = FilterThrusts(retVal);

            #region Reduce Percent

            double percent = 1;

            if (retVal.Count > 0)
            {
                double force = retVal.Sum(o => o.Item2);

                //F=MA, A=F/M
                double accel = force / mass;

                if (accel > maxAcceleration)
                {
                    percent = maxAcceleration / accel;
                }
            }

            #endregion

            return retVal.Select(o => new ThrusterSetting(o.Item1.Thruster, o.Item1.Index, percent)).ToArray();     // commiting to array so that this linq isn't rerun each time it's iterated over
        }
示例#13
0
        private static IEnumerable<ThrusterSetting> EnsureThrustKeysBuilt_Rotate(Vector3D torque, ThrustContribution[] contributions)
        {
            torque = torque.ToUnit();     // doing this so the dot product can be used as a percent

            List<Tuple<ThrustContribution, double>> retVal = new List<Tuple<ThrustContribution, double>>();

            // Get a list of thrusters that will contribute to the direction
            foreach (ThrustContribution contribution in contributions)
            {
                double dot = Vector3D.DotProduct(contribution.TorqueUnit, torque);

                if (dot > .5d)
                {
                    retVal.Add(Tuple.Create(contribution, contribution.TorqueLength * dot));
                }

                //if (dot > .05d)
                //{
                //    retVal.Add(new ThrusterSetting(thruster, cntr, dot));     // for now, use the dot as the percent
                //}
            }

            retVal = FilterThrusts(retVal, .05);

            return retVal.Select(o => new ThrusterSetting(o.Item1.Thruster, o.Item1.Index, 1)).ToArray();     // commiting to array so that this linq isn't rerun each time it's iterated over
        }
示例#14
0
        private void UpdateNeurons_fixed(Vector3D gravity, double magnitude)
        {
            const double MINDOT = 1d;

            if (Math3D.IsNearZero(gravity))
            {
                // There is no gravity to report
                for (int cntr = 0; cntr < _neurons.Length; cntr++)
                {
                    _neurons[cntr].Value = 0d;
                }
                return;
            }

            Vector3D gravityUnit = gravity.ToUnit();

            for (int cntr = 0; cntr < _neurons.Length; cntr++)
            {
                if (_neurons[cntr].PositionUnit == null)
                {
                    // This neuron is sitting at 0,0,0
                    _neurons[cntr].Value = magnitude;
                }
                else
                {
                    double dot = Vector3D.DotProduct(gravityUnit, _neurons[cntr].PositionUnit.Value);
                    dot += 1d;		// get this to scale from 0 to 2 instead of -1 to 1

                    if (dot < MINDOT)
                    {
                        _neurons[cntr].Value = 0d;
                    }
                    else
                    {
                        _neurons[cntr].Value = UtilityCore.GetScaledValue_Capped(0d, 1d, MINDOT, 2d, dot);
                    }
                }
            }
        }
示例#15
0
        /// <summary>
        /// This sets all the neurons from 0 to magnitude.  Magnitude needs to be from 0 to 1, and is based on the currently felt gravity compared
        /// to what the sensor has seen as the max felt
        /// </summary>
        internal static void UpdateNeurons(Neuron_SensorPosition[] neurons, double neuronMaxRadius, Vector3D vector, double magnitude)
        {
            const double MINDOT = 1.25d;

            if (Math3D.IsNearZero(vector))
            {
                // There is no gravity to report
                for (int cntr = 0; cntr < neurons.Length; cntr++)
                {
                    neurons[cntr].Value = 0d;
                }
                return;
            }

            Vector3D gravityUnit = vector.ToUnit();

            for (int cntr = 0; cntr < neurons.Length; cntr++)
            {
                if (neurons[cntr].PositionUnit == null)
                {
                    // This neuron is sitting at 0,0,0
                    neurons[cntr].Value = magnitude;
                }
                else
                {
                    // Figure out how aligned this neuron is with the gravity vector
                    double dot = Vector3D.DotProduct(gravityUnit, neurons[cntr].PositionUnit.Value);
                    dot += 1d;		// get this to scale from 0 to 2 instead of -1 to 1

                    // Scale minDot
                    double radiusPercent = neurons[cntr].PositionLength / neuronMaxRadius;
                    double revisedMinDot = UtilityCore.GetScaledValue_Capped(0d, MINDOT, 0d, 1d, radiusPercent);

                    // Rig it so that the lower radius neurons will fire stronger
                    double minReturn = 1d - radiusPercent;
                    if (minReturn < 0d)
                    {
                        minReturn = 0d;
                    }

                    // Figure out what percentage of magnitude to use
                    double percent;
                    if (dot < revisedMinDot)
                    {
                        percent = UtilityCore.GetScaledValue_Capped(0d, minReturn, 0d, revisedMinDot, dot);
                    }
                    else
                    {
                        percent = UtilityCore.GetScaledValue_Capped(minReturn, 1d, revisedMinDot, 2d, dot);
                    }

                    // Set the neuron
                    neurons[cntr].Value = percent * magnitude;
                }
            }
        }
        /// <summary>
        /// This will figure how much velocity to apply to each bodyCenter
        /// TODO: Also calculate angular velocities
        /// </summary>
        /// <param name="bodyCenters">The bodies to apply velocity to</param>
        /// <param name="hitStart">The point of impact</param>
        /// <param name="hitDirection">The direction and force of the impact</param>
        /// <param name="mainBodyRadius">The avg radius of the body that is getting blown apart</param>
        private static Vector3D[] DistributeForces(Point3D[] bodyCenters, Point3D hitStart, Vector3D hitDirection, double mainBodyRadius, HullVoronoiExploder_Options options)
        {
            Vector3D hitDirectionUnit = hitDirection.ToUnit();
            double hitForceBase = hitDirection.Length / mainBodyRadius;

            var vectors = bodyCenters.
                Select(o =>
                {
                    Vector3D direction = o - hitStart;
                    Vector3D directionUnit = direction.ToUnit();

                    double distance = direction.Length;
                    double scaledDistance = distance;
                    if (options.DistanceDot_Power != null)
                    {
                        double linearDot = Math3D.GetLinearDotProduct(hitDirectionUnit, directionUnit);     // making it linear so the power function is more predictable

                        // Exaggerate the distance based on dot product.  That way, points in line with the hit will get more of the impact
                        double scale = (1 - Math.Abs(linearDot));
                        scale = Math.Pow(scale, options.DistanceDot_Power.Value);
                        scaledDistance = scale * distance;
                    }

                    return new
                    {
                        ForcePoint = o,
                        Distance = distance,
                        ScaledDistance = scaledDistance,
                        DirectionUnit = directionUnit,
                    };
                }).
                ToArray();

            double[] percents = GetPercentOfProjForce(vectors.Select(o => o.ScaledDistance).ToArray());

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

            for (int cntr = 0; cntr < vectors.Length; cntr++)
            {
                retVal[cntr] = vectors[cntr].DirectionUnit * (hitForceBase * percents[cntr]);
            }

            return retVal;
        }
        public static double GetMaximumPossible_Rotation(ThrustContributionModel model, Vector3D direction)
        {
            direction = direction.ToUnit();     // doing this so the dot product can be used as a percent

            double retVal = 0d;

            foreach (var contribution in model.Contributions)
            {
                retVal += contribution.Item3.Torque.GetProjectedVector(direction, false).Length;
            }

            return retVal;
        }
        // These return error as a square (so the numbers can get big quick)
        private static double GetScore_Balance(Vector3D? objective, Vector3D actual)
        {
            if (objective == null || objective.Value.LengthSquared.IsNearZero())
            {
                // When null, the objective is zero.  So any length is an error
                return actual.LengthSquared;
            }

            double dot = Vector3D.DotProduct(objective.Value.ToUnit(false), actual.ToUnit(false));

            // Ideal dot is 1, so 1-1 is 0.
            // 1 - 0 is 1
            // 1 - -1 is 2
            // So divide by 2 to get difference in a range of 0 to 1
            double difference = (1d - dot) / 2d;

            // Now that difference is scaled 0 to 1, use the length squared as max error
            double dotScale = actual.LengthSquared * difference;

            return dotScale;
        }
示例#19
0
        private static RayHitTestParameters CastRay_PlaneLimitedSprtGetSnapLine(ITriangle plane, Vector3D lookDirection)
        {
            const double THRESHOLD = .33d;

            #region Get orthogonal vectors

            Point3D centerPoint = new Point3D();
            DoubleVector testVectors = new DoubleVector();

            //This assumes that the plane was set up with orthogonal vectors, and that these are the ones to use in this case

            for (int cntr = 0; cntr < 3; cntr++)
            {
                switch (cntr)
                {
                    case 0:
                        centerPoint = plane.Point0;
                        testVectors = new DoubleVector((plane.Point1 - plane.Point0).ToUnit(), (plane.Point2 - plane.Point0).ToUnit());
                        break;

                    case 1:
                        centerPoint = plane.Point1;
                        testVectors = new DoubleVector((plane.Point2 - plane.Point1).ToUnit(), (plane.Point0 - plane.Point1).ToUnit());
                        break;

                    case 2:
                        centerPoint = plane.Point2;
                        testVectors = new DoubleVector((plane.Point0 - plane.Point2).ToUnit(), (plane.Point1 - plane.Point2).ToUnit());
                        break;

                    default:
                        throw new ApplicationException("Unexpected cntr: " + cntr.ToString());
                }

                if (Math1D.IsNearZero(Vector3D.DotProduct(testVectors.Standard, testVectors.Orth)))
                {
                    break;
                }
            }

            #endregion

            double dot = Vector3D.DotProduct(testVectors.Standard, lookDirection.ToUnit());
            if (Math.Abs(dot) < THRESHOLD)
            {
                return new RayHitTestParameters(centerPoint, testVectors.Standard);		// standard is fairly orhogonal to the camera's look direction, so only allow the part to slide along this axis
            }

            dot = Vector3D.DotProduct(testVectors.Orth, lookDirection.ToUnit());
            if (Math.Abs(dot) < THRESHOLD)
            {
                return new RayHitTestParameters(centerPoint, testVectors.Orth);
            }

            return null;
        }
        private void FireRay(Point clickPoint)
        {
            // This is how microsoft recomends doing hit tests, but I don't care about wpf models.  I just want the world coords of the mouse
            //HitTestResult result = VisualTreeHelper.HitTest(grdViewPort, clickPoint, );

            // Project the mouse click into world coords
            RayHitTestParameters hitParam = UtilityWPF.RayFromViewportPoint(_camera, _viewport, clickPoint);
            _rayPoint = hitParam.Origin;
            _rayDirection = hitParam.Direction;

            if (_leftClickAction == LeftClickAction.ShootBall)
            {
                FireRaySprtShootBall();
                return;
            }

            List<WorldBase.IntersectionPoint> hits = _world.RayCast(_rayPoint, _rayPoint + (_rayDirection.ToUnit() * 1000d));

            switch (_leftClickAction)
            {
                case LeftClickAction.Remove:
                    #region Remove

                    if (hits.Count > 0)
                    {
                        RemoveBrick(hits[0].Body);
                    }

                    #endregion
                    break;

                case LeftClickAction.RemoveLine:
                    #region RemoveLine

                    foreach (WorldBase.IntersectionPoint hit in hits)
                    {
                        RemoveBrick(hit.Body);
                    }

                    #endregion
                    break;

                case LeftClickAction.Explode:
                    #region Explode

                    if (hits.Count > 0 && hits[0].Body.MaterialGroupID == _material_Brick)
                    {
                        ExplodeBody(hits[0].Body, true, trkLeftExplodePower.Value);

                        // Remove from brick list
                        _bricks.Remove(hits[0].Body);
                    }

                    #endregion
                    break;

                case LeftClickAction.ExplodeLine:
                    #region ExplodeLine

                    foreach (WorldBase.IntersectionPoint hit in hits)
                    {
                        if (hit.Body.MaterialGroupID == _material_Brick)
                        {
                            ExplodeBody(hit.Body, true, trkLeftExplodePower.Value);

                            // Remove from brick list
                            _bricks.Remove(hit.Body);
                        }
                    }

                    #endregion
                    break;

                case LeftClickAction.Implode:
                    #region Implode

                    if (hits.Count > 0 && hits[0].Body.MaterialGroupID == _material_Brick)
                    {
                        ExplodeBody(hits[0].Body, false, trkLeftExplodePower.Value);

                        // Remove from brick list
                        _bricks.Remove(hits[0].Body);
                    }

                    #endregion
                    break;

                case LeftClickAction.ImplodeLine:
                    #region ImplodeLine

                    foreach (WorldBase.IntersectionPoint hit in hits)
                    {
                        if (hit.Body.MaterialGroupID == _material_Brick)
                        {
                            ExplodeBody(hit.Body, false, trkLeftExplodePower.Value);

                            // Remove from brick list
                            _bricks.Remove(hit.Body);
                        }
                    }

                    #endregion
                    break;

                case LeftClickAction.ForceBeam:
                    // Nothing to do here, it's all in the apply force/torque callback
                    break;

                default:
                    // Paint them green for now
                    foreach (WorldBase.IntersectionPoint hit in hits)
                    {
                        if (_bodyMaterials.ContainsKey(hit.Body))		// the terrain isn't in the list
                        {
                            _bodyMaterials[hit.Body].Material.Brush = new SolidColorBrush(Colors.Chartreuse);
                        }
                    }
                    break;
            }
        }