private IEnumerable <GroupAction> Curve(int duration, double radius, double degrees, int delay = 0, double priority = 0, int[] positions = null)
        {
            double eps = 0.000001;

            return(new List <GroupAction>
            {
                GroupActions.Rotate(degrees / 2, duration: duration, delay: delay, priority: priority - eps, positions: positions),
                GroupActions.MoveForward(duration, stepsize: radius * PositionHelper.ToRadians(Math.Abs(degrees) / duration), delay: delay, priority: priority, positions: positions),
                GroupActions.Rotate(degrees / 2, duration: duration, delay: delay, priority: priority + eps, positions: positions)
            });
        }
 public Element MoveForward(string name, Formation formation, int duration)
 {
     return(new Element
     {
         Name = name,
         StartFormation = formation,
         GroupActions = new GroupAction[]
         {
             GroupActions.MoveForward(duration, stepsize: StepSize)
         }
     });
 }
        public Element Schwenkung(string name, RowsFormation formation, bool toRight = false, int duration = 8, double slowStep = 0.4)
        {
            List <GroupAction> groupActions           = new List <GroupAction>();
            double             degree                 = toRight ? -90.0 : 90.0;
            int    endOfLastRowTurn                   = (duration / 2) * (formation.Rows + 1);
            double posFrontRowWhenLastTurnEnds        = slowStep * (endOfLastRowTurn - duration);
            double posSecondToLastRowWhenLastTurnEnds = posFrontRowWhenLastTurnEnds - (formation.Rows - 2) * formation.Depth;
            int    durationAll = endOfLastRowTurn + (int)(posSecondToLastRowWhenLastTurnEnds / (StepSize - slowStep)) - 1;

            int[] frontRow = formation.GetRow(0);
            for (int j = 0; j < formation.Columns; j++)
            {
                int   inwardIndex = toRight ? (formation.Columns - j - 1) : j;
                int[] p           = new int[1];
                p[0] = frontRow[inwardIndex];
                groupActions.AddRange(Curve(duration, (j + 1) * formation.SideMargin, degree, positions: p));
            }
            groupActions.Add(GroupActions.MoveForward(durationAll - duration, delay: duration, stepsize: slowStep, positions: frontRow));

            int[] rowBefore = frontRow;

            List <int> allExceptFirstRow = new List <int>(Combination.Range(0, formation.Size - 1));

            allExceptFirstRow.RemoveAll(x => frontRow.Contains(x));
            groupActions.Add(GroupActions.MoveForward(1, delay: duration / 2, stepsize: StepSize, positions: allExceptFirstRow.ToArray()));

            for (int i = 1; i < formation.Rows; i++)
            {
                int[] row = formation.GetRow(i);
                int   timeFinishedTurn = (i + 1) * (duration / 2) + duration / 2;
                groupActions.Add(GroupActions.FollowDirectFront(i, formation, timeFinishedTurn - 2, duration / 2, delay: 2, followers: row));
                groupActions.Add(GroupActions.MoveUpTo(rowBefore[0], durationAll - timeFinishedTurn, row, delay: timeFinishedTurn, stepsize: StepSize, depth: formation.Depth));
                rowBefore = row;
            }

            return(new Element
            {
                Name = name,
                StartFormation = formation,
                GroupActions = groupActions.ToArray(),
            });
        }
        public Element GrosseWende(string name, RowsFormation formation, int rotDuration = 16, double slowStep = 0.4)
        {
            var actions  = new List <GroupAction>();
            var firstRow = formation.GetRow(0);

            int    endOfLastRowTurn                   = rotDuration + (formation.Rows - 1) * (rotDuration / 4);
            double posFrontRowWhenLastTurnEnds        = slowStep * (endOfLastRowTurn - rotDuration);
            double posSecondToLastRowWhenLastTurnEnds = posFrontRowWhenLastTurnEnds - (formation.Rows - 2) * formation.Depth;
            int    durationAll = endOfLastRowTurn + (int)(posSecondToLastRowWhenLastTurnEnds / (StepSize - slowStep)) - 1;

            int[] frontRow = formation.GetRow(0);
            for (int j = 0; j < formation.Columns; j++)
            {
                int   fromCenter = j - (formation.Columns - 1) / 2;
                int[] p          = new int[1];
                p[0] = frontRow[j];
                actions.AddRange(Curve(rotDuration, Math.Abs(0.5 + 2 * fromCenter) * formation.SideMargin / 2, fromCenter >= 0 ? 180 : -180, positions: p));
            }
            actions.Add(GroupActions.MoveForward(durationAll - rotDuration, rotDuration, slowStep, positions: frontRow));

            int[] rowBefore = firstRow;
            for (int i = 1; i < formation.Rows; i++)
            {
                int[] row = formation.GetRow(i);
                int   timeFinishedTurn = i * (rotDuration / 4) + rotDuration;
                actions.Add(GroupActions.FollowDirectFront(i, formation, i * rotDuration / 4 + rotDuration, rotDuration / 4, followers: row));
                actions.Add(GroupActions.MoveUpTo(rowBefore[0], durationAll - timeFinishedTurn, row, delay: timeFinishedTurn, stepsize: StepSize, depth: formation.Depth));
                rowBefore = row;
            }

            return(new Element
            {
                Name = name,
                StartFormation = formation,
                GroupActions = actions.ToArray()
            });
        }