AlmostEquals() public static method

public static AlmostEquals ( this a, double b, double epsilon = DOUBLE_EPSILON ) : bool
a this
b double
epsilon double
return bool
        public void TestContainerAutoSizeUpdatesWhenChildBecomesAlive()
        {
            Box       box    = null;
            Container parent = null;

            AddStep("create test", () =>
            {
                Child = parent = new Container
                {
                    RemoveCompletedTransforms = false,
                    AutoSizeAxes = Axes.Both,
                    Child        = box = new Box
                    {
                        Size          = new Vector2(200),
                        LifetimeStart = double.MaxValue
                    }
                };
            });

            AddStep("make child alive", () => box.LifetimeStart = double.MinValue);

            AddAssert("parent has size 200", () => Precision.AlmostEquals(new Vector2(200), parent.DrawSize));
        }
        public void TestContentAnchors()
        {
            AddStep("Create scroll container with centre-left content", () =>
            {
                Add(scrollContainer = new BasicScrollContainer
                {
                    Anchor        = Anchor.Centre,
                    Origin        = Anchor.Centre,
                    Size          = new Vector2(300),
                    ScrollContent =
                    {
                        Anchor = Anchor.CentreLeft,
                        Origin = Anchor.CentreLeft,
                    },
                    Child = new Box {
                        Size = new Vector2(300, 400)
                    }
                });
            });

            AddStep("Scroll to 0", () => scrollContainer.ScrollTo(0, false));
            AddAssert("Content position at top", () => Precision.AlmostEquals(scrollContainer.ScreenSpaceDrawQuad.TopLeft, scrollContainer.ScrollContent.ScreenSpaceDrawQuad.TopLeft));
        }
示例#3
0
        [TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 150)]               // (0 * 1 * 300) * (1 + 0 / 25) * 3 * 50 (bonus points)
        public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore)
        {
            var minResult = new TestJudgement(hitResult).MinResult;

            IBeatmap fourObjectBeatmap = new TestBeatmap(new RulesetInfo())
            {
                HitObjects = new List <HitObject>(Enumerable.Repeat(new TestHitObject(maxResult), 4))
            };

            scoreProcessor.Mode.Value = scoringMode;
            scoreProcessor.ApplyBeatmap(fourObjectBeatmap);

            for (int i = 0; i < 4; i++)
            {
                var judgementResult = new JudgementResult(fourObjectBeatmap.HitObjects[i], new Judgement())
                {
                    Type = i == 2 ? minResult : hitResult
                };
                scoreProcessor.ApplyResult(judgementResult);
            }

            Assert.IsTrue(Precision.AlmostEquals(expectedScore, scoreProcessor.TotalScore.Value, 0.5));
        }
示例#4
0
        public void TestSpinRateUnaffectedByMods(Type additionalModType)
        {
            var mods = new List <Mod> {
                new OsuModSpunOut()
            };

            if (additionalModType != null)
            {
                mods.Add((Mod)Activator.CreateInstance(additionalModType));
            }

            CreateModTest(new ModTestData
            {
                Mods          = mods,
                Autoplay      = false,
                Beatmap       = singleSpinnerBeatmap,
                PassCondition = () =>
                {
                    var counter = Player.ChildrenOfType <SpinnerSpmCounter>().SingleOrDefault();
                    return(counter != null && Precision.AlmostEquals(counter.SpinsPerMinute, 286, 1));
                }
            });
        }
示例#5
0
        public void TestAutoSizeDoesNotConsiderRelativeSizeChildren(bool row)
        {
            Box relativeBox = null;
            Box absoluteBox = null;

            setSingleDimensionContent(() => new[]
            {
                new Drawable[]
                {
                    relativeBox = new FillBox {
                        RelativeSizeAxes = Axes.Both
                    },
                    absoluteBox = new FillBox
                    {
                        RelativeSizeAxes = Axes.None,
                        Size             = new Vector2(100)
                    }
                }
            }, new[] { new Dimension(GridSizeMode.AutoSize) }, row);

            AddStep("resize absolute box", () => absoluteBox.Size = new Vector2(50));
            AddAssert("relative box has length 50", () => Precision.AlmostEquals(row ? relativeBox.DrawHeight : relativeBox.DrawWidth, 50, 1));
        }
