public override void RegenerateShapes()
        {
            Point             endpoint   = getPoint(ThetaMax, nGroup * (DominoLength + NormalDistance) / a);
            double            end_radius = Math.Sqrt(endpoint.X * endpoint.X + endpoint.Y * endpoint.Y);
            List <PathDomino> dominolist = new List <PathDomino>();
            double            pi2        = 1 / (2d * Math.PI); // spart ein paar Gleitkommadivisionen

            for (int i = 0; i < nGroup; i++)
            {
                double shift = i * (DominoLength + NormalDistance) / a;
                shift = shift - shiftfactor * nGroup * (DominoLength + NormalDistance) / a;
                double theta          = ThetaMin;
                int    ycounter       = 0;
                double current_radius = 0;
                while (closeEnds ? current_radius < end_radius : theta < ThetaMax)
                {
                    Point current_point = getPoint(theta, i * (DominoLength + NormalDistance) / a);
                    current_radius = Math.Sqrt(current_point.X * current_point.X + current_point.Y * current_point.Y);
                    for (int k = 0; k < nArms; k++)
                    {
                        PathDomino d = CreateDomino(theta, shift, 2.0 * Math.PI / nArms * k);
                        //d.position = new ProtocolDefinition();
                        //d.position.y = (int)Math.Floor((theta - theta_min) * pi2);
                        //d.position.x = ycounter;
                        dominolist.Add(d);
                    }
                    double start_value = theta;
                    double theta_new;
                    do
                    {
                        start_value += 0.01d;
                        theta_new    = approximate_archimedean(theta, start_value, TangentialDistance + DominoWidth, shift);
                    }while (theta_new < theta);
                    ycounter++;
                    if ((int)Math.Floor((theta - ThetaMin) * pi2) != (int)Math.Floor((theta_new - ThetaMin) * pi2))
                    {
                        ycounter = 0;
                    }
                    theta = theta_new;
                }
            }
            IDominoShape[]    dominoes   = dominolist.ToArray();
            DominoRectangle[] containers = dominoes.AsParallel().Select(x => x.GetContainer()).ToArray();

            double x_min = containers.Min(x => x.x);
            double y_min = containers.Min(x => x.y);
            double x_max = containers.Max(x => x.width + x.x);
            double y_max = containers.Max(x => x.height + x.y);

            Parallel.For(0, dominoes.Length, (i) =>
            {
                dominoes[i] = dominoes[i].TransformDomino(-x_min, -y_min, 0, 0, 0, 0);
            });
            last        = new DominoTransfer(dominoes, colors);
            shapesValid = true;
        }
        public override void RegenerateShapes()
        {
            PathDomino[][] dominos = new PathDomino[Circles][];
            Parallel.For(0, Circles, new ParallelOptions()
            {
                MaxDegreeOfParallelism = -1
            },
                         (circlecount) =>
            {
                int diameter             = StartDiameter + circlecount * (2 * DominoWidth + 2 * NormalDistance);
                double domino_angle      = Math.Asin((double)DominoLength / diameter) * 2;
                double distance_angle    = Math.Asin((double)TangentialDistance / diameter) * 2;
                int current_domino_count = (int)Math.Floor(2 * Math.PI / ((double)domino_angle + distance_angle));
                current_domino_count     = (int)Math.Floor((double)current_domino_count / _force_divisibilty) * _force_divisibilty;
                // equally space the distance between all dominoes
                distance_angle = (2 * Math.PI - (domino_angle * current_domino_count)) / current_domino_count;
                // calculate dominoes
                double angle         = (double)AngleShiftFactor * circlecount;
                dominos[circlecount] = new PathDomino[current_domino_count];
                for (int i = 0; i < current_domino_count; i++)
                {
                    PathDomino d = GenerateDomino(diameter, angle);
                    angle       += domino_angle + distance_angle;
                    d.position   = new ProtocolDefinition()
                    {
                        x = i, y = circlecount
                    };
                    dominos[circlecount][i] = d;
                }
            });
            IDominoShape[]    dominoes   = dominos.SelectMany(x => x).ToArray();
            DominoRectangle[] containers = dominoes.AsParallel().Select(x => x.GetContainer()).ToArray();

            double x_min = containers.Min(x => x.x);
            double y_min = containers.Min(x => x.y);
            double x_max = containers.Max(x => x.width + x.x);
            double y_max = containers.Max(x => x.height + x.y);

            Parallel.For(0, dominoes.Length, (i) =>
            {
                dominoes[i] = dominoes[i].TransformDomino(-x_min, -y_min, 0, 0, 0, 0);
            });
            last        = new DominoTransfer(dominoes, colors);
            shapesValid = true;
        }
 public override void RegenerateShapes()
 {
     Last        = new DominoTransfer(getNewShapes(Length, Height), colors);
     shapesValid = true;
 }
 public override void Calculate(DominoTransfer shapes, int charLength, CancellationToken ct)
 {
     LastValid = true;
 }
 public abstract void Calculate(DominoTransfer shapes, int charLength, CancellationToken ct);
        /// <summary>
        /// Weist jedem Shape die ideale Farbe zu, basierend auf den festgelegten Eigenschaften.
        /// </summary>
        /// <returns>ein Int-Array mit den Farbindizes</returns>
        internal override void CalculateColors()
        {
            var colors = this.colors.RepresentionForCalculation;

            //if (!shapesValid) throw new InvalidOperationException("Current shapes are invalid!");
            IterationInformation.weights = Enumerable.Repeat(1.0, colors.Length).ToArray();
            RTree <IDominoShape> tree = new RTree <IDominoShape>(9, new GuttmannQuadraticSplit <IDominoShape>());
            // wird nur beim Dithering benötigt und nur dann ausgeführt; sortiert alle Shapes nach deren Mittelpunktskoordinate
            // erst nach x, bei gleichem x nach y
            var list = shapes.dominoes.OrderByDescending(x =>
            {
                var container = x.GetContainer();
                return(container.y + container.height / 2);
            }).ThenBy(x =>
            {
                var container = x.GetContainer();
                return(container.x + container.width / 2);
            }).ToList();

            if (ditherMode.weights.GetLength(0) + ditherMode.weights.GetLength(1) > 2)
            {
                for (int i = 0; i < shapes.dominoes.Length; i++)
                {
                    tree.Insert(shapes.dominoes[i]);
                }
            }
            for (int iter = 0; iter < IterationInformation.maxNumberOfIterations; iter++)
            {
                if (ditherMode.weights.GetLength(0) + ditherMode.weights.GetLength(1) > 2)
                {
                    double extent_r = (ditherMode.matrix_width - ditherMode.start_first_row) * charLength;
                    double extent_l = (ditherMode.start_first_row - 1) * charLength;
                    double extent_u = (ditherMode.matrix_height - 1) * charLength;
                    // ditherColors im Baum ersetzen
                    for (int i = 0; i < list.Count; i++)
                    {
                        list[i].ditherColor = list[i].originalColor;
                    }
                    for (int i = 0; i < list.Count; i++)
                    {
                        var originalColor = list[i].ditherColor;
                        list[i].CalculateColor(colors, colorMode, TransparencySetting, IterationInformation.weights);
                        // Abweichung der beiden Farben bestimmen
                        int fehler_r = (int)(originalColor.Red - colors[list[i].color].mediaColor.R);
                        int fehler_g = (int)(originalColor.Green - colors[list[i].color].mediaColor.G);
                        int fehler_b = (int)(originalColor.Blue - colors[list[i].color].mediaColor.B);
                        // bestimme Abmessungen des Suchbereichs
                        DominoRectangle orig     = list[i].getBoundingRectangle();
                        double          orig_x   = orig.x + orig.width / 2;
                        double          orig_y   = orig.y + orig.height / 2;
                        DominoRectangle viewport = new DominoRectangle()
                        {
                            x      = orig_x - extent_l,
                            y      = orig_y - extent_u,
                            width  = extent_r + extent_l,
                            height = extent_u
                        };
                        var result  = tree.Search(viewport);
                        var weights = new double[result.Count];
                        // Rohgewichte aller gefundenen Shapes finden
                        for (int j = 0; j < result.Count; j++)
                        {
                            var bounding = result[j].getBoundingRectangle();
                            // alle rausschmeißen, die nicht komplett im Viewport liegen
                            double center_x = bounding.x + bounding.width / 2;
                            double center_y = bounding.y + bounding.height / 2;
                            // überprüfen, ob das Shape schon abgearbeitet wurde
                            if (center_y == orig_y && center_x <= orig_x)
                            {
                                continue;
                            }
                            if (center_y > orig_y)
                            {
                                continue;
                            }
                            weights[j] = ditherMode.Weight((center_x - orig_x) / charLength, (orig_y - center_y) / charLength);
                        }
                        var divisor = weights.Sum();
                        if (divisor == 0)
                        {
                        }
                        for (int j = 0; j < result.Count; j++)
                        {
                            if (weights[j] == 0)
                            {
                                continue;
                            }
                            ditherMode.AddToPixel(result[j],
                                                  (int)(fehler_r * weights[j] / divisor),
                                                  (int)(fehler_g * weights[j] / divisor),
                                                  (int)(fehler_b * weights[j] / divisor));
                        }
                    }
                }
                else
                {
                    ResetDitherColors(shapes.dominoes);
                    IterationInformation.numberofiterations = iter;
                    Console.WriteLine($"Iteration {iter}");
                    CancellationTokenSource cts = new CancellationTokenSource();
                    Parallel.For(0, shapes.dominoes.Length, new ParallelOptions()
                    {
                        MaxDegreeOfParallelism = -1, CancellationToken = cts.Token
                    }, (i) =>
                    {
                        try
                        {
                            shapes.dominoes[i].CalculateColor(colors, colorMode, TransparencySetting, IterationInformation.weights);
                        }
                        catch (Exception)
                        {
                            cts.Cancel();
                        }
                    });
                }
                // Farben zählen
                IterationInformation.EvaluateSolution(colors.ToArray(), shapes.dominoes);
                if (IterationInformation.colorRestrictionsFulfilled != false)
                {
                    break;
                }
            }
            last = new DominoTransfer(shapes.dominoes, this.colors);
        }