Example #1
0
        private string Merge_Sliders(Arguments arg, BackgroundWorker worker)
        {
            var slidersMerged = 0;

            var editorRead = EditorReaderStuff.TryGetFullEditorReader(out var reader);

            foreach (var path in arg.Paths)
            {
                var editor = EditorReaderStuff.GetBeatmapEditor(path, reader, editorRead, out var selected, out var editorActuallyRead);

                if (arg.SelectionMode == 0 && !editorActuallyRead)
                {
                    return(EditorReaderStuff.SelectedObjectsReadFailText);
                }

                var beatmap       = editor.Beatmap;
                var markedObjects = arg.SelectionMode == 0 ? selected :
                                    arg.SelectionMode == 1 ? beatmap.GetBookmarkedObjects() :
                                    beatmap.HitObjects;

                var mergeLast = false;
                for (var i = 0; i < markedObjects.Count - 1; i++)
                {
                    var ho1 = markedObjects[i];
                    var ho2 = markedObjects[i + 1];
                    if (ho1.IsSlider && ho2.IsSlider && (ho1.CurvePoints.Last() - ho2.Pos).Length <= arg.Leniency)
                    {
                        var sp1 = BezierConverter.ConvertToBezier(ho1.SliderPath).ControlPoints;
                        var sp2 = BezierConverter.ConvertToBezier(ho2.SliderPath).ControlPoints;

                        double extraLength = 0;
                        switch (arg.ConnectionMode)
                        {
                        case ConnectionMode.Move:
                            Move(sp2, sp1.Last() - sp2.First());
                            break;

                        case ConnectionMode.Linear:
                            sp1.Add(sp1.Last());
                            sp1.Add(sp2.First());
                            extraLength = (ho1.CurvePoints.Last() - ho2.Pos).Length;
                            break;
                        }

                        var mergedAnchors = sp1.Concat(sp2).ToList();
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp1) && IsLinearBezier(sp2);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(),
                                                        ho1.PixelLength + ho2.PixelLength + extraLength);
                        ho1.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsSlider && ho2.IsCircle && (ho1.CurvePoints.Last() - ho2.Pos).Length <= arg.Leniency)
                    {
                        var sp1 = BezierConverter.ConvertToBezier(ho1.SliderPath).ControlPoints;

                        sp1.Add(sp1.Last());
                        sp1.Add(ho2.Pos);
                        var extraLength = (ho1.CurvePoints.Last() - ho2.Pos).Length;

                        var mergedAnchors = sp1;
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp1);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), ho1.PixelLength + extraLength);
                        ho1.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsCircle && ho2.IsSlider && (ho1.Pos - ho2.Pos).Length <= arg.Leniency)
                    {
                        var sp2 = BezierConverter.ConvertToBezier(ho2.SliderPath).ControlPoints;

                        sp2.Insert(0, sp2.First());
                        sp2.Insert(0, ho1.Pos);
                        var extraLength = (ho1.Pos - ho2.Pos).Length;

                        var mergedAnchors = sp2;
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp2);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), ho2.PixelLength + extraLength);
                        ho2.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho1);
                        markedObjects.Remove(ho1);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsCircle && ho2.IsCircle && (ho1.Pos - ho2.Pos).Length <= arg.Leniency)
                    {
                        var mergedAnchors = new List <Vector2> {
                            ho1.Pos, ho2.Pos
                        };

                        var mergedPath = new SliderPath(arg.LinearOnLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), (ho1.Pos - ho2.Pos).Length);
                        ho1.SliderPath    = mergedPath;
                        ho1.IsCircle      = false;
                        ho1.IsSlider      = true;
                        ho1.Repeat        = 1;
                        ho1.EdgeHitsounds = new List <int> {
                            ho1.GetHitsounds(), ho2.GetHitsounds()
                        };
                        ho1.EdgeSampleSets = new List <SampleSet> {
                            ho1.SampleSet, ho2.SampleSet
                        };
                        ho1.EdgeAdditionSets = new List <SampleSet> {
                            ho1.AdditionSet, ho2.AdditionSet
                        };

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else
                    {
                        mergeLast = false;
                    }

                    if (worker != null && worker.WorkerReportsProgress)
                    {
                        worker.ReportProgress(i / markedObjects.Count);
                    }
                }

                // Save the file
                editor.SaveFile();
            }

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            if (arg.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, editorRead));
            }

            // Make an accurate message
            var message = "";

            if (Math.Abs(slidersMerged) == 1)
            {
                message += "Successfully merged " + slidersMerged + " slider!";
            }
            else
            {
                message += "Successfully merged " + slidersMerged + " sliders!";
            }
            return(arg.Quick ? "" : message);
        }
