private double calcCircleSegmentLength(Point2 from, Point2 to, Point2 mid)
        {
            Circle circle = new Circle(from, to, mid);

            Point2 center = circle.center;
            double radius = circle.radius;

            double angle1 = PatternGenerator.calcAngle(from, center);
            double angle2 = PatternGenerator.calcAngle(to, center);

            return(Math.Abs(angle2 - angle1) * radius);
        }
        private Point2 binarySeachPoint(Point2 from, double angle, int distToNextPoint, double shift_delta)
        {
            double high = distToNextPoint;
            double low  = 0;

            double eps = 1e-3;

            Point2 to = null;

            while (high - low > eps)
            {
                double current = (low + high) / 2;

                to = new Point2(from.X + (float)(current * Math.Cos(angle)), from.Y + (float)(current * Math.Sin(angle)));
                var mid = new Point2((to.X + from.X) / 2, (to.Y + from.Y) / 2);
                mid.X += (float)(shift_delta * Math.Sin(angle));
                mid.Y += (float)(shift_delta * Math.Cos(angle));
                if (!PatternGenerator.checkCoordinateLimits(mid))
                {
                    mid.X -= 2 * (float)(shift_delta * Math.Sin(angle));
                    mid.Y -= 2 * (float)(shift_delta * Math.Cos(angle));
                }

                double spacing = calcCircleSegmentLength(from, to, mid);

                if (spacing < distToNextPoint)
                {
                    low = current;
                }
                else
                {
                    high = current;
                }
            }

            return(to);
        }