示例#6
0
        public void Test3CellRowOrColumnDistributedXy(bool row)
        {
            FillBox[] boxes = new FillBox[3];

            setSingleDimensionContent(() => new[]
            {
                new Drawable[] { boxes[0] = new FillBox(), boxes[1] = new FillBox(), boxes[2] = new FillBox() }
            }, row: row);

            for (int i = 0; i < 3; i++)
            {
                int local = i;

                if (row)
                {
                    AddAssert($"box {local} has correct size", () => Precision.AlmostEquals(boxes[local].DrawSize, new Vector2(grid.DrawWidth / 3f, grid.DrawHeight)));
                }
                else
                {
                    AddAssert($"box {local} has correct size", () => Precision.AlmostEquals(boxes[local].DrawSize, new Vector2(grid.DrawWidth, grid.DrawHeight / 3f)));
                }
            }
        }
示例#7
0
        public void TestEnableAndDisablePassword()
        {
            DrawableRoom drawableRoom = null;
            Room         room         = null;

            AddStep("create room", () => Child = drawableRoom = new DrawableRoom(room = new Room
            {
                Name     = { Value = "Room with password" },
                Status   = { Value = new RoomStatusOpen() },
                Category = { Value = RoomCategory.Realtime },
            })
            {
                MatchingFilter = true
            });

            AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType <DrawableRoom.PasswordProtectedIcon>().Single().Alpha));

            AddStep("set password", () => room.Password.Value = "password");
            AddAssert("password icon visible", () => Precision.AlmostEquals(1, drawableRoom.ChildrenOfType <DrawableRoom.PasswordProtectedIcon>().Single().Alpha));

            AddStep("unset password", () => room.Password.Value = string.Empty);
            AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType <DrawableRoom.PasswordProtectedIcon>().Single().Alpha));
        }
示例#8
0
        protected override void Update()
        {
            base.Update();

            var elapsedFrameTime = Clock.ElapsedFrameTime;

            if (Math.Abs(verticalSpeed) > max_vertical_speed)
            {
                verticalSpeed = Math.Sign(verticalSpeed) * max_vertical_speed;
            }

            if (Precision.AlmostEquals(verticalSpeed, 0, 0.0001))
            {
                verticalSpeed = 0;
            }

            var adjustedVerticalDistance = verticalSpeed * (elapsedFrameTime / 20);

            Y -= (float)adjustedVerticalDistance;
            X += (float)(speedVector.X * (elapsedFrameTime / 20));

            verticalSpeed -= gravity * (elapsedFrameTime / 20);
        }
        public void TestBypassAutoSizeAxes()
        {
            const float autosize_height = 300;

            Container autoSizeContainer = null;
            Box       boxSizeReference  = null;

            AddStep("init", () =>
            {
                Child = autoSizeContainer = new Container
                {
                    Anchor       = Anchor.Centre,
                    Origin       = Anchor.Centre,
                    Width        = 300,
                    AutoSizeAxes = Axes.Y,
                    Children     = new Drawable[]
                    {
                        new Box
                        {
                            Colour           = Color4.Green,
                            RelativeSizeAxes = Axes.Both
                        },
                        boxSizeReference = new Box
                        {
                            RelativeSizeAxes = Axes.X,
                            Height           = autosize_height,
                            Colour           = Color4.Red.Opacity(0.2f),
                        }
                    }
                };
            });
            AddAssert($"height = {autosize_height}", () => Precision.AlmostEquals(autosize_height, autoSizeContainer.DrawHeight));
            AddStep("bypass y", () => boxSizeReference.BypassAutoSizeAxes = Axes.Y);
            AddAssert("height = 0", () => Precision.AlmostEquals(0, autoSizeContainer.DrawHeight));
            AddStep("bypass none", () => boxSizeReference.BypassAutoSizeAxes = Axes.None);
            AddAssert($"height = {autosize_height}", () => Precision.AlmostEquals(autosize_height, autoSizeContainer.DrawHeight));
        }
        public void TestRowSize()
        {
            AddStep("set content", () =>
            {
                table.Content = createContent(2, 2);
                table.RowSize = new Dimension(GridSizeMode.Absolute, 30f);
            });

            AddAssert("all row size = 30", () => testRows(30));
            AddStep("add headers", () => table.Columns = new[]
            {
                new TableColumn("Header 1"),
                new TableColumn("Header 2"),
                new TableColumn("Header 3"),
            });

            AddAssert("all row size = 30", () => testRows(30));
            AddStep("change row size", () => table.RowSize = new Dimension(GridSizeMode.Absolute, 50));
            AddAssert("all row size = 50", () => testRows(50));
            AddStep("change content", () => table.Content = createContent(4, 4));
            AddAssert("all row size = 50", () => testRows(50));
            AddStep("remove custom row size", () => table.RowSize = null);
            AddAssert("all row size = distributed", () => testRows(table.DrawHeight / 5f));

            bool testRows(float expectedHeight)
            {
                for (int row = 0; row < getGrid().Content.Count; row++)
                {
                    if (!Precision.AlmostEquals(expectedHeight, getGrid().Content[row][0].Parent.DrawHeight))
                    {
                        return(false);
                    }
                }

                return(true);
            }
        }