Example #2
0
        public static List <Vector2> MoveAnchorsToLength(List <Vector2> anchors, PathType pathType, double newLength, out PathType newPathType)
        {
            var newAnchors    = new List <Vector2>();
            var sliderPath    = new SliderPath(pathType, anchors.ToArray(), newLength);
            var maxSliderPath = new SliderPath(pathType, anchors.ToArray());

            if (newLength > maxSliderPath.Distance)
            {
                // Extend linearly
                switch (pathType)
                {
                case PathType.Bezier:
                    newPathType = PathType.Bezier;
                    newAnchors.AddRange(anchors);
                    newAnchors.Add(anchors.Last());
                    newAnchors.Add(sliderPath.PositionAt(1));
                    break;

                case PathType.Catmull:
                case PathType.PerfectCurve:
                    // Convert to bezier and then extend
                    newPathType = PathType.Bezier;
                    newAnchors  = BezierConverter.ConvertToBezier(sliderPath).ControlPoints;
                    newAnchors.Add(anchors.Last());
                    newAnchors.Add(sliderPath.PositionAt(1));
                    break;

                default:
                    newPathType = pathType;
                    newAnchors.AddRange(anchors);
                    newAnchors[newAnchors.Count - 1] = sliderPath.PositionAt(1);
                    break;
                }
            }
            else
            {
                switch (sliderPath.Type)
                {
                case PathType.Catmull:
                case PathType.Bezier:
                    newPathType = PathType.Bezier;

                    // Convert in case the path type is catmull
                    var convert = BezierConverter.ConvertToBezier(sliderPath).ControlPoints;

                    // Find the last bezier segment and the pixel length at that part
                    BezierSubdivision subdivision = null;
                    double            totalLength = 0;

                    foreach (var bezierSubdivision in ChopAnchors(convert))
                    {
                        subdivision = bezierSubdivision;
                        var length = bezierSubdivision.SubdividedApproximationLength();

                        if (totalLength + length > newLength)
                        {
                            break;
                        }

                        totalLength += length;
                        newAnchors.AddRange(bezierSubdivision.Points);
                    }

                    if (subdivision == null)
                    {
                        break;
                    }

                    // Find T for the remaining pixel length
                    var t = subdivision.LengthToT(newLength - totalLength);

                    // ScaleRight the BezierSubdivision so the anchors end at T
                    subdivision.ScaleRight(t);

                    // Add the scaled anchors
                    newAnchors.AddRange(subdivision.Points);
                    break;

                case PathType.PerfectCurve:
                    newPathType = PathType.PerfectCurve;
                    newAnchors.AddRange(anchors);
                    newAnchors[1] = sliderPath.PositionAt(0.5);
                    newAnchors[2] = sliderPath.PositionAt(1);
                    break;

                default:
                    newPathType = pathType;
                    if (anchors.Count > 2)
                    {
                        // Find the section of the linear slider which contains the slider end
                        totalLength = 0;
                        foreach (var bezierSubdivision in ChopAnchorsLinear(anchors))
                        {
                            newAnchors.Add(bezierSubdivision.Points[0]);
                            var length = bezierSubdivision.Length();

                            if (totalLength + length > newLength)
                            {
                                break;
                            }

                            totalLength += length;
                        }
                        newAnchors.Add(sliderPath.PositionAt(1));
                    }
                    else
                    {
                        newAnchors.AddRange(anchors);
                        newAnchors[newAnchors.Count - 1] = sliderPath.PositionAt(1);
                    }
                    break;
                }
            }

            return(newAnchors);
        }
        private string Merge_Sliders(SliderMergerVm arg, BackgroundWorker worker)
        {
            var slidersMerged = 0;

            var reader = EditorReaderStuff.GetFullEditorReaderOrNot(out var editorReaderException1);

            if (arg.ImportModeSetting == 0 && editorReaderException1 != null)
            {
                throw new Exception("Could not fetch selected hit objects.", editorReaderException1);
            }

            foreach (var path in arg.Paths)
            {
                var editor = EditorReaderStuff.GetNewestVersionOrNot(path, reader, out var selected, out var editorReaderException2);

                if (arg.ImportModeSetting == SliderMergerVm.ImportMode.Selected && editorReaderException2 != null)
                {
                    throw new Exception("Could not fetch selected hit objects.", editorReaderException2);
                }

                var beatmap       = editor.Beatmap;
                var markedObjects = arg.ImportModeSetting == 0 ? selected :
                                    arg.ImportModeSetting == SliderMergerVm.ImportMode.Bookmarked ? beatmap.GetBookmarkedObjects() :
                                    arg.ImportModeSetting == SliderMergerVm.ImportMode.Time ? beatmap.QueryTimeCode(arg.TimeCode).ToList() :
                                    beatmap.HitObjects;

                var mergeLast = false;
                for (var i = 0; i < markedObjects.Count - 1; i++)
                {
                    if (worker != null && worker.WorkerReportsProgress)
                    {
                        worker.ReportProgress(i / markedObjects.Count);
                    }

                    var ho1 = markedObjects[i];
                    var ho2 = markedObjects[i + 1];

                    var lastPos1 = ho1.IsSlider
                        ? arg.MergeOnSliderEnd ? ho1.GetSliderPath().PositionAt(1) : ho1.CurvePoints.Last()
                        : ho1.Pos;

                    double dist = Vector2.Distance(lastPos1, ho2.Pos);

                    if (dist > arg.Leniency)
                    {
                        mergeLast = false;
                        continue;
                    }

                    if (ho1.IsSlider && ho2.IsSlider)
                    {
                        if (arg.MergeOnSliderEnd)
                        {
                            // In order to merge on the slider end we first move the anchors such that the last anchor is exactly on the slider end
                            // After that merge as usual
                            ho1.SetAllCurvePoints(SliderPathUtil.MoveAnchorsToLength(
                                                      ho1.GetAllCurvePoints(), ho1.SliderType, ho1.PixelLength, out var pathType));
                            ho1.SliderType = pathType;
                        }

                        var sp1 = BezierConverter.ConvertToBezier(ho1.SliderPath).ControlPoints;
                        var sp2 = BezierConverter.ConvertToBezier(ho2.SliderPath).ControlPoints;

                        double extraLength = 0;
                        switch (arg.ConnectionModeSetting)
                        {
                        case SliderMergerVm.ConnectionMode.Move:
                            Move(sp2, sp1.Last() - sp2.First());
                            break;

                        case SliderMergerVm.ConnectionMode.Linear:
                            sp1.Add(sp1.Last());
                            sp1.Add(sp2.First());
                            extraLength = (ho1.CurvePoints.Last() - ho2.Pos).Length;
                            break;
                        }

                        var mergedAnchors = sp1.Concat(sp2).ToList();
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp1) && IsLinearBezier(sp2);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(),
                                                        ho1.PixelLength + ho2.PixelLength + extraLength);
                        ho1.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsSlider && ho2.IsCircle)
                    {
                        var sp1 = BezierConverter.ConvertToBezier(ho1.SliderPath).ControlPoints;

                        sp1.Add(sp1.Last());
                        sp1.Add(ho2.Pos);
                        var extraLength = (ho1.CurvePoints.Last() - ho2.Pos).Length;

                        var mergedAnchors = sp1;
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp1);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), ho1.PixelLength + extraLength);
                        ho1.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsCircle && ho2.IsSlider)
                    {
                        var sp2 = BezierConverter.ConvertToBezier(ho2.SliderPath).ControlPoints;

                        sp2.Insert(0, sp2.First());
                        sp2.Insert(0, ho1.Pos);
                        var extraLength = (ho1.Pos - ho2.Pos).Length;

                        var mergedAnchors = sp2;
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp2);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), ho2.PixelLength + extraLength);
                        ho2.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho1);
                        markedObjects.Remove(ho1);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsCircle && ho2.IsCircle)
                    {
                        var mergedAnchors = new List <Vector2> {
                            ho1.Pos, ho2.Pos
                        };

                        var mergedPath = new SliderPath(arg.LinearOnLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), (ho1.Pos - ho2.Pos).Length);
                        ho1.SliderPath    = mergedPath;
                        ho1.IsCircle      = false;
                        ho1.IsSlider      = true;
                        ho1.Repeat        = 1;
                        ho1.EdgeHitsounds = new List <int> {
                            ho1.GetHitsounds(), ho2.GetHitsounds()
                        };
                        ho1.EdgeSampleSets = new List <SampleSet> {
                            ho1.SampleSet, ho2.SampleSet
                        };
                        ho1.EdgeAdditionSets = new List <SampleSet> {
                            ho1.AdditionSet, ho2.AdditionSet
                        };

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else
                    {
                        mergeLast = false;
                    }
                }

                // Save the file
                editor.SaveFile();
            }

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            if (arg.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null));
            }

            // Make an accurate message
            var message = "";

            if (Math.Abs(slidersMerged) == 1)
            {
                message += "Successfully merged " + slidersMerged + " slider!";
            }
            else
            {
                message += "Successfully merged " + slidersMerged + " sliders!";
            }
            return(arg.Quick ? "" : message);
        }