예제 #3
0
        public List <CircleObject> generatePolygons(MapContextAwareness mapContext, int points, int number, int spacing, int rotation, int shift, bool randomize)
        {
            var result = new List <CircleObject>();

            double angle = 0;
            int    X     = mapContext.X;
            int    Y     = mapContext.Y;

            int shiftx = shift;
            int shifty = shift;

            for (int i = 0; i < number && mapContext.Offset < mapContext.endOffset; ++i)
            {
                Point2 pp = checkPolygonialBounds(X, Y, spacing);

                if (!ReferenceEquals(pp, null))
                {
                    X = (int)pp.X;
                    Y = (int)pp.Y;
                }

                var ps = PatternGenerator.polygon(points, new Point2(X, Y), spacing, angle);

                if (randomize)
                {
                    //ps = PatternGenerator.shuffleOrder(ps);
                    ps = reoderIntoStar(ps);
                }

                foreach (var p in ps)
                {
                    p.Type = BMAPI.v1.HitObjectType.Circle;
                }
                ps[0].Type |= BMAPI.v1.HitObjectType.NewCombo;

                foreach (var obj in ps)
                {
                    obj.StartTime      = (int)mapContext.Offset;
                    mapContext.Offset += mapContext.bpm;
                }

                result.AddRange(ps);
                angle += PatternGenerator.ConvertToRadians(rotation);
                if (!PatternGenerator.checkCoordinateLimits(X, Y, points, spacing, shiftx, shifty))
                {
                    //TODO: add normalization
                    Point2 next = PatternGenerator.findNextPosition(X, Y, shift);
                    shiftx = (int)(next.X - X);
                    shifty = (int)(next.Y - Y);
                }
                X += shiftx;
                Y += shifty;
            }

            double nextShift    = Math.Sqrt(2 * spacing * spacing * (1.0 - Math.Cos(Math.PI * 2 / points)));
            Point2 nextPosition = PatternGenerator.findNextPosition(X, Y, nextShift);

            mapContext.X = (int)nextPosition.X;
            mapContext.Y = (int)nextPosition.Y;

            return(result);
        }
        public List <CircleObject> generateHorizontalPattern(MapContextAwareness mapContext)
        {
            if (end)
            {
                number = (int)1e6;
            }

            var result = new List <CircleObject>();

            double angle = rotation;
            int    X     = mapContext.X;
            int    Y     = mapContext.Y;

            int shiftx = 0;
            int shifty = shift;

            for (int i = 0; i < number && mapContext.Offset < mapContext.endOffset; ++i)
            {
                Point2 pp = checkHorizontalJumpBounds(X, Y, spacing, angle);

                if (!ReferenceEquals(pp, null))
                {
                    X = (int)pp.X;
                    Y = (int)pp.Y;
                }

                var ps = PatternGenerator.generateHorizontalJump(new Point2(X, Y), spacing, angle, randomize);

                if (randomize)
                {
                    ps = PatternGenerator.shuffleOrder(ps);
                }

                foreach (var p in ps)
                {
                    p.Type = BMAPI.v1.HitObjectType.Circle;
                }

                ps[0].Type |= BMAPI.v1.HitObjectType.NewCombo;

                foreach (var obj in ps)
                {
                    obj.StartTime      = (int)mapContext.Offset;
                    mapContext.Offset += mapContext.bpm;
                }

                result.AddRange(ps);
                if (checkNextJumpBounds(X + shiftx, Y + shifty, angle))
                {
                    shifty = -shifty;
                }
                X += shiftx;
                Y += shifty;
            }

            double nextShift    = shift;
            Point2 nextPosition = PatternGenerator.findNextPosition(X, Y, nextShift);

            mapContext.X = (int)nextPosition.X;
            mapContext.Y = (int)nextPosition.Y;

            return(result);
        }
 private bool checkNextJumpBounds(int X, int Y, double angle)
 {
     return(!PatternGenerator.checkCoordinateLimits(X, Y) && !ReferenceEquals(checkVerticalJumpBounds(X, Y, spacing, angle), null));
 }
        private List <CircleObject> generateRotatingPattern(MapContextAwareness mapContext)
        {
            if (end)
            {
                number = (int)1e6;
            }

            var result = new List <CircleObject>();

            double angle = 0;
            int    X     = mapContext.X;
            int    Y     = mapContext.Y;

            int shiftx = shift;
            int shifty = shift;

            for (int i = 0; i < number && mapContext.Offset < mapContext.endOffset; ++i)
            {
                Point2 pp = checkVerticalJumpBounds(X, Y, spacing, angle);

                if (!ReferenceEquals(pp, null))
                {
                    X = (int)pp.X;
                    Y = (int)pp.Y;
                }

                var ps = PatternGenerator.generateRotationalJump(new Point2(X, Y), spacing, angle, randomize);

                if (randomize)
                {
                    ps = PatternGenerator.shuffleOrder(ps);
                }

                foreach (var p in ps)
                {
                    p.Type = BMAPI.v1.HitObjectType.Circle;
                }

                ps[0].Type |= BMAPI.v1.HitObjectType.NewCombo;

                foreach (var obj in ps)
                {
                    obj.StartTime      = (int)mapContext.Offset;
                    mapContext.Offset += mapContext.bpm;
                }

                result.AddRange(ps);
                angle += rotation;
                if (checkNextJumpBounds(X + shiftx, Y + shifty, angle))
                {
                    Point2 next = PatternGenerator.findNextPosition(X, Y, shift);
                    shiftx = (int)(next.X - X);
                    shifty = (int)(next.Y - Y);

                    double norm = Math.Sqrt(Utils.sqr(shiftx) + Utils.sqr(shifty));
                    double recommended_shift = Math.Sqrt(2 * Utils.sqr(shift));

                    shiftx = (int)(shiftx / norm * recommended_shift);
                    shifty = (int)(shifty / norm * recommended_shift);
                }
                X += shiftx;
                Y += shifty;
            }

            double nextShift    = shift;
            Point2 nextPosition = PatternGenerator.findNextPosition(X, Y, nextShift);

            mapContext.X = (int)nextPosition.X;
            mapContext.Y = (int)nextPosition.Y;

            return(result);
        }
        public List <CircleObject> generateStreams(MapContextAwareness mapContext, int points, int number, int spacing, int shift)
        {
            //spacing is the distance between two notes in the stream

            if (end)
            {
                //double endOffset = mapContext.endOffset;
                //double currOffset = mapContext.Offset;

                //int n = (int)Math.Floor((endOffset - currOffset) / mapContext.bpm * 2 / points) - 1;

                number = (int)1e6;
            }

            List <CircleObject> result = new List <CircleObject>();

            int shiftx = shift;
            int shifty = shift;

            double angle = 0;
            bool   flag  = false;

            int distToNextPoint = spacing * (points - 1);

            for (int i = 0; i < number && mapContext.Offset < mapContext.endOffset; ++i)
            {
                Point2 from      = new Point2(mapContext.X, mapContext.Y);
                double tmp_angle = angle;
                Point2 to        = new Point2(from.X + distToNextPoint * (float)Math.Cos(angle), from.Y + distToNextPoint * (float)Math.Sin(angle));
                if (!PatternGenerator.checkCoordinateLimits(to))
                {
                    flag = true;
                }

                int tmp_spacing = distToNextPoint;
                for (int k = 0; flag; ++k)
                {
                    tmp_angle = Utils.rng.NextDouble() * Math.PI * 2;
                    while (Math.Abs(Math.Tan(angle) - Math.Tan(tmp_angle)) < 0.05)
                    {
                        tmp_angle = Utils.rng.NextDouble() * Math.PI * 2;
                    }

                    to = new Point2(from.X + tmp_spacing * (float)Math.Cos(tmp_angle), from.Y + tmp_spacing * (float)Math.Sin(tmp_angle));

                    if (PatternGenerator.checkCoordinateLimits(to))
                    {
                        flag = false;
                    }
                    else
                    {
                        if (k > 1000)
                        {
                            to          = pointToCenter(from, tmp_spacing);
                            tmp_spacing = (int)(tmp_spacing * 0.9);
                            k           = 0;
                        }
                    }
                }

                double mid_delta = generateMidDelta();

                List <CircleObject> pattern = null;

                if (mid_delta > 0.1)
                {
                    double shift_delta = mid_delta * distToNextPoint;
                    to = binarySeachPoint(from, tmp_angle, distToNextPoint, shift_delta);

                    var mid = new Point2((to.X + from.X) / 2, (to.Y + from.Y) / 2);
                    mid.X += (float)(shift_delta * Math.Sin(tmp_angle));
                    mid.Y += (float)(shift_delta * Math.Cos(tmp_angle));
                    if (!PatternGenerator.checkCoordinateLimits(mid))
                    {
                        mid.X -= 2 * (float)(shift_delta * Math.Sin(tmp_angle));
                        mid.Y -= 2 * (float)(shift_delta * Math.Cos(tmp_angle));
                    }
                    pattern = PatternGenerator.stream(points, from, to, mid);
                }
                else
                {
                    pattern = PatternGenerator.stream(points, from, to);
                }
                pattern[0].Type |= BMAPI.v1.HitObjectType.NewCombo;
                foreach (var obj in pattern)
                {
                    obj.StartTime      = (int)mapContext.Offset;
                    mapContext.Offset += mapContext.bpm / 2;
                }

                result.AddRange(pattern);

                double spacing_shift     = spacing;
                double recommended_shift = Math.Max(spacing_shift, shift);

                if (!PatternGenerator.checkCoordinateLimits(to.X + shiftx, to.Y + shifty))
                {
                    Point2 next = PatternGenerator.findNextPosition(mapContext.X, mapContext.Y, recommended_shift);
                    shiftx = (int)(next.X - mapContext.X);
                    shifty = (int)(next.Y - mapContext.Y);

                    double norm = Math.Sqrt(Utils.sqr(shiftx) + Utils.sqr(shifty));

                    if (norm < 0.1)
                    {
                        norm = 1;
                    }

                    shiftx = (int)(shiftx / norm * recommended_shift);
                    shifty = (int)(shifty / norm * recommended_shift);
                }

                mapContext.X = (int)to.X + shiftx;
                mapContext.Y = (int)to.Y + shifty;

                angle = tmp_angle;
            }

            return(result);
        }
