Browse Source

drop old code

af/merge-core
Scott Williams 9 years ago
parent
commit
10b94e4fe8
  1. 4
      src/ImageSharp.Drawing/Fill.cs
  2. 4
      src/ImageSharp.Drawing/FillRectangle.cs
  3. 383
      src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs
  4. 452
      src/ImageSharp.Drawing/Processors/FillShapeProcessorFast.cs
  5. 77
      tests/ImageSharp.Benchmarks/Drawing/FillPolygonStatagies.cs

4
src/ImageSharp.Drawing/Fill.cs

@ -56,7 +56,7 @@ namespace ImageSharp
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, IShape shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillShapeProcessorFast<TColor>(brush, shape, options));
return source.Apply(new FillShapeProcessor<TColor>(brush, shape, options));
}
/// <summary>
@ -70,7 +70,7 @@ namespace ImageSharp
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, IShape shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillShapeProcessorFast<TColor>(brush, shape, GraphicsOptions.Default));
return source.Apply(new FillShapeProcessor<TColor>(brush, shape, GraphicsOptions.Default));
}
/// <summary>

4
src/ImageSharp.Drawing/FillRectangle.cs

@ -31,7 +31,7 @@ namespace ImageSharp
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, RectangleF shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillShapeProcessorFast<TColor>(brush, new RectangularPolygon(shape), options));
return source.Apply(new FillShapeProcessor<TColor>(brush, new RectangularPolygon(shape), options));
}
/// <summary>
@ -45,7 +45,7 @@ namespace ImageSharp
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, RectangleF shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillShapeProcessorFast<TColor>(brush, new RectangularPolygon(shape), GraphicsOptions.Default));
return source.Apply(new FillShapeProcessor<TColor>(brush, new RectangularPolygon(shape), GraphicsOptions.Default));
}
/// <summary>

383
src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs

@ -6,6 +6,7 @@
namespace ImageSharp.Drawing.Processors
{
using System;
using System.Buffers;
using System.Numerics;
using System.Threading.Tasks;
using Drawing;
@ -32,7 +33,7 @@ namespace ImageSharp.Drawing.Processors
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <param name="options">The options.</param>
public FillShapeProcessor(IBrush<TColor> brush, IShape shape, GraphicsOptions options)
{
this.poly = shape;
@ -61,16 +62,9 @@ namespace ImageSharp.Drawing.Processors
minY = Math.Max(0, minY);
maxY = Math.Min(source.Height, maxY);
// Reset offset if necessary.
if (minX > 0)
{
startX = 0;
}
ArrayPool<Vector2> arrayPool = ArrayPool<Vector2>.Shared;
if (minY > 0)
{
polyStartY = 0;
}
int maxIntersections = this.poly.MaxIntersections;
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (BrushApplicator<TColor> applicator = this.fillColor.CreateApplicator(sourcePixels, rect))
@ -81,21 +75,122 @@ namespace ImageSharp.Drawing.Processors
this.ParallelOptions,
y =>
{
int offsetY = y - polyStartY;
var buffer = arrayPool.Rent(maxIntersections);
var left = new Vector2(startX, y);
var right = new Vector2(endX, y);
// foreach line we get all the points where this line crosses the polygon
var pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
arrayPool.Return(buffer);
// nothign on this line skip
return;
}
QuickSortX(buffer, 0, pointsFound);
int currentIntersection = 0;
float nextPoint = buffer[0].X;
float lastPoint = float.MinValue;
float targetPoint = nextPoint;
bool isInside = false;
// every odd point is the start of a line
Vector2 currentPoint = default(Vector2);
for (int x = minX; x < maxX; x++)
{
int offsetX = x - startX;
currentPoint.X = offsetX;
currentPoint.Y = offsetY;
float dist = this.poly.Distance(currentPoint);
float opacity = this.Opacity(dist);
currentPoint.X = x;
currentPoint.Y = y;
if (!isInside)
{
if (x < (nextPoint - DrawPadding) && x > (lastPoint + DrawPadding))
{
if (nextPoint == right.X)
{
// we are in the ends run skip it
x = maxX;
continue;
}
// lets just jump forward
x = (int)Math.Floor(nextPoint) - DrawPadding;
}
}
bool onCorner = false;
// there seems to be some issue with this switch.
if (x >= nextPoint)
{
currentIntersection++;
lastPoint = nextPoint;
if (currentIntersection == pointsFound)
{
nextPoint = right.X;
}
else
{
nextPoint = buffer[currentIntersection].X;
// double point from a corner flip the bit back and move on again
if (nextPoint == lastPoint)
{
onCorner = true;
isInside ^= true;
currentIntersection++;
if (currentIntersection == pointsFound)
{
nextPoint = right.X;
}
else
{
nextPoint = buffer[currentIntersection].X;
}
}
}
isInside ^= true;
}
float opacity = 1;
if (!isInside && !onCorner)
{
if (this.options.Antialias)
{
float distance = float.MaxValue;
if (x == lastPoint || x == nextPoint)
{
// we are to far away from the line
distance = 0;
}
else if (nextPoint - AntialiasFactor < x)
{
// we are near the left of the line
distance = nextPoint - x;
}
else if (lastPoint + AntialiasFactor > x)
{
// we are near the right of the line
distance = x - lastPoint;
}
else
{
// we are to far away from the line
continue;
}
opacity = 1 - (distance / AntialiasFactor);
}
else
{
continue;
}
}
if (opacity > Constants.Epsilon)
{
Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4();
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
@ -103,35 +198,255 @@ namespace ImageSharp.Drawing.Processors
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
sourcePixels[offsetX, offsetY] = packed;
sourcePixels[x, y] = packed;
}
}
arrayPool.Return(buffer);
});
if (this.options.Antialias)
{
// we only need to do the X can for antialiasing purposes
Parallel.For(
minX,
maxX,
this.ParallelOptions,
x =>
{
var buffer = arrayPool.Rent(maxIntersections);
var left = new Vector2(x, polyStartY);
var right = new Vector2(x, polyEndY);
// foreach line we get all the points where this line crosses the polygon
var pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
arrayPool.Return(buffer);
// nothign on this line skip
return;
}
QuickSortY(buffer, 0, pointsFound);
int currentIntersection = 0;
float nextPoint = buffer[0].Y;
float lastPoint = left.Y;
float targetPoint = nextPoint;
bool isInside = false;
// every odd point is the start of a line
Vector2 currentPoint = default(Vector2);
for (int y = minY; y < maxY; y++)
{
currentPoint.X = x;
currentPoint.Y = y;
if (!isInside)
{
if (y < (nextPoint - DrawPadding) && y > (lastPoint + DrawPadding))
{
if (nextPoint == right.Y)
{
// we are in the ends run skip it
y = maxY;
continue;
}
// lets just jump forward
y = (int)Math.Floor(nextPoint) - DrawPadding;
}
}
else
{
if (y < nextPoint - DrawPadding)
{
if (nextPoint == right.Y)
{
// we are in the ends run skip it
y = maxY;
continue;
}
// lets just jump forward
y = (int)Math.Floor(nextPoint);
}
}
bool onCorner = false;
if (y >= nextPoint)
{
currentIntersection++;
lastPoint = nextPoint;
if (currentIntersection == pointsFound)
{
nextPoint = right.Y;
}
else
{
nextPoint = buffer[currentIntersection].Y;
// double point from a corner flip the bit back and move on again
if (nextPoint == lastPoint)
{
onCorner = true;
isInside ^= true;
currentIntersection++;
if (currentIntersection == pointsFound)
{
nextPoint = right.Y;
}
else
{
nextPoint = buffer[currentIntersection].Y;
}
}
}
isInside ^= true;
}
float opacity = 1;
if (!isInside && !onCorner)
{
if (this.options.Antialias)
{
float distance = float.MaxValue;
if (y == lastPoint || y == nextPoint)
{
// we are to far away from the line
distance = 0;
}
else if (nextPoint - AntialiasFactor < y)
{
// we are near the left of the line
distance = nextPoint - y;
}
else if (lastPoint + AntialiasFactor > y)
{
// we are near the right of the line
distance = y - lastPoint;
}
else
{
// we are to far away from the line
continue;
}
opacity = 1 - (distance / AntialiasFactor);
}
else
{
continue;
}
}
// don't set full opactiy color as it will have been gotten by the first scan
if (opacity > Constants.Epsilon && opacity < 1)
{
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
finalColor.W = backgroundVector.W;
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
sourcePixels[x, y] = packed;
}
}
arrayPool.Return(buffer);
});
}
}
}
/// <summary>
/// Returns the correct alpha value for the given distance.
/// </summary>
/// <param name="distance">
/// The distance.
/// </param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
private float Opacity(float distance)
private static void QuickSortX(Vector2[] data, int left, int right)
{
if (distance <= 0)
int i = left - 1;
int j = right;
while (true)
{
return 1;
float x = data[left].X;
do
{
i++;
}
while (data[i].X < x);
do
{
j--;
}
while (data[j].X > x);
if (i < j)
{
Vector2 tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
else
{
if (left < j)
{
QuickSortX(data, left, j);
}
if (++j < right)
{
QuickSortX(data, j, right);
}
return;
}
}
}
private static void QuickSortY(Vector2[] data, int left, int right)
{
int i = left - 1;
int j = right;
if (this.options.Antialias && distance < AntialiasFactor)
while (true)
{
return 1 - (distance / AntialiasFactor);
}
float d = data[left].Y;
do
{
i++;
}
while (data[i].Y < d);
do
{
j--;
}
while (data[j].Y > d);
return 0;
if (i < j)
{
Vector2 tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
else
{
if (left < j)
{
QuickSortY(data, left, j);
}
if (++j < right)
{
QuickSortY(data, j, right);
}
return;
}
}
}
}
}