示例#11
0
        public void TestSeekPerformsInGameplayTime(
            [Values(1.0, 0.5, 2.0)] double clockRate,
            [Values(0.0, 200.0, -200.0)] double userOffset,
            [Values(false, true)] bool whileStopped,
            [Values(false, true)] bool setAudioOffsetBeforeConstruction)
        {
            ClockBackedTestWorkingBeatmap working = null;
            GameplayClockContainer        gameplayClockContainer = null;

            if (setAudioOffsetBeforeConstruction)
            {
                AddStep($"preset audio offset to {userOffset}", () => localConfig.SetValue(OsuSetting.AudioOffset, userOffset));
            }

            AddStep("create container", () =>
            {
                working = new ClockBackedTestWorkingBeatmap(new OsuRuleset().RulesetInfo, new FramedClock(new ManualClock()), Audio);
                working.LoadTrack();

                Child = gameplayClockContainer = new MasterGameplayClockContainer(working, 0);

                gameplayClockContainer.Reset(startClock: !whileStopped);
            });

            AddStep($"set clock rate to {clockRate}", () => working.Track.AddAdjustment(AdjustableProperty.Frequency, new BindableDouble(clockRate)));

            if (!setAudioOffsetBeforeConstruction)
            {
                AddStep($"set audio offset to {userOffset}", () => localConfig.SetValue(OsuSetting.AudioOffset, userOffset));
            }

            AddStep("seek to 2500", () => gameplayClockContainer.Seek(2500));
            AddAssert("gameplay clock time = 2500", () => Precision.AlmostEquals(gameplayClockContainer.CurrentTime, 2500, 10f));

            AddStep("seek to 10000", () => gameplayClockContainer.Seek(10000));
            AddAssert("gameplay clock time = 10000", () => Precision.AlmostEquals(gameplayClockContainer.CurrentTime, 10000, 10f));
        }
