private static bool Iteration(RenderSequenceModel rsm, Stopwatch stopwatch, bool countShots, out int shots)
        {
            shots = 0;
            var shotsParallel = new int[0];

            if (countShots)
            {
                shotsParallel = new int[rsm.Cores];
            }

            #region render parallel

            var cx = rsm.CenterPoint.X;
            var cy = rsm.CenterPoint.Y;

            IsRendering = true;

            try
            {
                _sourceParallel?.Token.ThrowIfCancellationRequested();
            }
            catch (OperationCanceledException)
            {
                EndRender(rsm.Display, rsm.TotalIterations, stopwatch.Elapsed, rsm.RenderActionsPack,
                          $"render interrupted (RenderValidity) {rsm.RenderId}", rsm.DraftMode, rsm.RenderId);
                return(false);
            }

            lock (LockObj)
            {
                _sourceParallel = new CancellationTokenSource();
            }

            var parallelOptions = new ParallelOptions
            {
                CancellationToken = _sourceParallel.Token, MaxDegreeOfParallelism = rsm.Cores
            };

            try
            {
                Parallel.For(0, rsm.Cores, parallelOptions, core =>
                {
                    var iterator = rsm.Iterators[core];

                    iterator.Iterate(rsm.TotalPointsPerCore);

                    try
                    {
                        for (var i = 0; i < rsm.TotalPointsPerCore; i++)
                        {
                            var p  = i * 2;
                            var pX = iterator.Points[p];
                            var pY = iterator.Points[p + 1];

                            var colorId = iterator.ColorIds[i];

                            for (var s = 0; s < rsm.Symmetry; s++)
                            {
                                Trigonometry.TranslatePoint(pX, pY, rsm.TranslationArray, cx, cy, out var tpX,
                                                            out var tpY);
                                if (Trigonometry.InRange(tpX, tpY, rsm.ImageSize))
                                {
                                    rsm.Display.Shot((uint)tpX, (uint)tpY, colorId);
                                    if (countShots)
                                    {
                                        shotsParallel[core]++;
                                    }
                                }

                                if (s < rsm.Symmetry - 1)
                                {
                                    Trigonometry.RotatePoint(ref pX, ref pY, rsm.SectorCos, rsm.SectorSin);
                                }
                            }

                            parallelOptions.CancellationToken.ThrowIfCancellationRequested();
                        }
        private static RenderSequenceModel PrepareRsm(RenderPackModel renderPack, RenderActionsModel renderActionsPack,
                                                      int renderId, bool draftMode = true, bool continueRender = false)
        {
            var cores    = Environment.ProcessorCount;
            var symmetry = renderPack.ViewSettings.Symmetry;
            var totalPointsPerIteration = renderPack.RenderSettings.ShotsPerIteration;
            var imageSize         = new Size(renderPack.ViewSettings.ImageWidth, renderPack.ViewSettings.ImageHeight);
            var renderColorMode   = renderPack.RenderSettings.RenderColorMode;
            var translationMatrix = Matrix.FromViewSettings(renderPack.ViewSettings);
            var colorCount        = renderPack.Transformations.Length;
            var iterators         = new IteratorModel[cores];

            for (var i = 0; i < cores; i++)
            {
                iterators[i] = new IteratorModel(renderPack);
            }
            var sector = Math.PI * 2.0 / symmetry;

            LogDisplayModel display;

            if (continueRender && HasRender)
            {
                display = Display;
            }
            else
            {
                display = new LogDisplayModel((int)imageSize.Width, (int)imageSize.Height,
                                              renderPack.Transformations.Length, renderPack.ViewSettings.BackColor);
            }
            display.RenderColorMode = renderColorMode;


            _transformationColors         = new Color[colorCount];
            _transformationGradientValues = new double[colorCount];
            for (var i = 0; i < colorCount; i++)
            {
                _transformationColors[i] = renderPack.Transformations[i].Color;
            }
            for (var i = 0; i < colorCount; i++)
            {
                _transformationGradientValues[i] = renderPack.Transformations[i].ColorPosition;
            }

            _gradModel = renderPack.GradModelCopy;

            var rsm = new RenderSequenceModel
            {
                TotalIterations       = renderPack.RenderSettings.Iterations,
                Cores                 = cores,
                Iterators             = iterators,
                TotalPointsPerCore    = totalPointsPerIteration / cores / symmetry,
                Symmetry              = symmetry,
                TranslationArray      = translationMatrix.Array,
                CenterPoint           = new Point(renderPack.ViewSettings.HalfWidth, renderPack.ViewSettings.HalfHeight),
                ImageSize             = imageSize,
                Display               = display,
                RenderActionsPack     = renderActionsPack,
                RenderId              = renderId,
                DraftMode             = draftMode,
                RenderPack            = renderPack,
                IsDrawingIntermediate = false,
                SectorCos             = Math.Cos(sector),
                SectorSin             = Math.Sin(sector)
            };

            return(rsm);
        }