예제 #8
0
        public List <CircleObject> generateRandomJumps(MapContextAwareness mapContext, int numberOfNotes, int spacing)
        {
            var result = new List <CircleObject>();

            int c = 0;

            for (int i = 0; i < numberOfNotes && mapContext.Offset < mapContext.endOffset; ++i)
            {
                Point2 next;
                if (i > 0)
                {
                    next = PatternGenerator.findNextPosition(mapContext.X, mapContext.Y, spacing);
                }
                else
                {
                    next = PatternGenerator.findNextPosition(mapContext.X, mapContext.Y, 0);
                }

                int stackNumber;

                if (useOnly)
                {
                    stackNumber = maxStack;
                }
                else
                {
                    stackNumber = Utils.rng.Next(1, maxStack + 1);
                }

                for (int j = 0; j < stackNumber; ++j)
                {
                    CircleObject note = new CircleObject();

                    if (j == 0)
                    {
                        note.Type |= BMAPI.v1.HitObjectType.NewCombo;
                    }

                    note.Location = next;
                    result.Add(note);

                    mapContext.X = (int)next.X;
                    mapContext.Y = (int)next.Y;

                    note.StartTime = (int)mapContext.Offset;

                    if (j < stackNumber - 1)
                    {
                        mapContext.Offset += mapContext.bpm / 2;
                    }
                }
                if (stackNumber % 2 == 0)
                {
                    ++c;
                }

                mapContext.Offset += mapContext.bpm;
            }

            if (c % 2 == 1)
            {
                mapContext.Offset += mapContext.bpm / 2;
            }

            return(result);
        }
