Ejemplo n.º 1
0
        private bool PrevOverSpeedLimit(Anchor anchor)
        {
            if (anchor.PreviousAnchor == null)
            {
                return(false);
            }

            var diff = anchor.Pos - anchor.PreviousAnchor.Pos;

            if (ViewModel.GraphModeSetting == SlideratorVm.GraphMode.Position)
            {
                return(Math.Abs(InterpolatorHelper.GetBiggestDerivative(anchor.Interpolator) * diff.Y / diff.X)
                       / ViewModel.SvGraphMultiplier > ViewModel.VelocityLimit);
            }
            return(Math.Abs(InterpolatorHelper.GetBiggestValue(anchor.Interpolator)) > ViewModel.VelocityLimit);
        }
Ejemplo n.º 2
0
        private void AnchorsOnAnchorsChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (_ignoreAnchorsChange)
            {
                return;
            }

            var anchor = (Anchor)sender;

            // Correct the anchor change if it resulted in a speed limit violation
            if (PrevOverSpeedLimit(anchor) || NextOverSpeedLimit(anchor))
            {
                _ignoreAnchorsChange      = true;
                Graph.IgnoreAnchorUpdates = true;

                // Use binary search to find the closest value to the limit
                const double d = 0.001;

                switch (e.NewValue)
                {
                case double newDouble:
                    var oldDouble = (double)e.OldValue;

                    // Test if the old value is also a illegal speed violation
                    anchor.SetValue(e.Property, oldDouble);
                    if (PrevOverSpeedLimit(anchor) || NextOverSpeedLimit(anchor))
                    {
                        anchor.SetValue(e.Property, newDouble);
                        break;
                    }

                    anchor.SetValue(e.Property, BinarySearchUtil.DoubleBinarySearch(
                                        oldDouble, newDouble, d,
                                        mid => {
                        anchor.SetValue(e.Property, mid);
                        return(!PrevOverSpeedLimit(anchor) && !NextOverSpeedLimit(anchor));
                    }));
                    break;

                case Vector2 newVector2:
                    if (ViewModel.GraphModeSetting == SlideratorVm.GraphMode.Position && anchor.PreviousAnchor != null)
                    {
                        // List of bounds. X represents the minimum Y value and Y represents the maximum Y value
                        // I use Vector2 here because it has useful math methods
                        var bounds = new List <Vector2>();

                        if (anchor.PreviousAnchor != null)
                        {
                            var maxSpeed = InterpolatorHelper.GetBiggestDerivative(anchor.Interpolator);

                            if (Math.Abs(newVector2.X - anchor.PreviousAnchor.Pos.X) < Precision.DOUBLE_EPSILON)
                            {
                                bounds.Add(new Vector2(anchor.PreviousAnchor.Pos.Y));
                            }
                            else
                            {
                                bounds.Add(new Vector2(anchor.PreviousAnchor.Pos.Y) +
                                           new Vector2(Precision.DOUBLE_EPSILON).PerpendicularRight +
                                           new Vector2(ViewModel.VelocityLimit * ViewModel.SvGraphMultiplier *
                                                       (newVector2.X - anchor.PreviousAnchor.Pos.X) / maxSpeed)
                                           .PerpendicularLeft);
                            }
                        }

                        if (anchor.NextAnchor != null)
                        {
                            var maxSpeed = InterpolatorHelper.GetBiggestDerivative(anchor.NextAnchor.Interpolator);

                            if (Math.Abs(newVector2.X - anchor.NextAnchor.Pos.X) < Precision.DOUBLE_EPSILON)
                            {
                                bounds.Add(new Vector2(anchor.NextAnchor.Pos.Y));
                            }
                            else
                            {
                                bounds.Add(new Vector2(anchor.NextAnchor.Pos.Y) +
                                           new Vector2(Precision.DOUBLE_EPSILON).PerpendicularRight +
                                           new Vector2(ViewModel.VelocityLimit * ViewModel.SvGraphMultiplier *
                                                       (newVector2.X - anchor.NextAnchor.Pos.X) / maxSpeed)
                                           .PerpendicularRight);
                            }
                        }

                        // Clamp the new Y value between all the bounds
                        var newY = bounds.Aggregate(newVector2.Y,
                                                    (current, bound) => MathHelper.Clamp(current, bound.X, bound.Y));

                        // Break if the resulting value is not inside all the bounds
                        if (!bounds.All(b => newY >= b.X && newY <= b.Y))
                        {
                            break;
                        }

                        anchor.SetValue(e.Property, new Vector2(newVector2.X, newY));
                    }

                    break;
                }

                _ignoreAnchorsChange      = false;
                Graph.IgnoreAnchorUpdates = false;
            }

            if (ViewModel.PixelLength < HitObjectElement.MaxPixelLength)
            {
                AnimateProgress(GraphHitObjectElement);
            }
            UpdatePointsOfInterest();
            UpdateVelocity();
        }