public void ShouldRoundTrip() { using (var tempFile = new TempFile()) { EdgeSpanStream.Write( tempFile.Path, viewPort: new ViewPort( new ComplexArea(new DoubleRange(-1, 1), new DoubleRange(-1, 1)), new Size(3, 3)), computationType: ComputationType.ScalarDouble, spans: new[] { new LogicalEdgeSpan(new Point(1, 1), toOutside: Direction.Up), }); using (var stream = EdgeSpanStream.Load(tempFile.Path)) { var spans = stream.ToArray(); Assert.That(spans, Has.Length.EqualTo(1), "Incorrect number of spans."); var span = spans.First(); Assert.That(span.Location, Is.EqualTo(new Point(1, 1)), "Wrong location."); Assert.That(span.ToOutside, Is.EqualTo(Direction.Up), "Wrong direction."); } } }
public static void RenderAllSpans(string edgeSpansPath, string imageFilePath, bool showDirections) { Log.Info($"Output image: {imageFilePath}"); if (showDirections) { Log.Info("Displaying span directions as well."); } using var spans = EdgeSpanStream.Load(edgeSpansPath); using var timer = TimedOperation.Start("edge spans", totalWork: showDirections?spans.Count * 2 : spans.Count); var scale = showDirections ? 3 : 1; var resolution = spans.ViewPort.Resolution.Scale(scale); var image = new FastImage(resolution); image.Fill(Color.White); Parallel.ForEach(spans, logicalSpan => { if (showDirections) { var scaledLocation = logicalSpan.Location.Scale(scale); for (int yDelta = 0; yDelta < 3; yDelta++) { for (int xDelta = 0; xDelta < 3; xDelta++) { image.SetPixel( scaledLocation.OffsetBy(xDelta, yDelta), (logicalSpan.Location.X + logicalSpan.Location.Y) % 2 == 1 ? Color.Black : Color.Gray); } } } else { image.SetPixel( logicalSpan.Location, Color.Black); } timer.AddWorkDone(1); }); if (showDirections) { Parallel.ForEach(spans, locatedSpan => { var scaledLocation = locatedSpan.Location.Scale(scale); var pointingTo = scaledLocation.OffsetBy(1, 1).OffsetIn(locatedSpan.ToOutside); image.SetPixel( pointingTo, Color.Red); timer.AddWorkDone(1); }); } image.Save(imageFilePath); }
public static void CalculateToCsv(string edgeSpansPath, int pointsToCalculate) { using var edgeSpans = EdgeSpanStream.Load(edgeSpansPath); using var timedOperation = TimedOperation.Start("edge spans", totalWork: pointsToCalculate > 0 ? pointsToCalculate : edgeSpans.Count); using var outputFile = File.OpenWrite(edgeSpansPath + $".{timedOperation.TotalWork}.borderPoints.csv"); using var textWriter = new StreamWriter(outputFile); using var csv = new CsvWriter(textWriter, CultureInfo.InvariantCulture); //var kernel = KernelBuilder.BuildScalarKernel(edgeSpans.ComputationType); var sequence = edgeSpans.Take((int)timedOperation.TotalWork). Select((logicalSpan, index) => new { LogicalSpan = logicalSpan, Index = index }). AsParallel(). Select(result => { var span = result.LogicalSpan.ToConcreteDouble(edgeSpans.ViewPort); var borderPoint = span.FindBoundaryPoint(Constant.IterationRange.Max); var escapeTime = ScalarDoubleKernel.FindEscapeTime(borderPoint, Constant.IterationRange.Max); timedOperation.AddWorkDone(1); return ( Index: result.Index, Location: result.LogicalSpan.Location, Span: span, Point: borderPoint, EscapeTime: escapeTime ); }); csv.WriteField("Index"); csv.WriteField("Location"); csv.WriteField("Span"); csv.WriteField("Border Point"); csv.WriteField("Escape Time"); csv.NextRecord(); foreach (var result in sequence) { csv.WriteField(result.Index); csv.WriteField(result.Location); csv.WriteField(result.Span); csv.WriteField(result.Point); csv.WriteField(result.EscapeTime); csv.NextRecord(); } }
public static void CalculateWithDoubles(string edgeSpansPath, int pointsToCalculate) { using var edgeSpans = EdgeSpanStream.Load(edgeSpansPath); using var timedOperation = TimedOperation.Start("edge spans", totalWork: pointsToCalculate > 0 ? pointsToCalculate : edgeSpans.Count); var points = edgeSpans.Take((int)timedOperation.TotalWork). AsParallel(). Select(span => span. ToConcreteDouble(edgeSpans.ViewPort). FindBoundaryPoint(Constant.IterationRange.Max)). Where(point => { var escapeTime = ScalarDoubleKernel.FindEscapeTime(point, Constant.IterationRange.Max); timedOperation.AddWorkDone(1); return(Constant.IterationRange.IsInside(escapeTime)); }); PointStream.Write(edgeSpansPath + $".{timedOperation.TotalWork}.doublePoints", edgeSpans.ViewPort, points); }
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); }