示例#12
0
        public void TestShowHideStatistics()
        {
            TestResultsScreen screen = null;

            AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen()));
            AddUntilStep("wait for load", () => this.ChildrenOfType <ScorePanelList>().Single().AllPanelsVisible);

            AddStep("click expanded panel", () =>
            {
                var expandedPanel = this.ChildrenOfType <ScorePanel>().Single(p => p.State == PanelState.Expanded);
                InputManager.MoveMouseTo(expandedPanel);
                InputManager.Click(MouseButton.Left);
            });

            AddAssert("statistics shown", () => this.ChildrenOfType <StatisticsPanel>().Single().State.Value == Visibility.Visible);

            AddUntilStep("expanded panel at the left of the screen", () =>
            {
                var expandedPanel = this.ChildrenOfType <ScorePanel>().Single(p => p.State == PanelState.Expanded);
                return(expandedPanel.ScreenSpaceDrawQuad.TopLeft.X - screen.ScreenSpaceDrawQuad.TopLeft.X < 150);
            });

            AddStep("click expanded panel", () =>
            {
                var expandedPanel = this.ChildrenOfType <ScorePanel>().Single(p => p.State == PanelState.Expanded);
                InputManager.MoveMouseTo(expandedPanel);
                InputManager.Click(MouseButton.Left);
            });

            AddAssert("statistics hidden", () => this.ChildrenOfType <StatisticsPanel>().Single().State.Value == Visibility.Hidden);

            AddUntilStep("expanded panel in centre of screen", () =>
            {
                var expandedPanel = this.ChildrenOfType <ScorePanel>().Single(p => p.State == PanelState.Expanded);
                return(Precision.AlmostEquals(expandedPanel.ScreenSpaceDrawQuad.Centre.X, screen.ScreenSpaceDrawQuad.Centre.X, 1));
            });
        }
        /// <summary>
        /// Start a sequence of <see cref="Transform"/>s with a (cumulative) relative delay applied.
        /// </summary>
        /// <param name="delay">The offset in milliseconds from current time. Note that this stacks with other nested sequences.</param>
        /// <param name="recursive">Whether this should be applied to all children. True by default.</param>
        /// <returns>An <see cref="InvokeOnDisposal"/> to be used in a using() statement.</returns>
        public IDisposable BeginDelayedSequence(double delay, bool recursive = true)
        {
            EnsureTransformMutationAllowed();

            if (delay == 0)
            {
                return(null);
            }

            AddDelay(delay, recursive);
            double newTransformDelay = TransformDelay;

            return(new ValueInvokeOnDisposal <DelayedSequenceSender>(new DelayedSequenceSender(this, delay, recursive, newTransformDelay), sender =>
            {
                if (!Precision.AlmostEquals(sender.NewTransformDelay, sender.Transformable.TransformDelay))
                {
                    throw new InvalidOperationException(
                        $"{nameof(sender.Transformable.TransformStartTime)} at the end of delayed sequence is not the same as at the beginning, but should be. " +
                        $"(begin={sender.NewTransformDelay} end={sender.Transformable.TransformDelay})");
                }

                AddDelay(-sender.Delay, sender.Recursive);
            }));
        }
        public void ScaleSequence()
        {
            boxTest(box =>
            {
                box.Scale = Vector2.One;

                box.ScaleTo(0.75f, interval).Then()
                .ScaleTo(0.5f, interval).Then()
                .ScaleTo(0.25f, interval).Then()
                .ScaleTo(0, interval);
            });

            int i = 0;

            checkAtTime(interval * ++i, box => Precision.AlmostEquals(box.Scale.X, 0.75f));
            checkAtTime(interval * ++i, box => Precision.AlmostEquals(box.Scale.X, 0.5f));
            checkAtTime(interval * ++i, box => Precision.AlmostEquals(box.Scale.X, 0.25f));
            checkAtTime(interval * ++i, box => Precision.AlmostEquals(box.Scale.X, 0f));

            checkAtTime(interval * (i -= 2), box => Precision.AlmostEquals(box.Scale.X, 0.5f));
            checkAtTime(interval * --i, box => Precision.AlmostEquals(box.Scale.X, 0.75f));

            AddAssert("check transform count", () => box.Transforms.Count == 4);
        }