452
src/ImageSharp.Drawing/Processors/FillShapeProcessorFast.cs

@ -1,452 +0,0 @@
// <copyright file="FillShapeProcessorFast.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Processors
{
using System;
using System.Buffers;
using System.Numerics;
using System.Threading.Tasks;
using Drawing;
using ImageSharp.Processing;
using Shapes;
using Rectangle = ImageSharp.Rectangle;
/// <summary>
/// Usinf a brsuh and a shape fills shape with contents of brush the
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <seealso cref="ImageSharp.Processing.ImageProcessor{TColor}" />
public class FillShapeProcessorFast<TColor> : ImageProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
private const float AntialiasFactor = 1f;
private const int DrawPadding = 1;
private readonly IBrush<TColor> fillColor;
private readonly IShape poly;
private readonly GraphicsOptions options;
/// <summary>
/// Initializes a new instance of the <see cref="FillShapeProcessorFast{TColor}"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
public FillShapeProcessorFast(IBrush<TColor> brush, IShape shape, GraphicsOptions options)
{
this.poly = shape;
this.fillColor = brush;
this.options = options;
}
/// <inheritdoc/>
protected override void OnApply(ImageBase<TColor> source, Rectangle sourceRectangle)
{
Rectangle rect = RectangleF.Ceiling(this.poly.Bounds); // rounds the points out away from the center
int polyStartY = rect.Y - DrawPadding;
int polyEndY = rect.Bottom + DrawPadding;
int startX = rect.X - DrawPadding;
int endX = rect.Right + DrawPadding;
int minX = Math.Max(sourceRectangle.Left, startX);
int maxX = Math.Min(sourceRectangle.Right - 1, endX);
int minY = Math.Max(sourceRectangle.Top, polyStartY);
int maxY = Math.Min(sourceRectangle.Bottom - 1, polyEndY);
// Align start/end positions.
minX = Math.Max(0, minX);
maxX = Math.Min(source.Width, maxX);
minY = Math.Max(0, minY);
maxY = Math.Min(source.Height, maxY);
ArrayPool<Vector2> arrayPool = ArrayPool<Vector2>.Shared;
int maxIntersections = this.poly.MaxIntersections;
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (BrushApplicator<TColor> applicator = this.fillColor.CreateApplicator(sourcePixels, rect))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
var buffer = arrayPool.Rent(maxIntersections);
var left = new Vector2(startX, y);
var right = new Vector2(endX, y);
// foreach line we get all the points where this line crosses the polygon
var pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
arrayPool.Return(buffer);
// nothign on this line skip
return;
}
QuickSortX(buffer, 0, pointsFound);
int currentIntersection = 0;
float nextPoint = buffer[0].X;
float lastPoint = float.MinValue;
float targetPoint = nextPoint;
bool isInside = false;
// every odd point is the start of a line
Vector2 currentPoint = default(Vector2);
for (int x = minX; x < maxX; x++)
{
currentPoint.X = x;
currentPoint.Y = y;
if (!isInside)
{
if (x < (nextPoint - DrawPadding) && x > (lastPoint + DrawPadding))
{
if (nextPoint == right.X)
{
// we are in the ends run skip it
x = maxX;
continue;
}
// lets just jump forward
x = (int)Math.Floor(nextPoint) - DrawPadding;
}
}
bool onCorner = false;
// there seems to be some issue with this switch.
if (x >= nextPoint)
{
currentIntersection++;
lastPoint = nextPoint;
if (currentIntersection == pointsFound)
{
nextPoint = right.X;
}
else
{
nextPoint = buffer[currentIntersection].X;
// double point from a corner flip the bit back and move on again
if (nextPoint == lastPoint)
{
onCorner = true;
isInside ^= true;
currentIntersection++;
if (currentIntersection == pointsFound)
{
nextPoint = right.X;
}
else
{
nextPoint = buffer[currentIntersection].X;
}
}
}
isInside ^= true;
}
float opacity = 1;
if (!isInside && !onCorner)
{
if (this.options.Antialias)
{
float distance = float.MaxValue;
if (x == lastPoint || x == nextPoint)
{
// we are to far away from the line
distance = 0;
}
else if (nextPoint - AntialiasFactor < x)
{
// we are near the left of the line
distance = nextPoint - x;
}
else if (lastPoint + AntialiasFactor > x)
{
// we are near the right of the line
distance = x - lastPoint;
}
else
{
// we are to far away from the line
continue;
}
opacity = 1 - (distance / AntialiasFactor);
}
else
{
continue;
}
}
if (opacity > Constants.Epsilon)
{
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
finalColor.W = backgroundVector.W;
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
sourcePixels[x, y] = packed;
}
}
arrayPool.Return(buffer);
});
if (this.options.Antialias)
{
// we only need to do the X can for antialiasing purposes
Parallel.For(
minX,
maxX,
this.ParallelOptions,
x =>
{
var buffer = arrayPool.Rent(maxIntersections);
var left = new Vector2(x, polyStartY);
var right = new Vector2(x, polyEndY);
// foreach line we get all the points where this line crosses the polygon
var pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
arrayPool.Return(buffer);
// nothign on this line skip
return;
}
QuickSortY(buffer, 0, pointsFound);
int currentIntersection = 0;
float nextPoint = buffer[0].Y;
float lastPoint = left.Y;
float targetPoint = nextPoint;
bool isInside = false;
// every odd point is the start of a line
Vector2 currentPoint = default(Vector2);
for (int y = minY; y < maxY; y++)
{
currentPoint.X = x;
currentPoint.Y = y;
if (!isInside)
{
if (y < (nextPoint - DrawPadding) && y > (lastPoint + DrawPadding))
{
if (nextPoint == right.Y)
{
// we are in the ends run skip it
y = maxY;
continue;
}
// lets just jump forward
y = (int)Math.Floor(nextPoint) - DrawPadding;
}
}
else
{
if (y < nextPoint - DrawPadding)
{
if (nextPoint == right.Y)
{
// we are in the ends run skip it
y = maxY;
continue;
}
// lets just jump forward
y = (int)Math.Floor(nextPoint);
}
}
bool onCorner = false;
if (y >= nextPoint)
{
currentIntersection++;
lastPoint = nextPoint;
if (currentIntersection == pointsFound)
{
nextPoint = right.Y;
}
else
{
nextPoint = buffer[currentIntersection].Y;
// double point from a corner flip the bit back and move on again
if (nextPoint == lastPoint)
{
onCorner = true;
isInside ^= true;
currentIntersection++;
if (currentIntersection == pointsFound)
{
nextPoint = right.Y;
}
else
{
nextPoint = buffer[currentIntersection].Y;
}
}
}
isInside ^= true;
}
float opacity = 1;
if (!isInside && !onCorner)
{
if (this.options.Antialias)
{
float distance = float.MaxValue;
if (y == lastPoint || y == nextPoint)
{
// we are to far away from the line
distance = 0;
}
else if (nextPoint - AntialiasFactor < y)
{
// we are near the left of the line
distance = nextPoint - y;
}
else if (lastPoint + AntialiasFactor > y)
{
// we are near the right of the line
distance = y - lastPoint;
}
else
{
// we are to far away from the line
continue;
}
opacity = 1 - (distance / AntialiasFactor);
}
else
{
continue;
}
}
// don't set full opactiy color as it will have been gotten by the first scan
if (opacity > Constants.Epsilon && opacity < 1)
{
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
finalColor.W = backgroundVector.W;
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
sourcePixels[x, y] = packed;
}
}
arrayPool.Return(buffer);
});
}
}
}
private static void QuickSortX(Vector2[] data, int left, int right)
{
int i = left - 1;
int j = right;
while (true)
{
float x = data[left].X;
do
{
i++;
}
while (data[i].X < x);
do
{
j--;
}
while (data[j].X > x);
if (i < j)
{
Vector2 tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
else
{
if (left < j)
{
QuickSortX(data, left, j);
}
if (++j < right)
{
QuickSortX(data, j, right);
}
return;
}
}
}
private static void QuickSortY(Vector2[] data, int left, int right)
{
int i = left - 1;
int j = right;
while (true)
{
float d = data[left].Y;
do
{
i++;
}
while (data[i].Y < d);
do
{
j--;
}
while (data[j].Y > d);
if (i < j)
{
Vector2 tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
else
{
if (left < j)
{
QuickSortY(data, left, j);
}
if (++j < right)
{
QuickSortY(data, j, right);
}
return;
}
}
}
}
}