예제 #9
0
        private void extractMapContextFromWindow(InitialSettingsWindow window)
        {
            TimingPoint current = baseBeatmap.TimingPoints[0];
            //double generator_bpm = current.BpmDelay / 2;

            string tickDivisor = window.tickDivisorComboBox.Text;

            double bpm_multiplier;

            switch (tickDivisor)
            {
            case "1/1": bpm_multiplier = 2; break;

            case "1/2": bpm_multiplier = 1; break;

            case "1/3": bpm_multiplier = 2.0 / 3; break;

            case "1/4": bpm_multiplier = 0.5; break;

            default: throw new Exception("Unknown tick divisor");
            }

            double generator_beginOffset;

            if (window.firstTimingCheckbox.IsChecked.Value)
            {
                generator_beginOffset = current.Time;
            }
            else
            {
                double tmp;
                if (double.TryParse(window.beginOffsetTextbox.Text, out tmp))
                {
                    generator_beginOffset = tmp;
                }
                else
                {
                    MessageBox.Show("Unable to parse the begin offset. Please input a valid number or check the First timing point checkbox");
                    return;
                }
            }

            double generator_endOffset;

            if (window.lastObjectCheckbox.IsChecked.Value)
            {
                generator_endOffset = findLastObjectTimingInMap(baseBeatmap);
            }
            else
            {
                double tmp;
                if (double.TryParse(window.endOffsetTextbox.Text, out tmp))
                {
                    generator_endOffset = tmp;
                }
                else
                {
                    MessageBox.Show("Unable to parse the begin offset. Please input a valid number or check the Last object checkbox");
                    return;
                }
            }

            int generator_X;
            int generator_Y;

            if (window.overrideStartPointCheckBox.IsChecked ?? true)
            {
                double tmp;
                if (double.TryParse(window.XtextBox.Text, out tmp))
                {
                    generator_X = (int)tmp;
                }
                else
                {
                    MessageBox.Show("Unable to parse the X coordinate. Please input a valid number or uncheck the override starting position checkbox");
                    return;
                }

                if (double.TryParse(window.YtextBox.Text, out tmp))
                {
                    generator_Y = (int)tmp;
                }
                else
                {
                    MessageBox.Show("Unable to parse the Y coordinate. Please input a valid number or uncheck the override starting position checkbox");
                    return;
                }
            }
            else
            {
                generator_X = 200;
                generator_Y = 200;
            }

            generator.mapContext = new MapContextAwareness(bpm_multiplier, generator_beginOffset, generator_endOffset, generator_X, generator_Y, baseBeatmap.TimingPoints);

            if (window.keepOriginalPartCheckbox.IsChecked.Value)
            {
                PatternGenerator.copyMap(baseBeatmap, generator.generatedMap, generator.mapContext.Offset, generator.mapContext.endOffset);
            }
        }