示例#15
0
        public void TestSpinnerMiddleRewindingRotation()
        {
            double finalAbsoluteDiscRotation = 0, finalRelativeDiscRotation = 0, finalSpinnerSymbolRotation = 0;

            addSeekStep(5000);
            AddStep("retrieve disc relative rotation", () => finalRelativeDiscRotation   = drawableSpinner.Disc.Rotation);
            AddStep("retrieve disc absolute rotation", () => finalAbsoluteDiscRotation   = drawableSpinner.Disc.CumulativeRotation);
            AddStep("retrieve spinner symbol rotation", () => finalSpinnerSymbolRotation = spinnerSymbol.Rotation);

            addSeekStep(2500);
            AddUntilStep("disc rotation rewound",
                         // we want to make sure that the rotation at time 2500 is in the same direction as at time 5000, but about half-way in.
                         () => Precision.AlmostEquals(drawableSpinner.Disc.Rotation, finalRelativeDiscRotation / 2, 100));
            AddUntilStep("symbol rotation rewound",
                         () => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation / 2, 100));

            addSeekStep(5000);
            AddAssert("is disc rotation almost same",
                      () => Precision.AlmostEquals(drawableSpinner.Disc.Rotation, finalRelativeDiscRotation, 100));
            AddAssert("is symbol rotation almost same",
                      () => Precision.AlmostEquals(spinnerSymbol.Rotation, finalSpinnerSymbolRotation, 100));
            AddAssert("is disc rotation absolute almost same",
                      () => Precision.AlmostEquals(drawableSpinner.Disc.CumulativeRotation, finalAbsoluteDiscRotation, 100));
        }
            public OsuTKJoystickState(JoystickDevice device)
            {
                // Populate axes
                for (int i = 0; i < JoystickDevice.MAX_AXES; i++)
                {
                    var value = device.RawState.GetAxis(i);
                    if (!Precision.AlmostEquals(value, 0, device.DefaultDeadzones?[i] ?? Precision.FLOAT_EPSILON))
                    {
                        Axes.Add(new JoystickAxis(i, value));
                    }
                }

                // Populate normal buttons
                for (int i = 0; i < JoystickDevice.MAX_BUTTONS; i++)
                {
                    if (device.RawState.GetButton(i) == ButtonState.Pressed)
                    {
                        Buttons.SetPressed(JoystickButton.FirstButton + i, true);
                    }
                }

                // Populate hat buttons
                for (int i = 0; i < JoystickDevice.MAX_HATS; i++)
                {
                    foreach (var hatButton in getHatButtons(device, i))
                    {
                        Buttons.SetPressed(hatButton, true);
                    }
                }

                // Populate axis buttons (each axis has two buttons)
                foreach (var axis in Axes)
                {
                    Buttons.SetPressed((axis.Value < 0 ? JoystickButton.FirstAxisNegative : JoystickButton.FirstAxisPositive) + axis.Axis, true);
                }
            }
示例#17
0
        protected override void Update()
        {
            base.Update();

            // position updates should not occur if the item is filtered away.
            // this avoids panels flying across the screen only to be eventually off-screen or faded out.
            if (!Item.Visible)
            {
                return;
            }

            float targetY = Item.CarouselYPosition;

            if (Precision.AlmostEquals(targetY, Y))
            {
                Y = targetY;
            }
            else
            {
                // algorithm for this is taken from ScrollContainer.
                // while it doesn't necessarily need to match 1:1, as we are emulating scroll in some cases this feels most correct.
                Y = (float)Interpolation.Lerp(targetY, Y, Math.Exp(-0.01 * Time.Elapsed));
            }
        }
示例#18
0
 private void assertHue(float hue, float tolerance = 0.005f)
 {
     AddAssert($"hue selector has {hue}", () => Precision.AlmostEquals(colourPicker.HueControl.Hue.Value, hue, tolerance));
     AddAssert($"saturation/value selector has {hue}", () => Precision.AlmostEquals(colourPicker.SaturationValueControl.Hue.Value, hue, tolerance));
 }
示例#19
0
 private void assertSaturationAndValue(float saturation, float value, float tolerance = 0.005f)
 {
     AddAssert($"saturation is {saturation}", () => Precision.AlmostEquals(colourPicker.SaturationValueControl.Saturation.Value, saturation, tolerance));
     AddAssert($"value is {value}", () => Precision.AlmostEquals(colourPicker.SaturationValueControl.Value.Value, value, tolerance));
 }
示例#20
0
        private void assertSnappedDistance(float expectedDistance) => AddAssert($"snap distance = {expectedDistance}", () =>
        {
            Vector2 snappedPosition = grid.GetSnappedPosition(grid.ToLocalSpace(InputManager.CurrentState.Mouse.Position)).position;

            return(Precision.AlmostEquals(expectedDistance, Vector2.Distance(snappedPosition, grid_position)));
        });