77
tests/ImageSharp.Benchmarks/Drawing/FillPolygonStatagies.cs

@ -1,77 +0,0 @@
// <copyright file="FillPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Benchmarks
{
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Numerics;
using BenchmarkDotNet.Attributes;
using CoreColor = ImageSharp.Color;
using CoreImage = ImageSharp.Image;
using Drawing.Processors;
public class FillPolygonStatagies : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "Simple Fill Polygon - antialias")]
public void DrawSolidPolygonSimple()
{
CoreImage image = new CoreImage(800, 800);
var brush = Drawing.Brushes.Brushes.Solid(CoreColor.HotPink);
var shape = new Drawing.Shapes.LinearPolygon(new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
image.Apply(new FillShapeProcessor<ImageSharp.Color>(brush, shape, Drawing.GraphicsOptions.Default));
}
[Benchmark(Description = "Fast Fill Polygon - antialias")]
public void DrawSolidPolygonFast()
{
CoreImage image = new CoreImage(800, 800);
var brush = Drawing.Brushes.Brushes.Solid(CoreColor.HotPink);
var shape = new Drawing.Shapes.LinearPolygon(new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
image.Apply(new FillShapeProcessorFast<ImageSharp.Color>(brush, shape, Drawing.GraphicsOptions.Default));
}
[Benchmark(Description = "Simple Fill Polygon - antialias disabled")]
public void DrawSolidPolygonSimpleDisableAntiAliase()
{
CoreImage image = new CoreImage(800, 800);
var brush = Drawing.Brushes.Brushes.Solid(CoreColor.HotPink);
var shape = new Drawing.Shapes.LinearPolygon(new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
image.Apply(new FillShapeProcessor<ImageSharp.Color>(brush, shape, new Drawing.GraphicsOptions(false)));
}
[Benchmark(Description = "Fast Fill Polygon - antialias disabledp")]
public void DrawSolidPolygonFasteDisableAntiAliase()
{
CoreImage image = new CoreImage(800, 800);
var brush = Drawing.Brushes.Brushes.Solid(CoreColor.HotPink);
var shape = new Drawing.Shapes.LinearPolygon(new[] {
new Vector2(10, 10),
new Vector2(550, 50),
new Vector2(200, 400)
});
image.Apply(new FillShapeProcessorFast<ImageSharp.Color>(brush, shape, new Drawing.GraphicsOptions(false)));
}
}
}
Loading…
Cancel
Save