Пример #1
0
 public int FiniteIterationLimit()
 {
     return
         (_viewPort.Resolution.GetPositionsRowFirst().
          AsParallel().
          Select(p => ScalarDoubleKernel.FindEscapeTimeNoCycleDetection(_viewPort.GetComplex(p), MaxIterations).IsInfinite).
          Count());
 }
Пример #2
0
    public void ShouldRoundTripComplexNumbers()
    {
        var viewPort = new ViewPort(
            new ComplexArea(
                new DoubleRange(-1, 1),
                new DoubleRange(-1, 1)),
            new Size(101, 101));

        var point = new Point(-1, 1);

        var roundTripped = viewPort.GetPosition(viewPort.GetComplex(point));

        Assert.That(roundTripped, Is.EqualTo(point), "Returned wrong position.");
    }
Пример #3
0
    public void ShouldRoundTripPositions()
    {
        var viewPort = new ViewPort(
            new ComplexArea(
                new DoubleRange(-1, 1),
                new DoubleRange(-1, 1)),
            new Size(101, 101));

        var c = new Complex(-1, 1);

        var roundTripped = viewPort.GetComplex(viewPort.GetPosition(c));

        Assert.That(roundTripped, Is.EqualTo(c), "Returned wrong complex number.");
    }
Пример #4
0
    public static void Compute(
        string filePath,
        ViewPort viewPort,
        ComputationType computationType,
        CancellationToken token)
    {
        Log.Info($"Outputting to: {filePath}");
        Log.Info($"Resolution: {viewPort.Resolution.Width:N0}x{viewPort.Resolution.Height:N0}");
        Log.Info($"Area: {viewPort.Area}");
        Log.Info($"Computation type: {computationType}");

        IEnumerable <bool> GetPointsInSetScalar()
        {
            var kernel = KernelBuilder.BuildScalarKernel(computationType);

            var rowPointsInSet = new bool[viewPort.Resolution.Width];

            using var progress = TimedOperation.Start("points", totalWork: viewPort.Resolution.Area());
            for (int row = 0; row < viewPort.Resolution.Height; row++)
            {
                Parallel.For(
                    0,
                    viewPort.Resolution.Width,
                    col => rowPointsInSet[col] = kernel.FindEscapeTime(viewPort.GetComplex(col, row), Constant.IterationRange.Max).IsInfinite);

                for (int x = 0; x < viewPort.Resolution.Width; x++)
                {
                    yield return(rowPointsInSet[x]);
                }

                progress.AddWorkDone(viewPort.Resolution.Width);
            }
        }

        IEnumerable <bool> GetPointsInSetVectorDoubles()
        {
            using var progress = TimedOperation.Start("points", totalWork: viewPort.Resolution.Area());
            var vWidth = VectorDoubleKernel.Capacity;

            var vectorBatches = viewPort.Resolution.Width / vWidth;
            var remainder     = viewPort.Resolution.Width % vWidth;

            if (remainder != 0)
            {
                vectorBatches++;
            }
            var lastIndex = vectorBatches - 1;

            var rowPointsInSet = new bool[viewPort.Resolution.Width];

            // TODO: Why is the Parallel.For inside a loop?
            for (int row = 0; row < viewPort.Resolution.Height; row++)
            {
                Parallel.For(
                    0,
                    vectorBatches,
                    batchIndex =>
                {
                    var realBatch = new double[vWidth];
                    var imagBatch = new double[vWidth];
                    var times     = new EscapeTime[vWidth];

                    var batchSize = (batchIndex == lastIndex) ? remainder : vWidth;

                    for (int i = 0; i < batchSize; i++)
                    {
                        var c        = viewPort.GetComplex(batchIndex * vWidth + i, row);
                        realBatch[i] = c.Real;
                        imagBatch[i] = c.Imaginary;
                    }

                    VectorDoubleKernel.FindEscapeTimes(
                        realBatch, imagBatch, Constant.IterationRange.Max, times);

                    for (int i = 0; i < batchSize; i++)
                    {
                        rowPointsInSet[batchIndex * vWidth + i] = times[i].Iterations == Constant.IterationRange.Max;
                    }
                });

                for (int x = 0; x < viewPort.Resolution.Width; x++)
                {
                    yield return(rowPointsInSet[x]);
                }

                progress.AddWorkDone(viewPort.Resolution.Width);
            }
        }

        IEnumerable <bool> ChooseEnumerator() =>
        computationType switch
        {
            ComputationType.ScalarDouble => GetPointsInSetScalar(),
            ComputationType.ScalarFloat => GetPointsInSetScalar(),
            ComputationType.VectorDouble => GetPointsInSetVectorDoubles(),
            _ => throw new ArgumentException("Unsupported computation type: " + computationType)
        };

        Write(filePath, viewPort, computationType, ChooseEnumerator());
    }
}
Пример #5
0
    public static void RenderSingleSpan(string edgeSpansPath, int spanIndex, int sideResolution)
    {
        var resolution = new Size(sideResolution, sideResolution);

        using var spans = EdgeSpanStream.Load(edgeSpansPath);
        using var timer = TimedOperation.Start("points", totalWork: resolution.Area());
        var random = new Random();

        var index = spanIndex >= 0 ? spanIndex : random.Next(0, spans.Count);

        var imageFilePath = Path.Combine(
            Path.GetDirectoryName(edgeSpansPath) ?? throw new Exception($"Could not get directory name: {edgeSpansPath}"),
            Path.GetFileNameWithoutExtension(edgeSpansPath) + $"_{index}_{sideResolution}x{sideResolution}.png");

        Log.Info($"Using edge span index {index:N0}");
        Log.Info($"Output file: {imageFilePath}");

        var span       = spans.ElementAt(index).ToConcreteDouble(spans.ViewPort);
        var spanLength = span.Length();

        Log.Info($"Edge span: {span} (length: {spanLength})");

        var image = new FastImage(resolution);

        var viewPort = new ViewPort(GetArea(span), resolution);

        Log.Info($"View port: {viewPort}");


        var positionInSet    = viewPort.GetPosition(span.InSet);
        var positionNotInSet = viewPort.GetPosition(span.NotInSet);

        var highlightPixelRadius = resolution.Width / 100;

        var borderPoint = span.FindBoundaryPoint(Constant.IterationRange.Max);

        Log.Info($"Border point: {borderPoint} (escape time: {ScalarDoubleKernel.FindEscapeTime(borderPoint)})");
        var borderPointPosition = viewPort.GetPosition(borderPoint);

        // TODO: Why is the inner loop parallelized?
        for (int row = 0; row < resolution.Height; row++)
        {
            Parallel.For(0, resolution.Width,
                         col =>
            {
                var position = new Point(col, row);

                var c = viewPort.GetComplex(position);

                Color PickColor()
                {
                    if (position.DistanceSquaredFrom(positionInSet) <= highlightPixelRadius)
                    {
                        return(Color.Red);
                    }

                    if (position.DistanceSquaredFrom(positionNotInSet) <= highlightPixelRadius)
                    {
                        return(Color.ForestGreen);
                    }

                    if (position.DistanceSquaredFrom(borderPointPosition) <= highlightPixelRadius)
                    {
                        return(Color.Fuchsia);
                    }

                    var isInSet = ScalarDoubleKernel.FindEscapeTime(c, Constant.IterationRange.Max).IsInfinite;
                    return(isInSet ? Color.FromArgb(0x20, 0x20, 0x20) : Color.White);
                }


                image.SetPixel(position, PickColor());
            });

            timer.AddWorkDone(resolution.Width);
        }

        image.Save(imageFilePath);
    }