示例#21
0
 /// <summary>
 /// Checks if a cursor is at the current inputmanager screen position.
 /// </summary>
 /// <param name="cursorContainer">The cursor to check.</param>
 private bool checkAtMouse(CursorContainer cursorContainer)
 => Precision.AlmostEquals(InputManager.CurrentState.Mouse.NativeState.Position, cursorContainer.ToScreenSpace(cursorContainer.ActiveCursor.DrawPosition));
示例#22
0
 private void pressAndCheckTime(Key key, double expectedTime)
 {
     AddStep($"press {key}", () => InputManager.Key(key));
     AddUntilStep($"time is {expectedTime}", () => Precision.AlmostEquals(expectedTime, EditorClock.CurrentTime, 1));
 }
示例#23
0
        public override HitObject Parse(string text)
        {
            try
            {
                string[] split = text.Split(',');

                Vector2 pos = new Vector2((int)Convert.ToSingle(split[0], CultureInfo.InvariantCulture), (int)Convert.ToSingle(split[1], CultureInfo.InvariantCulture));

                ConvertHitObjectType type = (ConvertHitObjectType)int.Parse(split[3]);

                int comboOffset = (int)(type & ConvertHitObjectType.ComboOffset) >> 4;
                type &= ~ConvertHitObjectType.ComboOffset;

                bool combo = type.HasFlag(ConvertHitObjectType.NewCombo);
                type &= ~ConvertHitObjectType.NewCombo;

                var soundType = (LegacySoundType)int.Parse(split[4]);
                var bankInfo  = new SampleBankInfo();

                HitObject result = null;

                if (type.HasFlag(ConvertHitObjectType.Circle))
                {
                    result = CreateHit(pos, combo, comboOffset);

                    if (split.Length > 5)
                    {
                        readCustomSampleBanks(split[5], bankInfo);
                    }
                }
                else if (type.HasFlag(ConvertHitObjectType.Slider))
                {
                    PathType pathType = PathType.Catmull;
                    double   length   = 0;

                    string[] pointSplit = split[5].Split('|');

                    int pointCount = 1;
                    foreach (var t in pointSplit)
                    {
                        if (t.Length > 1)
                        {
                            pointCount++;
                        }
                    }

                    var points = new Vector2[pointCount];

                    int pointIndex = 1;
                    foreach (string t in pointSplit)
                    {
                        if (t.Length == 1)
                        {
                            switch (t)
                            {
                            case @"C":
                                pathType = PathType.Catmull;
                                break;

                            case @"B":
                                pathType = PathType.Bezier;
                                break;

                            case @"L":
                                pathType = PathType.Linear;
                                break;

                            case @"P":
                                pathType = PathType.PerfectCurve;
                                break;
                            }

                            continue;
                        }

                        string[] temp = t.Split(':');
                        points[pointIndex++] = new Vector2((int)Convert.ToDouble(temp[0], CultureInfo.InvariantCulture), (int)Convert.ToDouble(temp[1], CultureInfo.InvariantCulture)) - pos;
                    }

                    // osu-stable special-cased colinear perfect curves to a CurveType.Linear
                    bool isLinear(Vector2[] p) => Precision.AlmostEquals(0, (p[1].Y - p[0].Y) * (p[2].X - p[0].X) - (p[1].X - p[0].X) * (p[2].Y - p[0].Y));

                    if (points.Length == 3 && pathType == PathType.PerfectCurve && isLinear(points))
                    {
                        pathType = PathType.Linear;
                    }

                    int repeatCount = Convert.ToInt32(split[6], CultureInfo.InvariantCulture);

                    if (repeatCount > 9000)
                    {
                        throw new ArgumentOutOfRangeException(nameof(repeatCount), @"Repeat count is way too high");
                    }

                    // osu-stable treated the first span of the slider as a repeat, but no repeats are happening
                    repeatCount = Math.Max(0, repeatCount - 1);

                    if (split.Length > 7)
                    {
                        length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
                    }

                    if (split.Length > 10)
                    {
                        readCustomSampleBanks(split[10], bankInfo);
                    }

                    // One node for each repeat + the start and end nodes
                    int nodes = repeatCount + 2;

                    // Populate node sample bank infos with the default hit object sample bank
                    var nodeBankInfos = new List <SampleBankInfo>();
                    for (int i = 0; i < nodes; i++)
                    {
                        nodeBankInfos.Add(bankInfo.Clone());
                    }

                    // Read any per-node sample banks
                    if (split.Length > 9 && split[9].Length > 0)
                    {
                        string[] sets = split[9].Split('|');
                        for (int i = 0; i < nodes; i++)
                        {
                            if (i >= sets.Length)
                            {
                                break;
                            }

                            SampleBankInfo info = nodeBankInfos[i];
                            readCustomSampleBanks(sets[i], info);
                        }
                    }

                    // Populate node sound types with the default hit object sound type
                    var nodeSoundTypes = new List <LegacySoundType>();
                    for (int i = 0; i < nodes; i++)
                    {
                        nodeSoundTypes.Add(soundType);
                    }

                    // Read any per-node sound types
                    if (split.Length > 8 && split[8].Length > 0)
                    {
                        string[] adds = split[8].Split('|');
                        for (int i = 0; i < nodes; i++)
                        {
                            if (i >= adds.Length)
                            {
                                break;
                            }

                            int sound;
                            int.TryParse(adds[i], out sound);
                            nodeSoundTypes[i] = (LegacySoundType)sound;
                        }
                    }

                    // Generate the final per-node samples
                    var nodeSamples = new List <List <SampleInfo> >(nodes);
                    for (int i = 0; i < nodes; i++)
                    {
                        nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
                    }

                    result = CreateSlider(pos, combo, comboOffset, points, length, pathType, repeatCount, nodeSamples);

                    // The samples are played when the slider ends, which is the last node
                    result.Samples = nodeSamples[nodeSamples.Count - 1];
                }
                else if (type.HasFlag(ConvertHitObjectType.Spinner))
                {
                    result = CreateSpinner(new Vector2(512, 384) / 2, combo, comboOffset, Convert.ToDouble(split[5], CultureInfo.InvariantCulture) + Offset);

                    if (split.Length > 6)
                    {
                        readCustomSampleBanks(split[6], bankInfo);
                    }
                }
                else if (type.HasFlag(ConvertHitObjectType.Hold))
                {
                    // Note: Hold is generated by BMS converts

                    double endTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture);

                    if (split.Length > 5 && !string.IsNullOrEmpty(split[5]))
                    {
                        string[] ss = split[5].Split(':');
                        endTime = Convert.ToDouble(ss[0], CultureInfo.InvariantCulture);
                        readCustomSampleBanks(string.Join(":", ss.Skip(1)), bankInfo);
                    }

                    result = CreateHold(pos, combo, comboOffset, endTime + Offset);
                }

                if (result == null)
                {
                    Logger.Log($"Unknown hit object type: {type}. Skipped.", level: LogLevel.Error);
                    return(null);
                }

                result.StartTime = Convert.ToDouble(split[2], CultureInfo.InvariantCulture) + Offset;

                if (result.Samples.Count == 0)
                {
                    result.Samples = convertSoundType(soundType, bankInfo);
                }

                FirstObject = false;

                return(result);
            }
            catch (FormatException)
            {
                throw new FormatException("One or more hit objects were malformed.");
            }
        }
示例#24
0
 private void check(float ratio) =>
 AddAssert($"Check @{ratio}", () => Precision.AlmostEquals(autoSizeContainer.Size, new Vector2(changed_value * ratio)) &&
           Precision.AlmostEquals(box2.Position, new Vector2(changed_value * (1 - ratio), changed_value * ratio)));
示例#25
0
        private void addSeekStep(double time)
        {
            AddStep($"seek to {time}", () => track.Seek(time));

            AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, ((TestPlayer)Player).DrawableRuleset.FrameStableClock.CurrentTime, 100));
        }
示例#26
0
 private static bool almostEquals(double value1, double value2)
 {
     return(Precision.AlmostEquals(value1, value2, timing_precision));
 }
示例#27
0
 public void TestSliderMultiplier(float multiplier, float expectedSpacing)
 {
     AddStep($"set speed multiplier = {multiplier}", () => editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = multiplier);
     createGrid();
     AddAssert($"spacing = {expectedSpacing}", () => Precision.AlmostEquals(expectedSpacing, grid.DistanceSpacing));
 }
示例#28
0
 private void assertMenuInCentre(Func <Drawable> getBoxFunc)
 => AddAssert("menu in centre of box", () => Precision.AlmostEquals(contextMenuContainer.CurrentMenu.ScreenSpaceDrawQuad.TopLeft, getBoxFunc().ScreenSpaceDrawQuad.Centre));
 private void assertPosition(int index, float relativeY) => AddAssert($"hitobject {index} at {relativeY}",
                                                                      () => Precision.AlmostEquals(drawableRuleset.Playfield.AllHitObjects.ElementAt(index).DrawPosition.Y, drawableRuleset.Playfield.HitObjectContainer.DrawHeight * relativeY));
示例#30
0
        /// <summary>
        /// Creates a piecewise-linear approximation of a circular arc curve.
        /// </summary>
        /// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
        public static List <Vector2> ApproximateCircularArc(List <Vector2> controlPoints)
        {
            Vector2 a = controlPoints[0];
            Vector2 b = controlPoints[1];
            Vector2 c = controlPoints[2];

            double aSq = (b - c).LengthSquared;
            double bSq = (a - c).LengthSquared;
            double cSq = (a - b).LengthSquared;

            // If we have a degenerate triangle where a side-length is almost zero, then give up and fall
            // back to a more numerically stable method.
            if (Precision.AlmostEquals(aSq, 0) || Precision.AlmostEquals(bSq, 0) || Precision.AlmostEquals(cSq, 0))
            {
                return(new List <Vector2>());
            }

            double s = aSq * (bSq + cSq - aSq);
            double t = bSq * (aSq + cSq - bSq);
            double u = cSq * (aSq + bSq - cSq);

            double sum = s + t + u;

            // If we have a degenerate triangle with an almost-zero size, then give up and fall
            // back to a more numerically stable method.
            if (Precision.AlmostEquals(sum, 0))
            {
                return(new List <Vector2>());
            }

            Vector2 centre = (s * a + t * b + u * c) / sum;
            Vector2 dA     = a - centre;
            Vector2 dC     = c - centre;

            double r = dA.Length;

            double thetaStart = Math.Atan2(dA.Y, dA.X);
            double thetaEnd   = Math.Atan2(dC.Y, dC.X);

            while (thetaEnd < thetaStart)
            {
                thetaEnd += 2 * Math.PI;
            }

            double dir        = 1;
            double thetaRange = thetaEnd - thetaStart;

            // Decide in which direction to draw the circle, depending on which side of
            // AC B lies.
            Vector2 orthoAtoC = c - a;

            orthoAtoC = new Vector2(orthoAtoC.Y, -orthoAtoC.X);
            if (Vector2.Dot(orthoAtoC, b - a) < 0)
            {
                dir        = -dir;
                thetaRange = 2 * Math.PI - thetaRange;
            }

            // We select the amount of points for the approximation by requiring the discrete curvature
            // to be smaller than the provided tolerance. The exact angle required to meet the tolerance
            // is: 2 * Math.Acos(1 - TOLERANCE / r)
            // The special case is required for extremely short sliders where the radius is smaller than
            // the tolerance. This is a pathological rather than a realistic case.
            int amountPoints = 2 * r <= circular_arc_tolerance ? 2 : Math.Max(2, (int)Math.Ceiling(thetaRange / (2 * Math.Acos(1 - circular_arc_tolerance / r))));

            List <Vector2> output = new List <Vector2>(amountPoints);

            for (int i = 0; i < amountPoints; ++i)
            {
                double  fract = (double)i / (amountPoints - 1);
                double  theta = thetaStart + dir * fract * thetaRange;
                Vector2 o     = new Vector2(Math.Cos(theta), Math.Sin(theta)) * r;
                output.Add(centre + o);
            }

            return(output);
        }